//-------------------------------------------------------------------------------------- // File: EnvMap.fx // // The effect file for the OptimizedMesh sample. // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- /// size of the cube map taken from the reference point of the object #define CUBEMAP_SIZE 128 /// size of the cube map for diffuse/glossy reflections #define LR_CUBEMAP_SIZE 4 /// cube map downsampling rate for diffuse/glossy reflections #define RATE (CUBEMAP_SIZE/LR_CUBEMAP_SIZE) #define PI 3.14159f //-------------------------------------------------------------------------------------- // Global variables //-------------------------------------------------------------------------------------- float4x4 World; ///< World matrix for the current object float4x4 WorldIT; ///< World matrix IT (inverse transposed) to transform surface normals of the current object float4x4 WorldView; ///< World * View matrix //float4x4 WorldViewIT; ///< World * View IT (inverse transposed) to transform surface normals of the current object float4x4 WorldViewProjection; ///< World * View * Projection matrix float texel_size; ///< upload this constant every time the viewport changes float4 eyePos; ///< current eye (camera) position float4 reference_pos; ///< Reference point for the last cube map generation. int nFace; ///< int iShowCubeMap; ///< float4 objColor; float3 nMetal; ///< real part of the refraction coefficient for metals float3 kMetal; ///< imaginary part of the refraction coefficient for metals float sFresnel; ///< Fresnel refraction param. float refractionIndex; float intensity; float shininess; float brightness; texture EnvironmentMap; texture SmallEnvironmentMap; texture PreconvolvedEnvironmentMap; texture Decoration; sampler EnvironmentMapSampler = sampler_state { /*MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = LINEAR;*/ Texture = ; AddressU = WRAP; AddressV = WRAP; }; sampler PreconvolvedEnvironmentMapSampler = sampler_state { MinFilter = LINEAR; MagFilter = LINEAR; //MipFilter = LINEAR; Texture = ; AddressU = WRAP; AddressV = WRAP; }; sampler SmallEnvironmentMapSampler = sampler_state { MinFilter = Point; MagFilter = Point; //MipFilter = Point; Texture = ; AddressU = WRAP; AddressV = WRAP; }; sampler DecorationSampler = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; //MipFilter = LINEAR; AddressU = CLAMP; //WRAP; AddressV = CLAMP; //WRAP; }; // --------------------------------------------------------------------------------------------------- struct ReduceTextureVS_input { ///< vertex shader input float4 Position : POSITION; }; struct ReduceTextureVS_output { ///< vertex shader output, pixel shader input float4 hPosition : POSITION; float2 Position : TEXCOORD0; }; /// See the pixel program. ReduceTextureVS_output ReduceTextureVS(ReduceTextureVS_input IN) { ReduceTextureVS_output OUT; OUT.hPosition = IN.Position; OUT.Position = IN.Position.xy; return OUT; } /// \brief Downsamples a face of a cube map. /// /// Downsamples the nFace-th face of a cube map from resolution #CUBEMAP_SIZE to #LR_CUBEMAP_SIZE /// by averaging the corresponding texel values. The #EnvironmentMap is sampled via #EnvironmentMapSampler. /// \param nFace uniform parameter identifies the current face (0...5) float4 ReduceTexturePS(ReduceTextureVS_output IN) : COLOR { float4 color = 0; float3 dir; for (int i = 0; i < RATE; i++) for (int j = 0; j < RATE; j++) { // generate a position float2 pos; pos.x = IN.Position.x + (2*i + 1)/(float)CUBEMAP_SIZE; pos.y = IN.Position.y - (2*j + 1)/(float)CUBEMAP_SIZE; // y=-u // "scrambling" // ( put the generated position on the nFace-th face ) if (nFace == 0) dir = float3(1, pos.y, -pos.x); if (nFace == 1) dir = float3(-1, pos.y, pos.x); if (nFace == 2) dir = float3(pos.x, 1, -pos.y); if (nFace == 3) dir = float3(pos.x, -1, pos.y); if (nFace == 4) dir = float3(pos.xy, 1); if (nFace == 5) dir = float3(-pos.x, pos.y,-1); color += texCUBE( EnvironmentMapSampler, dir); } return color / (RATE*RATE); } /// \brief Returns the precalculated contribution of a texel with regard to the specified query direction. /// /// \param q query direction (i.e. surface normal in diffuse case, ideal reflection direction in specular case). /// \param L vector pointing to the texel center float4 GetContibution(float3 q, float3 L) // Lin * a * ( dw ) // -- actually, dw is calculated by the caller -- { //float shininess = 1; float fcos = max(dot(L, q), 0); // diffuse if (shininess <= 0) return 0.2 * fcos * texCUBE( SmallEnvironmentMapSampler, L); else // some ad-hoc formula that maintains more even intensity for different shininess values // in case of HDRI environment return (pow(shininess,0.8)*0.2) * pow(fcos, shininess) * texCUBE( SmallEnvironmentMapSampler, L); // return (shininess+2)/8 * pow(fcos, shininess) * texCUBE( SmallEnvironmentMapSampler, L); } /*float4 GetContibution_Metal(float3 q, float3 L) // Lin * a * ( dw ) // -- actually, dw is calculated by the caller -- { float fcos = max(dot(L, q), 0); float4 Lin = texCUBE( SmallEnvironmentMapSampler, L); return Lin * (pow(shininess,0.8)*0.2) * pow(fcos, shininess); }*/ struct ConvolutionVS_input { float4 Position : POSITION; }; struct ConvolutionVS_output { float4 hPosition : POSITION; float3 Position : TEXCOORD0; }; /// See the pixel program. ConvolutionVS_output ConvolutionVS(ConvolutionVS_input IN) { ConvolutionVS_output OUT; OUT.hPosition = IN.Position; float2 pos = IN.Position.xy; // -1..1 pos.x += 1.0f / LR_CUBEMAP_SIZE; pos.y -= 1.0f / LR_CUBEMAP_SIZE; if (nFace == 0) OUT.Position = float3(1, pos.y, -pos.x); if (nFace == 1) OUT.Position = float3(-1, pos.y, pos.x); if (nFace == 2) OUT.Position = float3(pos.x, 1, -pos.y); if (nFace == 3) OUT.Position = float3(pos.x,-1, pos.y); if (nFace == 4) OUT.Position = float3(pos.xy, 1); if (nFace == 5) OUT.Position = float3(-pos.x, pos.y,-1); return OUT; } /// \brief Convolves the values of a cube map. /// /// Calculates the diffuse/specular irradiance map of resolution #LR_CUBEMAP_SIZE by summing up the contributions of all cube map texels /// with regard to the current query direction. /// \param SmallEnvironmentMap is bound to EnvMap::pCubeTextureSmall (cube map of resolution #LR_CUBEMAP_SIZE) float4 ConvolutionPS(ConvolutionVS_output IN) : COLOR { // input position = query direction for the result float3 q = normalize( IN.Position ); float4 color = 0; // for (int i = 0; i < LR_CUBEMAP_SIZE; i++) for (int j = 0; j < LR_CUBEMAP_SIZE; j++) { float u = (i+0.5) / (float)LR_CUBEMAP_SIZE; float v = (j+0.5) / (float)LR_CUBEMAP_SIZE; float3 pos = float3( 2*u-1, 1-2*v, 1 ); float r = length(pos); pos /= r; float4 dcolor = 0; float3 L; L = float3(pos.z, pos.y, -pos.x); dcolor += GetContibution( q, L ); L = float3(-pos.z, pos.y, pos.x); dcolor += GetContibution( q, L ); L = float3(pos.x, pos.z, -pos.y); dcolor += GetContibution( q, L ); L = float3(pos.x, -pos.z, pos.y); dcolor += GetContibution( q, L ); L = float3(pos.x, pos.y, pos.z); dcolor += GetContibution( q, L ); L = float3(-pos.x, pos.y, -pos.z); dcolor += GetContibution( q, L ); float dw = 4 / (r*r*r); // using accurate solid angles //float dw = 4; // assuming equal solid angles color += dcolor*dw; } return 1.5 * color / (LR_CUBEMAP_SIZE * LR_CUBEMAP_SIZE); } // --------------------------------------------------------------------------------------------------- /// \brief This function approximately traces a ray from point x towards direction R. /// Depth information is obtained from the alpha channel of mp. /// \return the approximate hit point. float3 Hit(float3 x, float3 R, sampler mp) { float rl = texCUBE(mp, R).a; // |r| float dp = rl - dot(x, R); // parallax float3 p = x + R * dp; return p; } /// \brief Simple Fresnel term approximation for metals. /// /// The metal is described by its (complex) refraction coefficient (#nMetal,#kMetal). float4 metal_reflectivity(float3 L, float3 N, float3 V) { float3 n = nMetal; float3 k = kMetal; float ctheta_in = dot(N,L); float ctheta_out = dot(N,V); float4 intens = 0; float3 F = 0; // calculating terms F, P, G for Cook-Torrance if ( ctheta_in > 0 && ctheta_out > 0 ) { float3 H = normalize(L + V); // halfway vector float calpha = dot(N,H); float cbeta = dot(H,L); F = ( (n-1)*(n-1) + pow(1-cbeta,5) * 4*n + k*k) / ( (n+1)*(n+1) + k*k ); } return float4(F, 1); } // -------------------------------------------------------- // technique EnvMappedScene // -------------------------------------------------------- struct EnvMapVS_input { float4 Position : POSITION; float3 Normal : NORMAL; float2 TexCoord : TEXCOORD0; }; struct EnvMapVS_output { float4 hPosition : POSITION; float2 TexCoord : TEXCOORD0; float3 Normal : TEXCOORD1; float3 View : TEXCOORD2; float3 Position : TEXCOORD3; }; EnvMapVS_output EnvMapVS( EnvMapVS_input IN ) { EnvMapVS_output OUT; OUT.Position = mul( IN.Position, World ).xyz; // scale & offset OUT.View = normalize( OUT.Position - eyePos ); //OUT.Normal = IN.Normal; OUT.Normal = mul( IN.Normal, WorldIT ).xyz; // allow distortion/rotation OUT.TexCoord = IN.TexCoord; OUT.hPosition = mul( IN.Position, WorldViewProjection ); return OUT; } /// \brief Environment mapping with distance impostors. /// /// Determines the ideal reflection/refraction direction and approximately traces a ray toward that direction using the Hit() function. /// \param EnvironmentMap is bound to EnvMap::pCubeTexture (cube map of resolution #CUBEMAP_SIZE) float4 EnvMapImpostorPS( EnvMapVS_output IN ) : COLOR { IN.View = normalize( IN.View ); IN.Normal = normalize( IN.Normal ); float3 R = reflect(IN.View, IN.Normal); // reflection direction float3 T = refract(IN.View, IN.Normal, refractionIndex); // translate reference point to the origin float3 p0 = IN.Position - reference_pos.xyz; float3 RR = 0, TT = 0; // -------------------------- approximate raytracing -------------------------- // using depth impostors + interpolation RR = Hit(p0, R, EnvironmentMapSampler); // single refraction TT = Hit(p0, T, EnvironmentMapSampler); // reading from the cubemap float4 reflectcolor = texCUBE(EnvironmentMapSampler, RR); float4 refractcolor = texCUBE(EnvironmentMapSampler, TT); float cos_theta = -dot( IN.View, IN.Normal ); // Fresnel approximation float F = (sFresnel + pow(1-cos_theta, 5.0f) * (1-sFresnel)); return intensity * (F * reflectcolor + (1-F) * refractcolor); //return reflectcolor; } float4 EnvMapImpostorMetalPS( EnvMapVS_output IN ) : COLOR { IN.View = normalize( IN.View ); IN.Normal = normalize( IN.Normal ); float3 R = reflect(IN.View, IN.Normal); // reflection direction // translate reference point to the origin float3 p0 = IN.Position - reference_pos.xyz; // -------------------------- approximate raytracing -------------------------- // using depth impostors + interpolation float3 RR = Hit(p0, R, EnvironmentMapSampler); // reading from the cubemap float4 reflectcolor = texCUBE(EnvironmentMapSampler, RR); float3 L = R; return intensity * reflectcolor * metal_reflectivity(L, IN.Normal, -IN.View); //return reflectcolor; } /// \brief Classic environment mapping technique. /// /// Simply determines the ideal reflection/refraction direction and performs a cube map lookup into that direction /// \param EnvironmentMap is bound to EnvMap::pCubeTexture (cube map of resolution #CUBEMAP_SIZE) float4 EnvMapClassicPS( EnvMapVS_output IN ) : COLOR { IN.View = normalize( IN.View ); IN.Normal = normalize( IN.Normal ); float3 R = reflect(IN.View, IN.Normal); float3 T = refract(IN.View, IN.Normal, refractionIndex); float3 p0 = IN.Position; // -------------------------- return value -------------------------- // reading from the cubemap float4 reflectcolor = texCUBE(EnvironmentMapSampler, R); float4 refractcolor = texCUBE(EnvironmentMapSampler, T); float cos_theta = -dot( IN.View, IN.Normal ); // Fresnel approximation float F = (sFresnel + pow(1-cos_theta, 5.0f) * (1-sFresnel)); return intensity * (F * reflectcolor + (1-F) * refractcolor); //return reflectcolor; } /// Classic environment mapping technique with a simple Fresnel term approximation (metal_reflectivity()). float4 EnvMapClassicMetalPS( EnvMapVS_output IN ) : COLOR { IN.View = normalize( IN.View ); IN.Normal = normalize( IN.Normal ); float3 R = reflect(IN.View, IN.Normal); float3 p0 = IN.Position; float4 reflectcolor = texCUBE(EnvironmentMapSampler, R); float3 L = R; return intensity * reflectcolor * metal_reflectivity(L, IN.Normal, -IN.View); //return reflectcolor; } /// \brief Determines diffuse or specular illumination with a single lookup into #PreconvolvedEnvironmentMap. /// \param PreconvolvedEnvironmentMap is bound to EnvMap::pCubeTexturePreConvolved (cube map of resolution #LR_CUBEMAP_SIZE) float4 EnvMapDiffusePS( EnvMapVS_output IN ) : COLOR { IN.View = normalize( IN.View ); IN.Normal = normalize( IN.Normal ); float3 R = reflect(IN.View, IN.Normal); if (shininess <= 0) // diffuse return intensity * texCUBE(PreconvolvedEnvironmentMapSampler, IN.Normal); else // specular return intensity * texCUBE(PreconvolvedEnvironmentMapSampler, R); } /// \brief Calculates the contribution of a single texel of #SmallEnvironmentMap to the illumination of the shaded point. /// /// \param L vector pointing to the center of the texel under examination. We assume that the largest coordinate component /// of L is equal to one, i.e. L points to the face of a cube of edge length of 2. /// \param pos is the position of the shaded point /// \param N is the surface normal at the shaded point /// \param V is the viewing direction at the shaded point float4 GetContibution(float3 L, float3 pos, float3 N, float3 V) // Phong-Blinn // L: a hossza lényeges (az egységkocka faláig ér) { float kd = 0.4; // 0.3 float ks = 0.5; // 0.5 float l = length(L); L = normalize(L); //Lin float4 Lin = texCUBE(SmallEnvironmentMapSampler, L); //dw float dw = 4 / (LR_CUBEMAP_SIZE*LR_CUBEMAP_SIZE*l*l*l + 4/2/3.1416f); float dws = dw; //#ifdef LOCALIZE //r float doy = texCUBE(SmallEnvironmentMapSampler, L).a; float dxy = length(pos - L * doy); //dws dws = (doy*doy * dw) / (dxy*dxy*(1 - dw/2/3.1416f) + doy*doy*dw/2/3.1416f); // localization L = L * doy - pos; // L should start from the object (and not from the reference point) L = normalize(L); //#endif float3 H = normalize(L + V); // felezővektor float3 R = reflect(-V, N); // reflection vector // a: from texture float4 color = 0; float a = 0; if ( shininess <= 0 ) a = kd * max(dot(N,L),0); // diffuse else a = ks * pow(max(dot(N,H),0), shininess) * (shininess+2)/(2*PI); // specular // note: using dot(N,H) looks better than dot(R,L) return Lin * a * dws; } /// \brief Calculates diffuse or specular contributions of all texels in #SmallEnvironmentMap to the current point. /// For each texel of #SmallEnvironmentMap, function GetContibution(float3,float3,float3,float3) is called. /// \param SmallEnvironmentMap is bound to EnvMap::pCubeTextureSmall (cube map of resolution #LR_CUBEMAP_SIZE) float4 EnvMapDiffuseLocalizedPS( EnvMapVS_output IN ) : COLOR { IN.View = -normalize( IN.View ); IN.Normal = normalize( IN.Normal ); // translate reference point to the origin IN.Position -= reference_pos.xyz; float3 R = -reflect( IN.View, IN.Normal ); // reflection direction float4 I = 0; for (int x = 0; x < LR_CUBEMAP_SIZE; x++) // foreach texel for (int y = 0; y < LR_CUBEMAP_SIZE; y++) { // compute intensity for 6 texels with equal solid angles float2 tpos; tpos.x = x/(float)LR_CUBEMAP_SIZE; // 0..1 tpos.y = y/(float)LR_CUBEMAP_SIZE; // 0..1 tpos.xy += float2(0.5/LR_CUBEMAP_SIZE, 0.5/LR_CUBEMAP_SIZE); // offset to texel center float2 p = float2(tpos.x, 1-tpos.y); // reverse y p.xy = 2*p.xy - 1; // -1..1 float3 L; L = float3(p.x, p.y, 1); I += GetContibution( L, IN.Position, IN.Normal, IN.View ); L = float3(p.x, p.y, -1); I += GetContibution( L, IN.Position, IN.Normal, IN.View ); L = float3(p.x, 1, p.y); I += GetContibution( L, IN.Position, IN.Normal, IN.View ); L = float3(p.x, -1, p.y); I += GetContibution( L, IN.Position, IN.Normal, IN.View ); L = float3(1, p.x, p.y); I += GetContibution( L, IN.Position, IN.Normal, IN.View ); L = float3(-1, p.x, p.y); I += GetContibution( L, IN.Position, IN.Normal, IN.View ); } return intensity * I; } /// \brief Calculates the contribution of a single texel of #SmallEnvironmentMap to the illumination of the shaded point. /// /// The only difference from GetContibution(float3,float3,float3,float3) is that /// now we use precalculated integral values to compute reflectivity (instead of using only one sample). float4 GetContibutionWithCosLookup(float3 L, float3 pos, float3 N, float3 V) // Phong-Blinn // L: a hossza lényeges (az egységkocka faláig ér) { float ks = 0.5; // 0.5 float l = length(L); L = normalize(L); //Lin float4 Lin = texCUBE(SmallEnvironmentMapSampler, L); //dw //float dw = 4 / (LIGHT_TEXTURE_SIZE*LIGHT_TEXTURE_SIZE*l*l*l + 4/3.1416f); float dw = 4 / (LR_CUBEMAP_SIZE*LR_CUBEMAP_SIZE*l*l*l + 4/2/3.1416f); float dws = dw; //#ifdef LOCALIZE //if (localize > 0) { //r float doy = texCUBE(SmallEnvironmentMapSampler, L).a; float dxy = length(pos - L * doy); //dws //dws = (doy*doy * dw) / (dxy*dxy*(1 - dw/3.1416f) + doy*doy*dw/3.1416f); // localization: dws = (doy*doy * dw) / (dxy*dxy*(1 - dw/2/3.1416f) + doy*doy*dw/2/3.1416f); // localization: // az illum.képletben használt L kiszámítása L = L * doy - pos; // bugfix: L az objektumtól induljon, ne a középpontból (x->y) L = normalize(L); } //#endif float3 H = normalize(L + V); // felezővektor float3 R = reflect(-V, N); // reflection vector // from texture float4 color = 0; float cos_value; if (shininess <= 0) cos_value = dot(N,L); // diffuse else cos_value = dot(R,L); // specular float2 tex; tex.x = (cos_value + 1)/2; tex.y = dws/2/PI; cos_value = tex2D(DecorationSampler, tex).g * 3; //color = Lin * kd * cos_value * 2; // bugfix: kd color = Lin * ks * cos_value * 1.2; // ks //return Lin * cos_value; return color; } /// \brief Calculates diffuse or specular contributions of all texels in #SmallEnvironmentMap to the current point. /// For each texel of #SmallEnvironmentMap, function GetContibutionWithCosLookup() is called. /// \param SmallEnvironmentMap is bound to EnvMap::pCubeTextureSmall (cube map of resolution #LR_CUBEMAP_SIZE) float4 EnvMapDiffuseLocalizedWithCosLookupPS( EnvMapVS_output IN ) : COLOR { IN.View = -normalize( IN.View ); IN.Normal = normalize( IN.Normal ); IN.Position -= reference_pos.xyz; float3 R = -reflect( IN.View, IN.Normal ); // reflection direction float4 I = 0; for (int x = 0; x < LR_CUBEMAP_SIZE; x++) // foreach texel for (int y = 0; y < LR_CUBEMAP_SIZE; y++) { // compute intensity for 6 texels with equal solid angles float2 tpos; tpos.x = x/(float)LR_CUBEMAP_SIZE; // 0..1 tpos.y = y/(float)LR_CUBEMAP_SIZE; // 0..1 tpos.xy += float2(0.5/LR_CUBEMAP_SIZE, 0.5/LR_CUBEMAP_SIZE); // offset to texel center float2 p = float2(tpos.x, 1-tpos.y); // reverse y p.xy = 2*p.xy - 1; // -1..1 float3 L; L = float3(p.x, p.y, 1); I += GetContibutionWithCosLookup( L, IN.Position, IN.Normal, IN.View ); L = float3(p.x, p.y, -1); I += GetContibutionWithCosLookup( L, IN.Position, IN.Normal, IN.View ); L = float3(p.x, 1, p.y); I += GetContibutionWithCosLookup( L, IN.Position, IN.Normal, IN.View ); L = float3(p.x, -1, p.y); I += GetContibutionWithCosLookup( L, IN.Position, IN.Normal, IN.View ); L = float3(1, p.x, p.y); I += GetContibutionWithCosLookup( L, IN.Position, IN.Normal, IN.View ); L = float3(-1, p.x, p.y); I += GetContibutionWithCosLookup( L, IN.Position, IN.Normal, IN.View ); } return intensity * I; } // -------------------------------------------------------- // technique IlluminatedScene // -------------------------------------------------------- struct IlluminatedSceneVS_input { float4 Position : POSITION; float3 Normal : NORMAL; float2 TexCoord : TEXCOORD0; }; struct IlluminatedSceneVS_output { float4 hPosition : POSITION; float2 TexCoord : TEXCOORD0; float3 Position : TEXCOORD1; }; IlluminatedSceneVS_output IlluminatedSceneVS( IlluminatedSceneVS_input IN ) { IlluminatedSceneVS_output OUT; OUT.hPosition = mul( IN.Position, WorldViewProjection ); // texel_size as uniform parameter OUT.hPosition.x -= texel_size * OUT.hPosition.w; OUT.hPosition.y += texel_size * OUT.hPosition.w; if (iShowCubeMap > 0) { // if one of the cube maps is displayed on the walls, // position is simply forwarded OUT.Position = IN.Position; } else { // also consider camera orientation OUT.Position = mul( IN.Position, WorldView ); } OUT.TexCoord = IN.TexCoord; return OUT; } /// Displays the environment with a simple shading float4 IlluminatedScenePS( IlluminatedSceneVS_output IN ) : COLOR0 { float3 color = objColor * tex2D(DecorationSampler, IN.TexCoord); if (iShowCubeMap > 0) { // if one of the cube maps should be displayed on the walls, // display it color = texCUBE(EnvironmentMapSampler, IN.Position) * intensity; } else { // create an exponential falloff for each face of the room float3 L = float3(2*IN.TexCoord.x-1, 2*IN.TexCoord.y-1, -1); L = normalize(L); float3 N = float3(0,0,1); color *= abs(pow(dot(L,N), 3)) * brightness; } float dist = length( IN.Position ); return float4(color, dist); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- /// a helpful macro to define techniques with a common vertex program #define TechniqueUsingCommonVS(name); \ technique name \ { \ pass p0 \ { \ VertexShader = compile vs_3_0 EnvMapVS(); \ PixelShader = compile ps_3_0 name##PS(); \ } \ } TechniqueUsingCommonVS( EnvMapClassic ); TechniqueUsingCommonVS( EnvMapClassicMetal ); TechniqueUsingCommonVS( EnvMapImpostor ); TechniqueUsingCommonVS( EnvMapImpostorMetal ); TechniqueUsingCommonVS( EnvMapDiffuse ); TechniqueUsingCommonVS( EnvMapDiffuseLocalized ); TechniqueUsingCommonVS( EnvMapDiffuseLocalizedWithCosLookup ); /// a helpful macro to define techniques #define Technique(name); \ technique name \ { \ pass p0 \ { \ VertexShader = compile vs_3_0 name##VS(); \ PixelShader = compile ps_3_0 name##PS(); \ } \ } // defining techniques // where the name of EnvMapVS program is EnvMapVS // and the name of PS program is PS Technique( IlluminatedScene ); Technique( ReduceTexture ); Technique( Convolution );