/* CgFX 1.4 file for layers effect intended for cgfx_interfaces.c. */ /* This effect demonstrates how interfaces can be used to combine multiple abstract implementations of a shading concept. In this example, a layer returns a color given a texture coordinate set, object-space light vector, and object-space view vector. The implementation of a layer return the appropriate color of its layer. Several layers implementations and an example instance of each are provided: checkBoardLayer - red and transparent checkerboard triangleLayer - green and transparent triangle pattern constantLayer - thick yellow constant color diffuseLayer - based on diffuse lighting specularLayer - based on specular lighting fresnelLayer - view-dependent blue-ing of edges The "layers" effect parameter is an unsized (run-time sized and specified) array of Layer interfaces. The "LayerOrderList" annotation on the layers effect parameter is a string listing the layer instance in a given order. The application can read this annotation to determine how the layers should be applied. */ // Abstract interface for a layer interface Layer { float4 evaluate(float2 uv, float3 L, float3 V); }; // Implement a Layer defining a checkerboard pattern struct CheckerBoardLayer : Layer { float2 scale; float4 color1, color2; float4 evaluate(float2 uv, float3 L, float3 V) { uv = frac(scale * uv); float4 color = uv.x >= 0.5 ? (uv.y >= 0.5 ? color1 : color2) : (uv.y >= 0.5 ? color2 : color1); // Pre-multiply by alpha for later over compositing. color.rgb = color.rgb * color.a; return color; } }; // Parameterized instance the checkerboard layer CheckerBoardLayer checkerBoardLayer = { float2(4,4), // scale float4(1,0,0,0.5), // color1 = 50% red float4(0,0,0,0.0), // color2 = transparent }; // Implement a Layer defining a triangle pattern struct TriangleLayer : Layer { float2 scale; float4 color1, color2; float4 evaluate(float2 uv, float3 L, float3 V) { uv = frac(scale * uv); float4 color = frac(0.5*(uv.x+uv.y)) >= 0.5 ? color1 : color2; // Pre-multiply by alpha for later over compositing. color.rgb = color.rgb * color.a; return color; } }; // Parameterized instance the triangle pattern layer TriangleLayer triangleLayer = { float2(7,3), float4(0,1,0,0.8), // color1 = 30% green float4(1,1,1,0.1), // color2 = 10% white }; // Implement a Layer defining a constant color struct ConstantLayer : Layer { float4 constant; float4 evaluate(float2 uv, float3 L, float3 V) { // Pre-multiply by alpha for later over compositing. return float4(constant.rgb * constant.a, constant.a); } }; // Parameterized instance the constant color layer ConstantLayer thickYellowLayer = { float4(0.8, 0.8, 0.2, 0.7), // 70% yellow }; // Implement a Layer defining by diffuse shading struct DiffuseLayer : Layer { float opacity; float4 evaluate(float2 uv, float3 L, float3 V) { const float3 N = float3(0,0,1); L = normalize(L); float diffuse = dot(L,N); // Pre-multiply by alpha for later over compositing. return float4(diffuse * opacity); } }; // Parameterized instance the diffuse layer DiffuseLayer diffuseLayer = { 0.2, // opacity }; // Implement a Layer defining by specular shading struct SpecularLayer : Layer { float opacity; float shininess; float4 evaluate(float2 uv, float3 L, float3 V) { const float3 N = float3(0,0,1); L = normalize(L); V = normalize(V); float3 H = normalize(L+V); float diffuse = dot(L,N); float specular = diffuse > 0 ? pow(max(0, dot(H,N)), shininess) : 0; // Pre-multiply by alpha for later over compositing. return float4(specular * opacity); } }; // Parameterized instance the specular layer SpecularLayer specularLayer = { 0.8, // opacity 31.5, // shininess }; // Implement a Layer defining by fresnel shading struct FresnelLayer : Layer { float power; float3 color; float4 evaluate(float2 uv, float3 L, float3 V) { const float3 N = float3(0,0,1); V = normalize(V); float fresnel = 1-pow(dot(V,N), power); return float4(fresnel * color, fresnel); } }; // Parameterized instance the fresnel layer FresnelLayer fresnelLayer = { 1.7, float3(0.7,0,1), }; // Effect parameter for an unsized (run-time sized and // specified) array of layers Layer layers[] <string LayerOrderList = "thickYellowLayer," "checkerBoardLayer," "diffuseLayer," "fresnelLayer," "specularLayer," "triangleLayer,";>; // Fragment program to "over" composite the array of layers void RenderLayers(float2 texCoord : TEXCOORD0, float3 lightDirection : TEXCOORD1, float3 eyeDirection : TEXCOORD2, out float4 color : COLOR) { float4 result = float4(0,0,0,1); int i; for (i=0; i<layers.length; i++) { float4 layerRGBA = layers[i].evaluate(texCoord, lightDirection, eyeDirection); // "over" compositing operator. result = layerRGBA + (1-layerRGBA.a)*result; } color = result; } // Fragment program to "over" composite the array of layers void RenderReversedLayers(float2 texCoord : TEXCOORD0, float3 lightDirection : TEXCOORD1, float3 eyeDirection : TEXCOORD2, out float4 color : COLOR) { float4 result = float4(0,0,0,1); int i; for (i=layers.length-1; i>=0; i--) { float4 layerRGBA = layers[i].evaluate(texCoord, lightDirection, eyeDirection); // "over" compositing operator. result = layerRGBA + (1-layerRGBA.a)*result; } color = result; } // RollTorus is based on C8E6v_torus from "The Cg Tutorial" // (Addison-Wesley, ISBN 0321194969) by Randima Fernando and // Mark J. Kilgard void RollTorus(float2 parametric : POSITION, out float4 position : POSITION, out float2 oTexCoord : TEXCOORD0, out float3 lightDirection : TEXCOORD1, out float3 eyeDirection : TEXCOORD2, uniform float3 lightPosition, // Object-space uniform float3 eyePosition, // Object-space uniform float4x4 modelViewProj, uniform float2 torusInfo) { const float pi2 = 6.28318530; // 2 times Pi // Stetch texture coordinates counterclockwise // over torus to repeat normal map in 6 by 2 pattern float M = torusInfo[0]; float N = torusInfo[1]; oTexCoord = parametric * float2(-6, 2); // Compute torus position from its parameteric equation float cosS, sinS; sincos(pi2 * parametric.x, sinS, cosS); float cosT, sinT; sincos(pi2 * parametric.y, sinT, cosT); float3 torusPosition = float3((M + N * cosT) * cosS, (M + N * cosT) * sinS, N * sinT); position = mul(modelViewProj, float4(torusPosition, 1)); // Compute per-vertex rotation matrix float3 dPds = float3(-sinS*(M+N*cosT), cosS*(M+N*cosT), 0); float3 norm_dPds = normalize(dPds); float3 normal = float3(cosS * cosT, sinS * cosT, sinT); float3 dPdt = cross(normal, norm_dPds); float3x3 rotation = float3x3(norm_dPds, dPdt, normal); // Rotate object-space vectors to texture space eyeDirection = eyePosition - torusPosition; lightDirection = lightPosition - torusPosition; lightDirection = mul(rotation, lightDirection); eyeDirection = mul(rotation, eyeDirection); eyeDirection = normalize(eyeDirection); } // Effect parameters passed as vertex program parameters float4x4 ModelViewProj : ModelViewProjection; float OuterRadius = 6; float InnerRadius = 2; float3 LightPosition = { -8, 0, 15 }; float3 EyePosition = { 0, 0, 18 }; // Technique with best profiles for GeForce 6x00, 7x00, and higher GPUs technique RenderLayers_nv40 { pass forward { VertexProgram = compile vp40 RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile fp40 RenderLayers(); } pass reverse { VertexProgram = compile vp40 RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile fp40 RenderReversedLayers(); } } // Technique with best profiles for GeForce 5x00 GPUs technique RenderLayers_nv30 { pass forward { VertexProgram = compile vp30 RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile fp30 RenderLayers(); } pass reverse { VertexProgram = compile vp30 RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile fp30 RenderReversedLayers(); } } // Technique using OpenGL Shading Language (GLSL) profiles technique RenderLayers_glsl { pass forward { VertexProgram = compile glslv RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile glslf RenderLayers(); } pass reverse { VertexProgram = compile glslv RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile glslf RenderReversedLayers(); } } // Technique using multi-vendor ARB assembly profiles technique RenderLayers_arb { pass forward { VertexProgram = compile arbvp1 RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile arbfp1 RenderLayers(); } pass reverse { VertexProgram = compile arbvp1 RollTorus(LightPosition, EyePosition, ModelViewProj, float2(OuterRadius, InnerRadius)); FragmentProgram = compile arbfp1 RenderReversedLayers(); } }