float4x4 objectToWorldMatrix; float4x4 worldToCameraMatrix; float4x4 cameraToObjectMatrix; // modelview inverse float4x4 projMatrix; float4x4 textureMatrix; TextureCube CubeMap : register(t0);; //Texture2D txDiffuse; //Texture2D Image : register(t0); sampler texSampler : register(s0); float g_CubeSize = 256; float g_CubeLod = 0; float g_CubeLodCount = 1; // float Roughness; // int BaseMip; // int NumSamples; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer Params : register(b0) { float Roughness; int BaseMip; int NumSamples; float Exposure; } float mod(float a, float b) { return a - b*floor(a/b); } float3 mod(float3 a, float b) { return a - b*floor(a/b); } static const float PI = 3.14159265358979; float radicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); return float(bits) * 2.3283064365386963e-10; // / 0x100000000 } float2 hammersley2d(uint i, uint N) { return float2(float(i)/float(N), radicalInverse_VdC(i)); } /* float3 hemisphereSample_uniform(float u, float v) { float phi = v * 2.0 * PI; float cosTheta = 1.0 - u; float sinTheta = sqrt(1.0 - cosTheta * cosTheta); return float3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); } float3 hemisphereSample_cos(float u, float v) { float phi = v * 2.0 * PI; float cosTheta = sqrt(1.0 - u); float sinTheta = sqrt(1.0 - cosTheta * cosTheta); return float3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); } float3 importanceSampleGGX(float2 xi, float3 N) { float alpha = Roughness * Roughness; float alpha2 = alpha*alpha; float phi = 2 * PI * xi.x; float cosTheta = sqrt((1 - xi.y) / (1 + (alpha2 - 1) * xi.y)); float sinTheta = sqrt(1 - cosTheta*cosTheta); float3 H; H.x = sinTheta * cos(phi); H.y = sinTheta * sin(phi); H.z = cosTheta; float3 up = abs(N.z) < 0.999 ? float3(0,0,1) : float3(1,0,0); float3 tangentX = normalize(cross(up, N)); float3 tangentY = cross(N, tangentX); return tangentX*H.x + tangentY*H.y + N*H.z; } */ struct vsOutput { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; void vsMain(out vsOutput o, uint id : SV_VERTEXID) { o.uv = float2((id << 1) & 2, id & 2); o.pos = float4(o.uv * float2(2,-2) + float2(-1,1), 0, 1); //o.uv = (o.pos.xy * float2(0.5,-0.5) + 0.5) * 4; //o.uv.y = 1 - o.uv.y; } struct gsOutput { float4 pos : SV_POSITION; float3 nrm : TEXCOORD0; float4 col : COLOR0; uint face : SV_RENDERTARGETARRAYINDEX; }; float4 colorOfBox(uint face) { float4 c = float4(0,0,0,1); if (face == 0) // posx (red) { c = float4(1,0,0,1); } else if (face == 1) // negx (cyan) { c = float4(1,1,0,1); } else if (face == 2) // posy (green) { c = float4(0,1,0,1); } else if (face == 3) // negy (magenta) { c = float4(0,1,1,1); } else if (face == 4) // posz (blue) { c = float4(0,0,1,1); } else // if (i.face == 5) // negz (yellow) { c = float4(1,0,1,1); } return c; } float3 UvAndIndexToBoxCoord(float2 uv, uint face) { float3 n = float3(0,0,0); float3 t = float3(0,0,0); if (face == 0) // posx (red) { n = float3(1,0,0); t = float3(0,1,0); } else if (face == 1) // negx (cyan) { n = float3(-1,0,0); t = float3(0,1,0); } else if (face == 2) // posy (green) { n = float3(0,-1,0); t = float3(0,0,-1); } else if (face == 3) // negy (magenta) { n = float3(0,1,0); t = float3(0,0,1); } else if (face == 4) // posz (blue) { n = float3(0,0,-1); t = float3(0,1,0); } else // if (i.face == 5) // negz (yellow) { n = float3(0,0,1); t = float3(0,1,0); } float3 x = cross(n, t); uv = uv * 2 - 1; n = n + t*uv.y + x*uv.x; n.y *= -1; n.z *= -1; return n; } [maxvertexcount(18)] void gsMain(triangle vsOutput input[3], inout TriangleStream output) { for( int f = 0; f < 6; ++f ) { for( int v = 0; v < 3; ++v ) { gsOutput o; o.pos = input[v].pos; o.nrm = UvAndIndexToBoxCoord(input[v].uv, f); o.col = colorOfBox(f); o.face = f; output.Append(o); } output.RestartStrip(); } } // static const SamplerState g_samCube // { // Filter = MIN_MAG_MIP_LINEAR; // AddressU = Clamp; // AddressV = Clamp; // }; /* cbuffer mip : register(b0) { float g_CubeSize; float g_CubeLod; float g_CubeLodCount; }; */ // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html /* float radicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); return float(bits) * 2.3283064365386963e-10; // / 0x100000000 } */ // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html float2 Hammersley(uint i, uint N) { return float2(float(i)/float(N), radicalInverse_VdC(i)); } float G_schlick_IBL(float NoV, float NoL, float roughness) { float k = roughness*roughness/2.0f; float one_minus_k = 1.0f - k; return (NoL / (NoL * one_minus_k + k)) * (NoV / (NoV * one_minus_k + k) ); } // Image-Based Lighting // http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf float3 ImportanceSampleGGX( float2 Xi, float roughness, float3 N ) { float a = roughness * roughness; float Phi = 2 * PI * Xi.x; float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) ); float SinTheta = sqrt( 1 - CosTheta * CosTheta ); float3 H; H.x = SinTheta * cos( Phi ); H.y = SinTheta * sin( Phi ); H.z = CosTheta; float3 UpVector = abs(N.z) < 0.999 ? float3(0,0,1) : float3(1,0,0); float3 TangentX = normalize( cross( UpVector, N ) ); float3 TangentY = cross( N, TangentX ); // Tangent to world space return TangentX * H.x + TangentY * H.y + N * H.z; } // Ignacio Castano via http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ float3 fix_cube_lookup_for_lod(float3 v, float cube_size, float lod) { float M = max(max(abs(v.x), abs(v.y)), abs(v.z)); float scale = 1 - exp2(lod) / cube_size; if (abs(v.x) != M) v.x *= scale; if (abs(v.y) != M) v.y *= scale; if (abs(v.z) != M) v.z *= scale; return v; } float D_GGX(float NoH, float roughness) { // towbridge-reitz / GGX distribution float alpha = roughness*roughness; float alpha2 = alpha*alpha; float NoH2 = NoH*NoH; float f = NoH2 * (alpha2 - 1.0) + 1; return alpha2 / (3.1415 * f*f); } //#define REFERENCE_ON float4 psMain(in gsOutput i) : SV_TARGET0 { float3 N = normalize(i.nrm); // return colorOfBox(i.face); float4 totalRadiance = float4(0,0,0,0); float roughness = max(Roughness, 0.01); #ifdef REFERENCE_ON uint NUM_SAMPLES = 25000; #else uint NUM_SAMPLES = NumSamples; #endif [fastopt] for (uint j = 0; j < NUM_SAMPLES; ++j) { float2 Xi = Hammersley(j, NUM_SAMPLES); float3 H = ImportanceSampleGGX(Xi, roughness, N); float3 L = 2*dot(N, H)*H - N; float NdotL = saturate(dot(N, L)); if (NdotL > 0) { #ifdef REFERENCE_ON float mipmapLevel = 0; #else float NdotH = saturate(dot(N,H)); float pdf_H = D_GGX(NdotH, roughness)*NdotH; float pdf = pdf_H/(4*NdotH); // transform from half to incoming float area = 2*3.1415f; // hemispehere area float solidangleSample = area/(NUM_SAMPLES*pdf); // solid angle for sample float solidangleTexel = area/(3.0*128*128); // solid angle per cubemap texel float mipmapLevel = clamp(0.5 * log2(solidangleSample/solidangleTexel), BaseMip, 9); #endif totalRadiance.rgb += CubeMap.SampleLevel(texSampler, L, mipmapLevel).rgb*NdotL; totalRadiance.w += NdotL; } } //return float4(Roughness, Roughness, Roughness, 1); return float4(totalRadiance.rgb / totalRadiance.w * Exposure, 1); } // technique10 Render // { // pass P0 // { // SetVertexShader( CompileShader( vs_5_0, vsMain() ) ); // SetGeometryShader( CompileShader( gs_5_0, gsMain() ) ); // SetPixelShader( CompileShader( ps_5_0, psMain() ) ); // } // }