PageRenderTime 26ms CodeModel.GetById 8ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

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