/src/away3d/materials/methods/BasicDiffuseMethod.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 372 lines · 247 code · 59 blank · 66 comment · 45 complexity · bbe13c0ca201d0703153f2c6746e1df8 MD5 · raw file

  1. package away3d.materials.methods
  2. {
  3. import away3d.arcane;
  4. import away3d.core.managers.Stage3DProxy;
  5. import away3d.materials.compilation.ShaderRegisterCache;
  6. import away3d.materials.compilation.ShaderRegisterElement;
  7. import away3d.textures.Texture2DBase;
  8. use namespace arcane;
  9. /**
  10. * BasicDiffuseMethod provides the default shading method for Lambert (dot3) diffuse lighting.
  11. */
  12. public class BasicDiffuseMethod extends LightingMethodBase
  13. {
  14. private var _useAmbientTexture:Boolean;
  15. protected var _useTexture:Boolean;
  16. internal var _totalLightColorReg:ShaderRegisterElement;
  17. // TODO: are these registers at all necessary to be members?
  18. protected var _diffuseInputRegister:ShaderRegisterElement;
  19. private var _texture:Texture2DBase;
  20. private var _diffuseColor:uint = 0xffffff;
  21. private var _diffuseR:Number = 1, _diffuseG:Number = 1, _diffuseB:Number = 1, _diffuseA:Number = 1;
  22. protected var _shadowRegister:ShaderRegisterElement;
  23. protected var _alphaThreshold:Number = 0;
  24. protected var _isFirstLight:Boolean;
  25. /**
  26. * Creates a new BasicDiffuseMethod object.
  27. */
  28. public function BasicDiffuseMethod()
  29. {
  30. super();
  31. }
  32. /**
  33. * Set internally if the ambient method uses a texture.
  34. */
  35. arcane function get useAmbientTexture():Boolean
  36. {
  37. return _useAmbientTexture;
  38. }
  39. arcane function set useAmbientTexture(value:Boolean):void
  40. {
  41. if (_useAmbientTexture == value)
  42. return;
  43. _useAmbientTexture = value;
  44. invalidateShaderProgram();
  45. }
  46. override arcane function initVO(vo:MethodVO):void
  47. {
  48. vo.needsUV = _useTexture;
  49. vo.needsNormals = vo.numLights > 0;
  50. }
  51. /**
  52. * Forces the creation of the texture.
  53. * @param stage3DProxy The Stage3DProxy used by the renderer
  54. */
  55. public function generateMip(stage3DProxy:Stage3DProxy):void
  56. {
  57. if (_useTexture)
  58. _texture.getTextureForStage3D(stage3DProxy);
  59. }
  60. /**
  61. * The alpha component of the diffuse reflection.
  62. */
  63. public function get diffuseAlpha():Number
  64. {
  65. return _diffuseA;
  66. }
  67. public function set diffuseAlpha(value:Number):void
  68. {
  69. _diffuseA = value;
  70. }
  71. /**
  72. * The color of the diffuse reflection when not using a texture.
  73. */
  74. public function get diffuseColor():uint
  75. {
  76. return _diffuseColor;
  77. }
  78. public function set diffuseColor(diffuseColor:uint):void
  79. {
  80. _diffuseColor = diffuseColor;
  81. updateDiffuse();
  82. }
  83. /**
  84. * The bitmapData to use to define the diffuse reflection color per texel.
  85. */
  86. public function get texture():Texture2DBase
  87. {
  88. return _texture;
  89. }
  90. public function set texture(value:Texture2DBase):void
  91. {
  92. if (Boolean(value) != _useTexture ||
  93. (value && _texture && (value.hasMipMaps != _texture.hasMipMaps || value.format != _texture.format))) {
  94. invalidateShaderProgram();
  95. }
  96. _useTexture = Boolean(value);
  97. _texture = value;
  98. }
  99. /**
  100. * The minimum alpha value for which pixels should be drawn. This is used for transparency that is either
  101. * invisible or entirely opaque, often used with textures for foliage, etc.
  102. * Recommended values are 0 to disable alpha, or 0.5 to create smooth edges. Default value is 0 (disabled).
  103. */
  104. public function get alphaThreshold():Number
  105. {
  106. return _alphaThreshold;
  107. }
  108. public function set alphaThreshold(value:Number):void
  109. {
  110. if (value < 0)
  111. value = 0;
  112. else if (value > 1)
  113. value = 1;
  114. if (value == _alphaThreshold)
  115. return;
  116. if (value == 0 || _alphaThreshold == 0)
  117. invalidateShaderProgram();
  118. _alphaThreshold = value;
  119. }
  120. /**
  121. * @inheritDoc
  122. */
  123. override public function dispose():void
  124. {
  125. _texture = null;
  126. }
  127. /**
  128. * @inheritDoc
  129. */
  130. override public function copyFrom(method:ShadingMethodBase):void
  131. {
  132. var diff:BasicDiffuseMethod = BasicDiffuseMethod(method);
  133. alphaThreshold = diff.alphaThreshold;
  134. texture = diff.texture;
  135. useAmbientTexture = diff.useAmbientTexture;
  136. diffuseAlpha = diff.diffuseAlpha;
  137. diffuseColor = diff.diffuseColor;
  138. }
  139. /**
  140. * @inheritDoc
  141. */
  142. arcane override function cleanCompilationData():void
  143. {
  144. super.cleanCompilationData();
  145. _shadowRegister = null;
  146. _totalLightColorReg = null;
  147. _diffuseInputRegister = null;
  148. }
  149. /**
  150. * @inheritDoc
  151. */
  152. override arcane function getFragmentPreLightingCode(vo:MethodVO, regCache:ShaderRegisterCache):String
  153. {
  154. var code:String = "";
  155. _isFirstLight = true;
  156. if (vo.numLights > 0) {
  157. _totalLightColorReg = regCache.getFreeFragmentVectorTemp();
  158. regCache.addFragmentTempUsages(_totalLightColorReg, 1);
  159. }
  160. return code;
  161. }
  162. /**
  163. * @inheritDoc
  164. */
  165. override arcane function getFragmentCodePerLight(vo:MethodVO, lightDirReg:ShaderRegisterElement, lightColReg:ShaderRegisterElement, regCache:ShaderRegisterCache):String
  166. {
  167. var code:String = "";
  168. var t:ShaderRegisterElement;
  169. // write in temporary if not first light, so we can add to total diffuse colour
  170. if (_isFirstLight)
  171. t = _totalLightColorReg;
  172. else {
  173. t = regCache.getFreeFragmentVectorTemp();
  174. regCache.addFragmentTempUsages(t, 1);
  175. }
  176. code += "dp3 " + t + ".x, " + lightDirReg + ", " + _sharedRegisters.normalFragment + "\n" +
  177. "max " + t + ".w, " + t + ".x, " + _sharedRegisters.commons + ".y\n";
  178. if (vo.useLightFallOff)
  179. code += "mul " + t + ".w, " + t + ".w, " + lightDirReg + ".w\n";
  180. if (_modulateMethod != null)
  181. code += _modulateMethod(vo, t, regCache, _sharedRegisters);
  182. code += "mul " + t + ", " + t + ".w, " + lightColReg + "\n";
  183. if (!_isFirstLight) {
  184. code += "add " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + t + "\n";
  185. regCache.removeFragmentTempUsage(t);
  186. }
  187. _isFirstLight = false;
  188. return code;
  189. }
  190. /**
  191. * @inheritDoc
  192. */
  193. arcane override function getFragmentCodePerProbe(vo:MethodVO, cubeMapReg:ShaderRegisterElement, weightRegister:String, regCache:ShaderRegisterCache):String
  194. {
  195. var code:String = "";
  196. var t:ShaderRegisterElement;
  197. // write in temporary if not first light, so we can add to total diffuse colour
  198. if (_isFirstLight)
  199. t = _totalLightColorReg;
  200. else {
  201. t = regCache.getFreeFragmentVectorTemp();
  202. regCache.addFragmentTempUsages(t, 1);
  203. }
  204. code += "tex " + t + ", " + _sharedRegisters.normalFragment + ", " + cubeMapReg + " <cube,linear,miplinear>\n" +
  205. "mul " + t + ".xyz, " + t + ".xyz, " + weightRegister + "\n";
  206. if (_modulateMethod != null)
  207. code += _modulateMethod(vo, t, regCache, _sharedRegisters);
  208. if (!_isFirstLight) {
  209. code += "add " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + t + "\n";
  210. regCache.removeFragmentTempUsage(t);
  211. }
  212. _isFirstLight = false;
  213. return code;
  214. }
  215. /**
  216. * @inheritDoc
  217. */
  218. override arcane function getFragmentPostLightingCode(vo:MethodVO, regCache:ShaderRegisterCache, targetReg:ShaderRegisterElement):String
  219. {
  220. var code:String = "";
  221. var albedo:ShaderRegisterElement;
  222. var cutOffReg:ShaderRegisterElement;
  223. // incorporate input from ambient
  224. if (vo.numLights > 0) {
  225. if (_shadowRegister)
  226. code += applyShadow(vo, regCache);
  227. albedo = regCache.getFreeFragmentVectorTemp();
  228. regCache.addFragmentTempUsages(albedo, 1);
  229. } else
  230. albedo = targetReg;
  231. if (_useTexture) {
  232. _diffuseInputRegister = regCache.getFreeTextureReg();
  233. vo.texturesIndex = _diffuseInputRegister.index;
  234. code += getTex2DSampleCode(vo, albedo, _diffuseInputRegister, _texture);
  235. if (_alphaThreshold > 0) {
  236. cutOffReg = regCache.getFreeFragmentConstant();
  237. vo.fragmentConstantsIndex = cutOffReg.index*4;
  238. code += "sub " + albedo + ".w, " + albedo + ".w, " + cutOffReg + ".x\n" +
  239. "kil " + albedo + ".w\n" +
  240. "add " + albedo + ".w, " + albedo + ".w, " + cutOffReg + ".x\n";
  241. }
  242. } else {
  243. _diffuseInputRegister = regCache.getFreeFragmentConstant();
  244. vo.fragmentConstantsIndex = _diffuseInputRegister.index*4;
  245. code += "mov " + albedo + ", " + _diffuseInputRegister + "\n";
  246. }
  247. if (vo.numLights == 0)
  248. return code;
  249. code += "sat " + _totalLightColorReg + ", " + _totalLightColorReg + "\n";
  250. if (_useAmbientTexture) {
  251. code += "mul " + albedo + ".xyz, " + albedo + ", " + _totalLightColorReg + "\n" +
  252. "mul " + _totalLightColorReg + ".xyz, " + targetReg + ", " + _totalLightColorReg + "\n" +
  253. "sub " + targetReg + ".xyz, " + targetReg + ", " + _totalLightColorReg + "\n" +
  254. "add " + targetReg + ".xyz, " + albedo + ", " + targetReg + "\n";
  255. } else {
  256. code += "add " + targetReg + ".xyz, " + _totalLightColorReg + ", " + targetReg + "\n";
  257. if (_useTexture) {
  258. code += "mul " + targetReg + ".xyz, " + albedo + ", " + targetReg + "\n" +
  259. "mov " + targetReg + ".w, " + albedo + ".w\n";
  260. } else {
  261. code += "mul " + targetReg + ".xyz, " + _diffuseInputRegister + ", " + targetReg + "\n" +
  262. "mov " + targetReg + ".w, " + _diffuseInputRegister + ".w\n";
  263. }
  264. }
  265. regCache.removeFragmentTempUsage(_totalLightColorReg);
  266. regCache.removeFragmentTempUsage(albedo);
  267. return code;
  268. }
  269. /**
  270. * Generate the code that applies the calculated shadow to the diffuse light
  271. * @param vo The MethodVO object for which the compilation is currently happening.
  272. * @param regCache The register cache the compiler is currently using for the register management.
  273. */
  274. protected function applyShadow(vo:MethodVO, regCache:ShaderRegisterCache):String
  275. {
  276. return "mul " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + _shadowRegister + ".w\n";
  277. }
  278. /**
  279. * @inheritDoc
  280. */
  281. override arcane function activate(vo:MethodVO, stage3DProxy:Stage3DProxy):void
  282. {
  283. if (_useTexture) {
  284. stage3DProxy._context3D.setTextureAt(vo.texturesIndex, _texture.getTextureForStage3D(stage3DProxy));
  285. if (_alphaThreshold > 0)
  286. vo.fragmentData[vo.fragmentConstantsIndex] = _alphaThreshold;
  287. } else {
  288. var index:int = vo.fragmentConstantsIndex;
  289. var data:Vector.<Number> = vo.fragmentData;
  290. data[index] = _diffuseR;
  291. data[index + 1] = _diffuseG;
  292. data[index + 2] = _diffuseB;
  293. data[index + 3] = _diffuseA;
  294. }
  295. }
  296. /**
  297. * Updates the diffuse color data used by the render state.
  298. */
  299. private function updateDiffuse():void
  300. {
  301. _diffuseR = ((_diffuseColor >> 16) & 0xff)/0xff;
  302. _diffuseG = ((_diffuseColor >> 8) & 0xff)/0xff;
  303. _diffuseB = (_diffuseColor & 0xff)/0xff;
  304. }
  305. /**
  306. * Set internally by the compiler, so the method knows the register containing the shadow calculation.
  307. */
  308. arcane function set shadowRegister(value:ShaderRegisterElement):void
  309. {
  310. _shadowRegister = value;
  311. }
  312. }
  313. }