PageRenderTime 496ms CodeModel.GetById 282ms app.highlight 14ms RepoModel.GetById 197ms app.codeStats 0ms

/src/away3d/materials/methods/FresnelEnvMapMethod.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 204 lines | 131 code | 30 blank | 43 comment | 10 complexity | 70aa7fb98bf772a0cfdefa975faaba80 MD5 | raw file
  1package 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.CubeTextureBase;
  8	import away3d.textures.Texture2DBase;
  9	
 10	import flash.display3D.Context3D;
 11	
 12	use namespace arcane;
 13
 14	/**
 15	 * FresnelEnvMapMethod provides a method to add fresnel-based reflectivity to an object using cube maps, which gets
 16	 * stronger as the viewing angle becomes more grazing.
 17	 */
 18	public class FresnelEnvMapMethod extends EffectMethodBase
 19	{
 20		private var _cubeTexture:CubeTextureBase;
 21		private var _fresnelPower:Number = 5;
 22		private var _normalReflectance:Number = 0;
 23		private var _alpha:Number;
 24		private var _mask:Texture2DBase;
 25
 26		/**
 27		 * Creates an FresnelEnvMapMethod object.
 28		 * @param envMap The environment map containing the reflected scene.
 29		 * @param alpha The reflectivity of the material.
 30		 */
 31		public function FresnelEnvMapMethod(envMap:CubeTextureBase, alpha:Number = 1)
 32		{
 33			super();
 34			_cubeTexture = envMap;
 35			_alpha = alpha;
 36		}
 37
 38		/**
 39		 * @inheritDoc
 40		 */
 41		override arcane function initVO(vo:MethodVO):void
 42		{
 43			vo.needsNormals = true;
 44			vo.needsView = true;
 45			vo.needsUV = _mask != null;
 46		}
 47
 48		/**
 49		 * @inheritDoc
 50		 */
 51		override arcane function initConstants(vo:MethodVO):void
 52		{
 53			vo.fragmentData[vo.fragmentConstantsIndex + 3] = 1;
 54		}
 55
 56		/**
 57		 * An optional texture to modulate the reflectivity of the surface.
 58		 */
 59		public function get mask():Texture2DBase
 60		{
 61			return _mask;
 62		}
 63		
 64		public function set mask(value:Texture2DBase):void
 65		{
 66			if (Boolean(value) != Boolean(_mask) ||
 67				(value && _mask && (value.hasMipMaps != _mask.hasMipMaps || value.format != _mask.format))) {
 68				invalidateShaderProgram();
 69			}
 70			_mask = value;
 71		}
 72
 73		/**
 74		 * The power used in the Fresnel equation. Higher values make the fresnel effect more pronounced. Defaults to 5.
 75		 */
 76		public function get fresnelPower():Number
 77		{
 78			return _fresnelPower;
 79		}
 80		
 81		public function set fresnelPower(value:Number):void
 82		{
 83			_fresnelPower = value;
 84		}
 85		
 86		/**
 87		 * The cubic environment map containing the reflected scene.
 88		 */
 89		public function get envMap():CubeTextureBase
 90		{
 91			return _cubeTexture;
 92		}
 93		
 94		public function set envMap(value:CubeTextureBase):void
 95		{
 96			_cubeTexture = value;
 97		}
 98		
 99		/**
100		 * @inheritDoc
101		 */
102		override public function dispose():void
103		{
104		}
105
106		/**
107		 * The reflectivity of the surface.
108		 */
109		public function get alpha():Number
110		{
111			return _alpha;
112		}
113		
114		public function set alpha(value:Number):void
115		{
116			_alpha = value;
117		}
118		
119		/**
120		 * The minimum amount of reflectance, ie the reflectance when the view direction is normal to the surface or light direction.
121		 */
122		public function get normalReflectance():Number
123		{
124			return _normalReflectance;
125		}
126		
127		public function set normalReflectance(value:Number):void
128		{
129			_normalReflectance = value;
130		}
131
132		/**
133		 * @inheritDoc
134		 */
135		arcane override function activate(vo:MethodVO, stage3DProxy:Stage3DProxy):void
136		{
137			var data:Vector.<Number> = vo.fragmentData;
138			var index:int = vo.fragmentConstantsIndex;
139			var context:Context3D = stage3DProxy._context3D;
140			data[index] = _alpha;
141			data[index + 1] = _normalReflectance;
142			data[index + 2] = _fresnelPower;
143			context.setTextureAt(vo.texturesIndex, _cubeTexture.getTextureForStage3D(stage3DProxy));
144			if (_mask)
145				context.setTextureAt(vo.texturesIndex + 1, _mask.getTextureForStage3D(stage3DProxy));
146		}
147
148		/**
149		 * @inheritDoc
150		 */
151		arcane override function getFragmentCode(vo:MethodVO, regCache:ShaderRegisterCache, targetReg:ShaderRegisterElement):String
152		{
153			var dataRegister:ShaderRegisterElement = regCache.getFreeFragmentConstant();
154			var temp:ShaderRegisterElement = regCache.getFreeFragmentVectorTemp();
155			var code:String = "";
156			var cubeMapReg:ShaderRegisterElement = regCache.getFreeTextureReg();
157			var viewDirReg:ShaderRegisterElement = _sharedRegisters.viewDirFragment;
158			var normalReg:ShaderRegisterElement = _sharedRegisters.normalFragment;
159			
160			vo.texturesIndex = cubeMapReg.index;
161			vo.fragmentConstantsIndex = dataRegister.index*4;
162			
163			regCache.addFragmentTempUsages(temp, 1);
164			var temp2:ShaderRegisterElement = regCache.getFreeFragmentVectorTemp();
165			
166			// r = V - 2(V.N)*N
167			code += "dp3 " + temp + ".w, " + viewDirReg + ".xyz, " + normalReg + ".xyz		\n" +
168				"add " + temp + ".w, " + temp + ".w, " + temp + ".w											\n" +
169				"mul " + temp + ".xyz, " + normalReg + ".xyz, " + temp + ".w						\n" +
170				"sub " + temp + ".xyz, " + temp + ".xyz, " + viewDirReg + ".xyz					\n" +
171				getTexCubeSampleCode(vo, temp, cubeMapReg, _cubeTexture, temp) +
172				"sub " + temp2 + ".w, " + temp + ".w, fc0.x									\n" +               	// -.5
173				"kil " + temp2 + ".w\n" +	// used for real time reflection mapping - if alpha is not 1 (mock texture) kil output
174				"sub " + temp + ", " + temp + ", " + targetReg + "											\n";
175			
176			// calculate fresnel term
177			code += "dp3 " + viewDirReg + ".w, " + viewDirReg + ".xyz, " + normalReg + ".xyz\n" +   // dot(V, H)
178				"sub " + viewDirReg + ".w, " + dataRegister + ".w, " + viewDirReg + ".w\n" +             // base = 1-dot(V, H)
179				
180				"pow " + viewDirReg + ".w, " + viewDirReg + ".w, " + dataRegister + ".z\n" +             // exp = pow(base, 5)
181				
182				"sub " + normalReg + ".w, " + dataRegister + ".w, " + viewDirReg + ".w\n" +             // 1 - exp
183				"mul " + normalReg + ".w, " + dataRegister + ".y, " + normalReg + ".w\n" +             // f0*(1 - exp)
184				"add " + viewDirReg + ".w, " + viewDirReg + ".w, " + normalReg + ".w\n" +          // exp + f0*(1 - exp)
185				
186				// total alpha
187				"mul " + viewDirReg + ".w, " + dataRegister + ".x, " + viewDirReg + ".w\n";
188			
189			if (_mask) {
190				var maskReg:ShaderRegisterElement = regCache.getFreeTextureReg();
191				code += getTex2DSampleCode(vo, temp2, maskReg, _mask, _sharedRegisters.uvVarying) +
192					"mul " + viewDirReg + ".w, " + temp2 + ".x, " + viewDirReg + ".w\n";
193			}
194			
195			// blend
196			code += "mul " + temp + ", " + temp + ", " + viewDirReg + ".w						\n" +
197				"add " + targetReg + ", " + targetReg + ", " + temp + "						\n";
198			
199			regCache.removeFragmentTempUsage(temp);
200			
201			return code;
202		}
203	}
204}