/src/away3d/materials/methods/BasicSpecularMethod.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 326 lines · 214 code · 53 blank · 59 comment · 36 complexity · 82ec62879e3d211f97d6e5b348ed4a2c MD5 · raw file

  1. package away3d.materials.methods
  2. {
  3. import away3d.*;
  4. import away3d.core.managers.*;
  5. import away3d.materials.compilation.*;
  6. import away3d.textures.*;
  7. use namespace arcane;
  8. /**
  9. * BasicSpecularMethod provides the default shading method for Blinn-Phong specular highlights (an optimized but approximated
  10. * version of Phong specularity).
  11. */
  12. public class BasicSpecularMethod extends LightingMethodBase
  13. {
  14. protected var _useTexture:Boolean;
  15. protected var _totalLightColorReg:ShaderRegisterElement;
  16. protected var _specularTextureRegister:ShaderRegisterElement;
  17. protected var _specularTexData:ShaderRegisterElement;
  18. protected var _specularDataRegister:ShaderRegisterElement;
  19. private var _texture:Texture2DBase;
  20. private var _gloss:int = 50;
  21. private var _specular:Number = 1;
  22. private var _specularColor:uint = 0xffffff;
  23. arcane var _specularR:Number = 1, _specularG:Number = 1, _specularB:Number = 1;
  24. private var _shadowRegister:ShaderRegisterElement;
  25. protected var _isFirstLight:Boolean;
  26. /**
  27. * Creates a new BasicSpecularMethod object.
  28. */
  29. public function BasicSpecularMethod()
  30. {
  31. super();
  32. }
  33. /**
  34. * @inheritDoc
  35. */
  36. override arcane function initVO(vo:MethodVO):void
  37. {
  38. vo.needsUV = _useTexture;
  39. vo.needsNormals = vo.numLights > 0;
  40. vo.needsView = vo.numLights > 0;
  41. }
  42. /**
  43. * The sharpness of the specular highlight.
  44. */
  45. public function get gloss():Number
  46. {
  47. return _gloss;
  48. }
  49. public function set gloss(value:Number):void
  50. {
  51. _gloss = value;
  52. }
  53. /**
  54. * The overall strength of the specular highlights.
  55. */
  56. public function get specular():Number
  57. {
  58. return _specular;
  59. }
  60. public function set specular(value:Number):void
  61. {
  62. if (value == _specular)
  63. return;
  64. _specular = value;
  65. updateSpecular();
  66. }
  67. /**
  68. * The colour of the specular reflection of the surface.
  69. */
  70. public function get specularColor():uint
  71. {
  72. return _specularColor;
  73. }
  74. public function set specularColor(value:uint):void
  75. {
  76. if (_specularColor == value)
  77. return;
  78. // specular is now either enabled or disabled
  79. if (_specularColor == 0 || value == 0)
  80. invalidateShaderProgram();
  81. _specularColor = value;
  82. updateSpecular();
  83. }
  84. /**
  85. * The bitmapData that encodes the specular highlight strength per texel in the red channel, and the sharpness
  86. * in the green channel. You can use SpecularBitmapTexture if you want to easily set specular and gloss maps
  87. * from grayscale images, but prepared images are preferred.
  88. */
  89. public function get texture():Texture2DBase
  90. {
  91. return _texture;
  92. }
  93. public function set texture(value:Texture2DBase):void
  94. {
  95. if (Boolean(value) != _useTexture ||
  96. (value && _texture && (value.hasMipMaps != _texture.hasMipMaps || value.format != _texture.format))) {
  97. invalidateShaderProgram();
  98. }
  99. _useTexture = Boolean(value);
  100. _texture = value;
  101. }
  102. /**
  103. * @inheritDoc
  104. */
  105. override public function copyFrom(method:ShadingMethodBase):void
  106. {
  107. var spec:BasicSpecularMethod = BasicSpecularMethod(method);
  108. texture = spec.texture;
  109. specular = spec.specular;
  110. specularColor = spec.specularColor;
  111. gloss = spec.gloss;
  112. }
  113. /**
  114. * @inheritDoc
  115. */
  116. arcane override function cleanCompilationData():void
  117. {
  118. super.cleanCompilationData();
  119. _shadowRegister = null;
  120. _totalLightColorReg = null;
  121. _specularTextureRegister = null;
  122. _specularTexData = null;
  123. _specularDataRegister = null;
  124. }
  125. /**
  126. * @inheritDoc
  127. */
  128. override arcane function getFragmentPreLightingCode(vo:MethodVO, regCache:ShaderRegisterCache):String
  129. {
  130. var code:String = "";
  131. _isFirstLight = true;
  132. if (vo.numLights > 0) {
  133. _specularDataRegister = regCache.getFreeFragmentConstant();
  134. vo.fragmentConstantsIndex = _specularDataRegister.index*4;
  135. if (_useTexture) {
  136. _specularTexData = regCache.getFreeFragmentVectorTemp();
  137. regCache.addFragmentTempUsages(_specularTexData, 1);
  138. _specularTextureRegister = regCache.getFreeTextureReg();
  139. vo.texturesIndex = _specularTextureRegister.index;
  140. code = getTex2DSampleCode(vo, _specularTexData, _specularTextureRegister, _texture);
  141. } else
  142. _specularTextureRegister = null;
  143. _totalLightColorReg = regCache.getFreeFragmentVectorTemp();
  144. regCache.addFragmentTempUsages(_totalLightColorReg, 1);
  145. }
  146. return code;
  147. }
  148. /**
  149. * @inheritDoc
  150. */
  151. override arcane function getFragmentCodePerLight(vo:MethodVO, lightDirReg:ShaderRegisterElement, lightColReg:ShaderRegisterElement, regCache:ShaderRegisterCache):String
  152. {
  153. var code:String = "";
  154. var t:ShaderRegisterElement;
  155. if (_isFirstLight)
  156. t = _totalLightColorReg;
  157. else {
  158. t = regCache.getFreeFragmentVectorTemp();
  159. regCache.addFragmentTempUsages(t, 1);
  160. }
  161. var viewDirReg:ShaderRegisterElement = _sharedRegisters.viewDirFragment;
  162. var normalReg:ShaderRegisterElement = _sharedRegisters.normalFragment;
  163. // blinn-phong half vector model
  164. code += "add " + t + ", " + lightDirReg + ", " + viewDirReg + "\n" +
  165. "nrm " + t + ".xyz, " + t + "\n" +
  166. "dp3 " + t + ".w, " + normalReg + ", " + t + "\n" +
  167. "sat " + t + ".w, " + t + ".w\n";
  168. if (_useTexture) {
  169. // apply gloss modulation from texture
  170. code += "mul " + _specularTexData + ".w, " + _specularTexData + ".y, " + _specularDataRegister + ".w\n" +
  171. "pow " + t + ".w, " + t + ".w, " + _specularTexData + ".w\n";
  172. } else
  173. code += "pow " + t + ".w, " + t + ".w, " + _specularDataRegister + ".w\n";
  174. // attenuate
  175. if (vo.useLightFallOff)
  176. code += "mul " + t + ".w, " + t + ".w, " + lightDirReg + ".w\n";
  177. if (_modulateMethod != null)
  178. code += _modulateMethod(vo, t, regCache, _sharedRegisters);
  179. code += "mul " + t + ".xyz, " + lightColReg + ", " + t + ".w\n";
  180. if (!_isFirstLight) {
  181. code += "add " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + t + "\n";
  182. regCache.removeFragmentTempUsage(t);
  183. }
  184. _isFirstLight = false;
  185. return code;
  186. }
  187. /**
  188. * @inheritDoc
  189. */
  190. arcane override function getFragmentCodePerProbe(vo:MethodVO, cubeMapReg:ShaderRegisterElement, weightRegister:String, regCache:ShaderRegisterCache):String
  191. {
  192. var code:String = "";
  193. var t:ShaderRegisterElement;
  194. // write in temporary if not first light, so we can add to total diffuse colour
  195. if (_isFirstLight)
  196. t = _totalLightColorReg;
  197. else {
  198. t = regCache.getFreeFragmentVectorTemp();
  199. regCache.addFragmentTempUsages(t, 1);
  200. }
  201. var normalReg:ShaderRegisterElement = _sharedRegisters.normalFragment;
  202. var viewDirReg:ShaderRegisterElement = _sharedRegisters.viewDirFragment;
  203. code += "dp3 " + t + ".w, " + normalReg + ", " + viewDirReg + "\n" +
  204. "add " + t + ".w, " + t + ".w, " + t + ".w\n" +
  205. "mul " + t + ", " + t + ".w, " + normalReg + "\n" +
  206. "sub " + t + ", " + t + ", " + viewDirReg + "\n" +
  207. "tex " + t + ", " + t + ", " + cubeMapReg + " <cube," + (vo.useSmoothTextures? "linear" : "nearest") + ",miplinear>\n" +
  208. "mul " + t + ".xyz, " + t + ", " + weightRegister + "\n";
  209. if (_modulateMethod != null)
  210. code += _modulateMethod(vo, t, regCache, _sharedRegisters);
  211. if (!_isFirstLight) {
  212. code += "add " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + t + "\n";
  213. regCache.removeFragmentTempUsage(t);
  214. }
  215. _isFirstLight = false;
  216. return code;
  217. }
  218. /**
  219. * @inheritDoc
  220. */
  221. override arcane function getFragmentPostLightingCode(vo:MethodVO, regCache:ShaderRegisterCache, targetReg:ShaderRegisterElement):String
  222. {
  223. var code:String = "";
  224. if (vo.numLights == 0)
  225. return code;
  226. if (_shadowRegister)
  227. code += "mul " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + _shadowRegister + ".w\n";
  228. if (_useTexture) {
  229. // apply strength modulation from texture
  230. code += "mul " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + _specularTexData + ".x\n";
  231. regCache.removeFragmentTempUsage(_specularTexData);
  232. }
  233. // apply material's specular reflection
  234. code += "mul " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + _specularDataRegister + "\n" +
  235. "add " + targetReg + ".xyz, " + targetReg + ", " + _totalLightColorReg + "\n";
  236. regCache.removeFragmentTempUsage(_totalLightColorReg);
  237. return code;
  238. }
  239. /**
  240. * @inheritDoc
  241. */
  242. arcane override function activate(vo:MethodVO, stage3DProxy:Stage3DProxy):void
  243. {
  244. //var context : Context3D = stage3DProxy._context3D;
  245. if (vo.numLights == 0)
  246. return;
  247. if (_useTexture)
  248. stage3DProxy._context3D.setTextureAt(vo.texturesIndex, _texture.getTextureForStage3D(stage3DProxy));
  249. var index:int = vo.fragmentConstantsIndex;
  250. var data:Vector.<Number> = vo.fragmentData;
  251. data[index] = _specularR;
  252. data[index + 1] = _specularG;
  253. data[index + 2] = _specularB;
  254. data[index + 3] = _gloss;
  255. }
  256. /**
  257. * Updates the specular color data used by the render state.
  258. */
  259. private function updateSpecular():void
  260. {
  261. _specularR = ((_specularColor >> 16) & 0xff)/0xff*_specular;
  262. _specularG = ((_specularColor >> 8) & 0xff)/0xff*_specular;
  263. _specularB = (_specularColor & 0xff)/0xff*_specular;
  264. }
  265. /**
  266. * Set internally by the compiler, so the method knows the register containing the shadow calculation.
  267. */
  268. arcane function set shadowRegister(shadowReg:ShaderRegisterElement):void
  269. {
  270. _shadowRegister = shadowReg;
  271. }
  272. }
  273. }