// transformations float4x4 WorldViewProj; float4x4 ViewProj; float4x4 ViewProjI; float4x4 World; float4x4 WorldIT; float3 EyePos; float3 TilePos; float RefractionIndex; float colOrder; #define MIN_RAY_DEPTH 0.01 #define MAX_RAY_DEPTH 200.0 #define RAY_TABLE_SIZE 512.0 float4 ConePeak; float4 ConeDirAndCosAngle; texture rayDirTable; sampler rayDirTableSampler = sampler_state { Texture = ; MinFilter = Point; MagFilter = Point; MipFilter = None; }; texture rayOriginTable; sampler rayOriginTableSampler = sampler_state { Texture = ; MinFilter = Point; MagFilter = Point; MipFilter = None; }; texture coneDirTable; sampler coneDirTableSampler = sampler_state { Texture = ; MinFilter = Point; MagFilter = Point; MipFilter = None; }; texture conePeakTable; sampler conePeakTableSampler = sampler_state { Texture = ; MinFilter = Point; MagFilter = Point; MipFilter = None; }; textureCUBE environmentTexture; sampler environmentSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = None; }; void PrimaryRaysVS ( in float4 Pos : POSITION, in float3 Norm : NORMAL, out float4 hPos : POSITION, out float3 wNorm : TEXCOORD0, out float3 wPos : TEXCOORD1 ) { hPos = mul(Pos, WorldViewProj); wNorm = mul(Norm, WorldIT); wPos = mul(Pos, World).xyz; } void PrimaryRaysPS ( in float3 wNorm : TEXCOORD0, in float3 wPos : TEXCOORD1, out float4 Origin : COLOR0, out float4 Dir : COLOR1) { Origin = float4(wPos, 1); wNorm = normalize(wNorm); float3 ViewDir = wPos - EyePos; ViewDir = normalize(ViewDir); float3 refractedDir = refract(ViewDir, wNorm, RefractionIndex); if(dot(refractedDir, refractedDir) < 0.5) //total internal reflection refractedDir = reflect(ViewDir, wNorm); Dir = float4(refractedDir, colOrder); Dir.xyz = normalize(Dir.xyz); } struct vsInputCopyBack { float4 Pos : POSITION; float2 tex : TEXCOORD0; }; struct vsOutputCopyBack { float4 Pos : POSITION; float2 tex : TEXCOORD0; }; vsOutputCopyBack vsCopyBack(vsInputCopyBack input) { vsOutputCopyBack output = (vsOutputCopyBack)0; output.Pos = input.Pos; output.tex = input.tex; return output; } void psCopyBack(vsOutputCopyBack input, out float4 c0 : COLOR0, out float4 c1 : COLOR1) { c0 = tex2D(rayOriginTableSampler, input.tex); c1 = tex2D(rayDirTableSampler, input.tex); } struct vsInputShowTex { float4 Pos : POSITION; float2 tex : TEXCOORD0; }; struct vsOutputShowTex { float4 Pos : POSITION; float2 tex : TEXCOORD0; }; vsOutputShowTex vsShowTex(vsInputShowTex input) { vsOutputShowTex output = (vsOutputShowTex)0; output.Pos = input.Pos; output.tex = input.tex; return output; } float4 psShowTex(vsOutputShowTex input) : COLOR0 { // return abs(float4(tex2D(rayDirTableSampler, input.tex).xyz, 1)); return float4(tex2D(rayOriginTableSampler, input.tex).xyz, 1); // return abs(float4(tex2D(conePeakTableSampler, input.tex).xyz, 1)); // return float4(1,1,0,1); // return float4(input.tex.x,input.tex.y,0,1); // return float4(1.0 - acos(tex2D(coneDirTableSampler, input.tex).aaa) / 3.14, 1); // + float4(0, 0.7, 0, 0); // + float4(tex2D(rayDirTableSampler, input.tex).xyz, 1); float3 relfDir = tex2D(rayDirTableSampler, input.tex); return float4((relfDir.x +1) / 2, (relfDir.y + 1) / 2, (relfDir.z + 1) / 2, 1); } void RayCastVS( in float4 Sphere : POSITION, in float3 PlanePos : NORMAL, in float3 Invmx0 : TEXCOORD0, in float3 Invmx1 : TEXCOORD1, in float3 Invmx2 : TEXCOORD2, in float3 Normals0 : TEXCOORD3, in float3 Normals1 : TEXCOORD4, in float3 Normals2 : TEXCOORD5, out float4 hPos : POSITION, out float3 oPlanePos : TEXCOORD6, out float3 oInvmx0 : TEXCOORD0, out float3 oInvmx1 : TEXCOORD1, out float3 oInvmx2 : TEXCOORD2, out float3 oNormals0 : TEXCOORD3, out float3 oNormals1 : TEXCOORD4, out float3 oNormals2 : TEXCOORD5 ) { oPlanePos = PlanePos; oInvmx0 = Invmx0; oInvmx1 = Invmx1; oInvmx2 = Invmx2; oNormals0 = Normals0; oNormals1 = Normals1; oNormals2 = Normals2; hPos = float4(TilePos, 1); ConeDirAndCosAngle.xyz = mul(WorldIT, float4(ConeDirAndCosAngle.xyz, 0)); ConePeak.xyz = mul(WorldIT, float4(ConePeak.xyz, 1)); float3 sfc = Sphere.xyz - ConePeak.xyz; float lsfc = length(sfc); if(Sphere.w < lsfc) // cone peak not in sphere { // angle difference between cone main direction and direction to sphere centre float angSpMidConeMid = acos(dot(ConeDirAndCosAngle.xyz, sfc) / lsfc); // the half of the opening angle at which the sphere is seen float angSpRad = asin(Sphere.w / lsfc); // cone opening angle float angCone = acos(ConeDirAndCosAngle.w); // if sphere direction not within (cone direction + sphere angle), discard tile for this triangle if(angCone + angSpRad < angSpMidConeMid) { hPos = float4(10000000.0, 10000000.0, 10000000.0, 1.0); } } } void RayCastPS( // in float3 PlanePos : TEXCOORD6, in float3 Invmx0 : TEXCOORD0, in float3 Invmx1 : TEXCOORD1, in float3 Invmx2 : TEXCOORD2, in float3 Normals0 : TEXCOORD3, in float3 Normals1 : TEXCOORD4, in float3 Normals2 : TEXCOORD5, in float2 vPos : VPOS, out float4 oOrigin : COLOR0, out float4 oDir : COLOR1, out float1 oDepth : DEPTH) { float3 PlanePos = Invmx0 + Invmx1 + Invmx2; PlanePos /= dot(PlanePos, PlanePos); float2 pixpos = vPos.xy; pixpos /= RAY_TABLE_SIZE; // to texture coordinates float3 rayOrigin = tex2D(rayOriginTableSampler, pixpos.xy); rayOrigin = mul(WorldIT, float4(rayOrigin, 1)); float3 rayDir = tex2D(rayDirTableSampler, pixpos.xy); rayDir = mul(WorldIT, float4(rayDir, 0)); float hitDepth = (dot(PlanePos, PlanePos) - dot(rayOrigin, PlanePos)) / dot(rayDir, PlanePos); if(hitDepth < MIN_RAY_DEPTH || hitDepth > MAX_RAY_DEPTH) { oDepth = 1000000.0; oOrigin = oDir = 0; } else { float3 hitPoint = rayOrigin + (rayDir * hitDepth); float3 worldDist = mul(float4(hitPoint - rayOrigin, 0), World).xyz; oDepth = length(worldDist) / MAX_RAY_DEPTH; float baryA = dot(Invmx0, hitPoint); float baryB = dot(Invmx1, hitPoint); float baryC = dot(Invmx2, hitPoint); if(baryA > -0.001 && baryB > -0.001 && baryC > -0.001) { oOrigin = mul(float4(hitPoint, 1), World); float3 normalAtHitPoint = Normals0 * baryA; normalAtHitPoint += Normals1 * baryB; normalAtHitPoint += Normals2 * baryC; normalAtHitPoint = normalize(normalAtHitPoint); if(dot(normalAtHitPoint, rayDir) > 0) { normalAtHitPoint = -normalAtHitPoint; RefractionIndex = 1.0 / RefractionIndex; // exiting ray } float3 refractedDir = refract(rayDir, normalAtHitPoint, RefractionIndex); if(dot(refractedDir, refractedDir) < 0.5) // total internal reflection refractedDir = reflect(rayDir, normalAtHitPoint); oDir = float4( mul(float4(refractedDir,0), World).xyz, 1); } else { oOrigin = float4(10.0, 0, 0, 1); oDir = float4(10.0, 0, 0, 1); oDepth = 1000000.0; } } } struct vsInputBackGround { float4 Pos : POSITION; //Pos float2 tex : TEXCOORD0; }; struct vsOutputBackGround { float4 Pos : POSITION; //Pos float2 tex : TEXCOORD0; float3 wPos : TEXCOORD1; }; vsOutputBackGround vsBackground(vsInputBackGround input){ vsOutputBackGround output = (vsOutputBackGround)0; output.Pos=input.Pos; float4 worldpos = mul(input.Pos, ViewProjI); worldpos /= worldpos.w; output.wPos = worldpos.xyz; output.tex = input.tex; return output; } void psBackground(vsOutputBackGround input, out float4 o0 : COLOR0) { float4 dird = tex2D(rayDirTableSampler, input.tex); float3 Dir = dird.xyz; float3 col = 1 ; /*float3(pow(0.7, frac(dird.w / 10.0) * 10.0) , pow(0.7, frac(dird.w / 100.0) * 10.0) , pow(0.7, frac(dird.w / 1000.0) * 10.0));*/ if(dot(Dir, Dir) < 0.5) { Dir = normalize(input.wPos.xyz - EyePos.xyz); col = float3(4, 4, 4); } o0 = float4(texCUBE(environmentSampler, Dir).xyz * col * 1.1, 0.0); // o0 = float4(dird.w / 5.0, dird.w / 2.0, dird.w / 10.0, 1.0); // o0 = float4(input.tex.x, input.tex.y, 1.0, 1.0); } void ConeVS( in float4 Pos : POSITION, in float2 Tex : TEXCOORD0, out float4 oPos : POSITION, out float2 oTex : TEXCOORD0 ) { oPos = Pos; oTex = Tex; } void ConePS( in float2 Tex : TEXCOORD0, out float4 oConePeak : COLOR0, out float4 oConeDir : COLOR1) { float3 peak = 0; float3 dir = 0; float cosAngle = 1.0; float sinAngle = 0.0; for(int i=0; i < 16; i++) for(int j=0; j < 16; j++) { float3 currentRayDir = tex2D(rayDirTableSampler, Tex + float2((float)j/RAY_TABLE_SIZE, (float)i/RAY_TABLE_SIZE)); if(dot(currentRayDir, currentRayDir) > 0.5) // a valid ray { float3 currentRayOrigin = tex2D(rayOriginTableSampler, Tex + float2((float)j/RAY_TABLE_SIZE, (float)i/RAY_TABLE_SIZE)); if(dot(dir,dir) < 0.5) // no valid ray found before this one { dir = currentRayDir; peak = currentRayOrigin; } else { float ncos = dot(currentRayDir,dir); if(ncos < cosAngle) { float3 perpdir = normalize(currentRayDir - ncos * dir); float3 farConeEdge = cosAngle * dir - sinAngle * perpdir; dir = farConeEdge + currentRayDir; dir = normalize(dir); cosAngle = dot(dir, currentRayDir); sinAngle = sqrt(1.0 - cosAngle * cosAngle); } float3 pd = currentRayOrigin - peak; float3 ptop = normalize(pd); float cospp = dot(dir, ptop); if(cospp < cosAngle) { float3 perpdir = ptop - cospp * dir; perpdir = normalize(perpdir); float3 farConeEdge = (cosAngle * dir - sinAngle * perpdir); float3 nearConeEdge = (cosAngle * dir + sinAngle * perpdir); float3 g = currentRayOrigin - peak - nearConeEdge * dot(nearConeEdge, pd); peak += farConeEdge * dot(g,g) / dot(farConeEdge, g); } } } } oConePeak = float4(peak, 1.0); oConeDir = float4(dir, cosAngle); if(dot(dir, dir) < 0.5) // no valid rays in tile { //cone far away not intersecting anything oConePeak = float4(1000000.0, 0 , 0, 0.0); oConeDir = float4(1, 0, 0, 1.0); } } technique RenderPrimaryRayArray{ pass P0 { VertexShader = compile vs_3_0 PrimaryRaysVS(); PixelShader = compile ps_3_0 PrimaryRaysPS(); } } technique RayCast{ pass P0 { VertexShader = compile vs_3_0 RayCastVS(); PixelShader = compile ps_3_0 RayCastPS(); } } technique ShowTex{ pass P0 { VertexShader = compile vs_2_0 vsShowTex(); PixelShader = compile ps_2_0 psShowTex(); } } technique Background{ pass P0 { VertexShader = compile vs_2_0 vsBackground(); PixelShader = compile ps_2_0 psBackground(); } } technique CopyBack{ pass P0 { VertexShader = compile vs_2_0 vsCopyBack(); PixelShader = compile ps_2_0 psCopyBack(); } } technique ComputeCones{ pass P0 { VertexShader = compile vs_3_0 ConeVS(); PixelShader = compile ps_3_0 ConePS(); } }