float4 readCubeMap(samplerCUBE cm, float3 coord) { float4 color = texCUBElod( cm, float4(coord.xy, - coord.z,0) ); return color; } float readDistanceCubeMap(samplerCUBE dcm, float3 coord) { float dist = texCUBElod(dcm, float4(coord.xy, - coord.z,0)).a; return dist; } #define MAX_LIN_ITERATIONCOUNT 50 //80 #define MIN_LIN_ITERATIONCOUNT 30 //60 #define SECANT_ITERATIONCOUNT 1 #define MAX_RAY_DEPTH 4 uniform samplerCUBE mp3Color : register(s0); uniform samplerCUBE mp3Dist : register(s1); uniform samplerCUBE mp1 : register(s2); uniform samplerCUBE mp2 : register(s3); void linearSearch( float3 x, float3 R, samplerCUBE mp, out float3 p, out float dl, out float dp, out float llp, out float ppp) { p = 1; float3 Ra = abs(R), xa = abs(x); float a = max(max(xa.x, xa.y), xa.z) / max(max(Ra.x, Ra.y), Ra.z); bool undershoot = false, overshoot = false; float dt = length(x / max(max(xa.x, xa.y), xa.z) - R / max(max(Ra.x, Ra.y), Ra.z)) * MAX_LIN_ITERATIONCOUNT; dt = max(dt, MIN_LIN_ITERATIONCOUNT); dt = 1.0 / dt; float t = 0.01; while( t < 1 && !(overshoot && undershoot) ) { // iteration float dr = a * t / (1 - t); // ray parameter corresponding to t float3 r = x + R * dr; // point on the ray float ra = readDistanceCubeMap(mp, r); // |p'|: distance direction of p if (ra > 0) { // valid texel, i.e. anything is visible float rrp = length(r)/ra; //|r|/|r'| if (rrp < 1) { // undershooting dl = dr; // store last undershooting as l llp = rrp; undershoot = true; } else { dp = dr; // store last overshooting as p ppp = rrp; overshoot = true;} } else { // nothing is visible: restart search undershoot = false; overshoot = false; } t += dt; // next texel } if(!(overshoot && undershoot)) p = float3(0,0,0); } void secantSearch(float3 x, float3 R, samplerCUBE mp, float dl, float dp, float llp, float ppp, out float3 p) { for(int i= 0; i < SECANT_ITERATIONCOUNT; i++) { float dnew; dnew = dl + (dp - dl) * (1 - llp) / (ppp - llp); p = x + R * dnew; half pppnew = length(p) / readDistanceCubeMap(mp, p); if(pppnew < 1) { llp = pppnew; dl = dnew; } else { ppp = pppnew; dp = dnew; } } } float3 Hit(float3 x, float3 R, out float4 Il, out float3 Nl) { float dl1 = 0, dp1, llp1, ppp1; float3 p1; linearSearch(x, R, mp1, p1, dl1, dp1, llp1, ppp1); float dl2 = 0, dp2, llp2, ppp2; float3 p2; linearSearch(x, R, mp2, p2, dl2, dp2, llp2, ppp2); bool valid1 = dot(p1,p1) != 0; bool valid2 = dot(p2,p2) != 0; float dl, dp, llp, ppp; float3 p; if(!valid1 && ! valid2) { linearSearch(x, R, mp3Dist, p, dl, dp, llp, ppp); Il.a = 1; secantSearch(x, R, mp3Dist, dl, dp, llp, ppp, p); Il.rgb = Nl.rgb = readCubeMap(mp3Color, p).rgb; } else { if( !valid2 || (valid1 && dp1 < dp2)) { secantSearch(x, R, mp1, dl1, dp1, llp1, ppp1, p1); Il.rgb = Nl.rgb = readCubeMap(mp1, p1).rgb; p = p1; } else { secantSearch(x, R, mp2, dl2, dp2, llp2, ppp2, p2); Il.rgb = Nl.rgb = readCubeMap(mp2, p2).rgb; p = p2; } Il.a = 0; } return p; } void SpecularReflectionVS( in float4 Pos : POSITION, // modeling space in float4 Norm : NORMAL, // normal vector out float4 hPos : POSITION, // clipping space out float3 x : TEXCOORD1, // cube map space out float3 N : TEXCOORD2, // normal out float3 V : TEXCOORD3, // view uniform float4x4 WorldViewProj, uniform float4x4 World, uniform float4x4 WorldIT, uniform float3 eyePos // eye position ) { hPos = mul(Pos, WorldViewProj); x = mul(Pos, World).xyz; N = mul(Norm, WorldIT).xyz; V = x - eyePos; } float4 SingleReflectionPS( float3 x : TEXCOORD1, // cube map space float3 N : TEXCOORD2, // normal float3 V : TEXCOORD3, // view uniform float Fp0, uniform float3 lastCenter // cube map center position ) : COLOR { x -= lastCenter; V = normalize(V); N = normalize(N); float3 R = reflect(V, N); // reflection dir. float3 Nl; // normal vector at the hit point float3 Il; // radiance at the hit point // ray hit l, radiance Il, normal Nl float3 l = Hit(x, R, Il, Nl); // Fresnel reflection float3 F = Fp0 + pow(1-dot(N, -V), 5) * (1 - Fp0); return float4(F * Il, 1); } float4 MultipleReflectionPS( float3 x : TEXCOORD1, // shaded point in Cube map space float3 N : TEXCOORD2, // normal vector float3 V : TEXCOORD3, // view direction uniform float3 Fp0, // Fresnel at perpendicular direction uniform float3 refIndex, // index of refraction uniform float3 lastCenter ) : COLOR { x-= lastCenter; V = normalize(V); N = normalize(N); float3 I = float3(1, 1, 1);// radiance of the path float3 Fp = Fp0; // Fresnel at 90 degrees at first hit float n = refIndex; // index of refraction of the first hit int depth = 0; // length of the path while (depth < MAX_RAY_DEPTH) { float3 R; // reflection or refraction dir float3 F = Fp + pow(1-abs(dot(N, -V)), 5) * (1-Fp); // Fresnel if (n <= 0) { R = reflect(V, N); // reflection I *= F; // Fresnel reflection } else{ // refraction if (dot(V,N) > 0) { // coming from inside n = 1.0 / n; N = -N; } R = refract(V, N, n); if (dot(R, R) == 0) // no refraction direction exits R = reflect(V, N); // total reflection else I *= (1-F); // Fresnel refraction } float3 Nl; // normal vector at the hit point float4 Il; // radiance at the hit point // Trace ray x+R*d and obtain hit l, radiance Il, normal Nl float3 l = Hit(x, R, Il, Nl); if (Il.a == 0) { // hit point is on specular surface depth += 1; } else { // hit point is on diffuse surface I *= Il.rgb; // multiply with the radiance depth = MAX_RAY_DEPTH; // terminate } N = Nl; V = R; x = l; // hit point is the next shaded point } return float4(I, 1); } struct Shaded_OUT { float4 vPos : POSITION; float4 wNormal : TEXCOORD0; float4 wPos : TEXCOORD1; }; float4 MultipleReflectionPS_o(Shaded_OUT IN, uniform float3 cameraPos, uniform float3 lastCenter) : COLOR0 { return 1; float4 I = float4(0,0,0,0); float3 N = normalize(IN.wNormal.xyz); float3 x = IN.wPos.xyz - lastCenter; float3 V = (IN.wPos.xyz - cameraPos); V = normalize(V); float3 l; //return readCubeMap(NormDistMap2, x).a /2.0 + 0.000000000001 * x.x; int depth = 0; while(depth < MAX_RAY_DEPTH) { float3 R; R = normalize(reflect( V, N)); float3 Nl; float4 Il = 0; l = Hit(x, R, Il, Nl); if(Il.a == 0) { depth += 1; } else { I = Il; depth = MAX_RAY_DEPTH; } x = l; N = Nl; V = R; } if(I.a == 0) I = readCubeMap(mp3Color, l); return I; } float4 MultipleRefractionPS(Shaded_OUT IN, uniform float3 cameraPos, uniform float3 lastCenter, uniform float sFresnel, uniform float refIndex ) : COLOR0 { float4 I = float4(0,0,0,0); float3 N = normalize(IN.wNormal.xyz); float3 x = IN.wPos.xyz - lastCenter; float3 V = (IN.wPos.xyz - cameraPos); V = normalize(V); float F; int depth = 0; F = sFresnel + pow(1 - dot(N, -V), 5) * (1 - sFresnel); while(depth < MAX_RAY_DEPTH) { float3 R; float ri = refIndex; if(dot(V,N) > 0) { ri = 1.0 / ri; N = -N; } R = refract( V, N, ri); if(dot(R,R) == 0) R = reflect( V, N); float3 Nl; float4 Il; float3 l = Hit(x, R, Il, Nl); if(Il.a == 0) { depth += 1; } else { I = Il; depth = MAX_RAY_DEPTH; } x = l; N = normalize(Nl); V = R; } /* if(I.a == 0) { float ri = refIndex; if(dot(V,N) > 0) { ri = 1.0 / ri; N = -N; } float3 R = refract( V, N, ri); if(dot(R,R) == 0) R = reflect( V, N); I = readCubeMap(mp3Color, R); } */ I *= (1.0 - F); return I; } float4 MultipleRefractionPhotonMap_PS(Shaded_OUT IN, uniform float3 cameraPos, uniform float3 lastCenter, uniform float refIndex) : COLOR0 { float4 I = 0; float3 N = normalize(IN.wNormal.xyz); float3 x = IN.wPos.xyz - lastCenter; float3 V = (IN.wPos.xyz - cameraPos); V = normalize(V); int depth = 0; float3 l; while(depth < MAX_RAY_DEPTH) { float3 R; float ri = refIndex; if(dot(V,N) > 0) { ri = 1.0 / ri; N = -N; } R = refract( V, N, ri); if(dot(R,R) == 0) R = reflect( V, N); float3 Nl; float4 Il; l = Hit(x, R, Il, Nl); if(Il.a == 0) { depth += 1; } else { I = Il; depth = MAX_RAY_DEPTH; } x = l; N = normalize(Nl); V = R; } if(I.a == 0) I = float4(V,1); else I = float4(l,1); return I; }