Var* GBufferConditionerGLSL::_conditionOutput( Var *unconditionedOutput, MultiLine *meta ) { Var *retVar = new Var; retVar->setType("vec4"); retVar->setName("_gbConditionedOutput"); LangElement *outputDecl = new DecOp( retVar ); switch(mNormalStorageType) { case CartesianXYZ: meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.xyz, depth)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("@.xyz", unconditionedOutput)), unconditionedOutput ) ); break; case CartesianXY: meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, @.a);", outputDecl, _posnegEncode(new GenOp("vec3(@.xy, sign(@.z))", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) ); break; case Spherical: meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, 0.0, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("vec2(atan2(@.y, @.x) / 3.14159265358979323846f, @.z)", unconditionedOutput, unconditionedOutput, unconditionedOutput ) ), unconditionedOutput ) ); break; } // Encode depth into two channels if(mNormalStorageType != CartesianXYZ) { const U64 maxValPerChannel = 1 << mBitsPerChannel; const U64 extraVal = (maxValPerChannel * maxValPerChannel - 1) - (maxValPerChannel - 1) * 2; meta->addStatement( new GenOp( " \r\n // Encode depth into hi/lo\r\n" ) ); meta->addStatement( new GenOp( avar( " vec3 _tempDepth = fract(@.a * vec3(1.0, %llu.0, %llu.0));\r\n", maxValPerChannel - 1, extraVal ), unconditionedOutput ) ); meta->addStatement( new GenOp( avar( " @.zw = _tempDepth.xy - _tempDepth.yz * vec2(1.0/%llu.0, 1.0/%llu.0);\r\n\r\n", maxValPerChannel - 1, maxValPerChannel - 1 ), retVar ) ); } AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) ); return retVar; }
Var* GBufferConditionerGLSL::_conditionOutput( Var *unconditionedOutput, MultiLine *meta ) { Var *retVar = new Var; retVar->setType("float4"); retVar->setName("_gbConditionedOutput"); LangElement *outputDecl = new DecOp( retVar ); switch(mNormalStorageType) { case CartesianXYZ: meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.xyz, depth)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("@.xyz", unconditionedOutput)), unconditionedOutput ) ); break; case CartesianXY: meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, @.a);", outputDecl, _posnegEncode(new GenOp("float3(@.xy, sign(@.z))", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) ); break; case Spherical: meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, 0.0, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("float2(atan2(@.y, @.x) / 3.14159265358979323846f, @.z)", unconditionedOutput, unconditionedOutput, unconditionedOutput ) ), unconditionedOutput ) ); // HACK: This fixes the noise present when using a floating point // gbuffer on Geforce cards and the "flat areas unlit" issues. // // We need work around atan2() above to fix this issue correctly // without the extra overhead of this test. // meta->addStatement( new GenOp( " if ( abs( dot( @.xyz, float3( 0.0, 0.0, 1.0 ) ) ) > 0.999f ) @ = float4( 0, 1 * sign( @.z ), 0, @.a );\r\n", unconditionedOutput, retVar, unconditionedOutput, unconditionedOutput ) ); break; case LambertAzimuthal: //http://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection // // Note we're casting to half to use partial precision // sqrt which is much faster on older Geforces while // still being acceptable for normals. // meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.X, normal.Y, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, 0.0, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("sqrt(half(2.0/(1.0 - @.y))) * half2(@.xz)", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) ); break; } // Encode depth into two channels if(mNormalStorageType != CartesianXYZ) { const U64 maxValPerChannel = 1 << mBitsPerChannel; meta->addStatement( new GenOp( " \r\n // Encode depth into hi/lo\r\n" ) ); meta->addStatement( new GenOp( avar( " float2 _tempDepth = frac(@.a * float2(1.0, %llu.0));\r\n", maxValPerChannel - 1 ), unconditionedOutput ) ); meta->addStatement( new GenOp( avar( " @.zw = _tempDepth.xy - _tempDepth.yy * float2(1.0/%llu.0, 0.0);\r\n\r\n", maxValPerChannel - 1 ), retVar ) ); } AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) ); return retVar; }