/*********************************************************************NVMH3**** File: $Id: //sw/devtools/SDK/9.5/SDK/MEDIA/HLSL/scene_raytrace.fx#1 $ Copyright NVIDIA Corporation 2004 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Comments: Simple ray tracer in a pixel shader - this is intended to demonstrate branching and early exit in PS 3.0 - based on Paul Heckbert's code from "An Introduction to Ray Tracing" - it only supports spheres currently sgreen@nvidia.com 12/2003 ***************************************************************/ float Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "scene"; string ScriptOrder = "standard"; string ScriptOutput = "color"; string Script = "Technique=PS30;"; > = 0.8; float4x4 view : ViewInverse; float time : Time < string UIWidget = "none"; >; float2 viewport : VIEWPORTPIXELSIZE < string UIWidget = "none">; float foclen < string UIWidget="Slider"; string UIName="Focal Length"; float UIMin = 1.0f; float UIMax = 5000.0f; float UIStep = 10.0f; > = 500.0; float3 lightPosition : POSITION < string UIName="Light Position"; string Object = "PointLight"; string Space = "World"; > = { 10.0, 10.0, -10.0 }; float4 lightColor : DIFFUSE < string UIName = "Light Color"; string Object = "PointLight"; > = { 1.0, 1.0, 1.0, 1.0 }; float shininess < string UIWidget = "slider"; float UIMin = 1.0f; float UIStep = 1.0f; float UIMax = 100.0f; > = 40.0; float4 backgroundColor : DIFFUSE < string UIName="Background Color"; string UIWidget = "color"; > = { 0.0, 0.0, 0.0, 1.0 }; // build a 2D texture with a Whitted-style checkerboard pattern! texture checkTexture < string texturetype = "2D"; string function = "GenerateCheck"; int width = 16, height = 16; >; sampler2D checkSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; }; float4 GenerateCheck(float2 p : POSITION) : COLOR { float4 c1 = { 1.0, 0.0, 0.0, 1.0 }; float4 c2 = { 1.0, 1.0, 0.0, 1.0 }; float2 s = step(p, 0.5); float check = (s.x || s.y) && !(s.x && s.y); // no XOR in HLSL! return lerp(c1, c2, check); } struct Ray { float3 o; // origin float3 d; // direction }; struct Sphere { float3 centre; float rad2; // radius^2 float4 color; float Kd, Ks, Kr; }; // Object database stored in constants #define SQR(N) (N*N) #define NOBJECTS 3 static Sphere object[NOBJECTS] = { { 0.0, 0.0, 0.0, SQR(1.0), 0.0, 0.5, 1.0, 1.0, 1.0, 1.0, 0.5, }, { 1.5, -0.5, 0.0, SQR(0.5), 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.5, }, { 0.0, -101.0, 0.0, SQR(100.0), // 0.0, 0.0, 1.0, 1.0 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, } }; const float eps = 0.001; // error epsilon float SphereIntersect(Sphere s, Ray ray, out bool hit) { float3 v = s.centre - ray.o; float b = dot(v, ray.d); float disc = (b*b) - dot(v, v) + s.rad2; hit = true; // note - early returns not supported by HLSL compiler currently: // if (disc<=0) return -1.0; // ray misses if (disc<=0) hit = false;; disc = sqrt(disc); float t2 = b + disc; // if (t2<=eps) return -1.0; // behind ray origin if (t2<=eps) hit = false; // behind ray origin float t1 = b - disc; if ((t1>eps) && (t1 0.0); return diff*diffuseColor + spec*specularColor; } float4 Shade(float3 i, float3 n, float3 v, int hitobj) { float3 l = normalize(lightPosition - i); // check if shadowed Ray shadowray; shadowray.o = i; shadowray.d = l; bool shadowed = AnyHit(shadowray); // lighting float4 diff = object[hitobj].color * object[hitobj].Kd; if (hitobj==2) { // diff *= tex2D(checkSampler, i.xz); // floor texture // use tex2Dlod to work around D3D restriction that doesn't allow tex2D inside IF/ENDIF: diff *= tex2Dlod(checkSampler, float4(i.xz, 0.0, 0.0)); // floor texture } float4 spec = lightColor * object[hitobj].Ks; float shadowFactor = 0.25 + 0.75*!shadowed; return Phong(n, l, v, shininess, diff, spec) * shadowFactor; } // Vertex shader struct Vertex { float4 pos : POSITION; float4 texcoord : TEXCOORD0; }; Vertex RayTraceVS(Vertex v) { return v; } void animate_scene(float time) { object[1].centre.x = sin(time)*1.5; object[1].centre.z = cos(time)*1.5; } // Pixel shader float4 RayTracePS(Vertex IN) : COLOR { animate_scene(time); // calculate eye ray float3 d; d.xy = ((IN.texcoord*2.0)-1.0) * viewport; d.y = -d.y; // flip y axis d.z = foclen; // transform by view matrix Ray eyeray; eyeray.o = mul(float4(0, 0, 0, 1), view); eyeray.d = mul(d, (float3x3) view); eyeray.d = normalize(eyeray.d); // find nearest hit int hitobj; bool hit; float3 i = NearestHit(eyeray, hitobj, hit); float4 c = backgroundColor; if (hit) { // shade surface float3 n = SphereNormal(object[hitobj], i); c = Shade(i, n, eyeray.d, hitobj); #if 1 // shoot reflection ray float3 r = reflect(eyeray.d, n); Ray reflray; reflray.o = i; reflray.d = r; int hitobj2; i = NearestHit(reflray, hitobj2, hit); if (hit) { n = SphereNormal(object[hitobj2], i); c += Shade(i, n, reflray.d, hitobj2) * object[hitobj].Kr; } else { c += backgroundColor; } #endif } return c; } technique PS30 < string Script = "ScriptSignature=color;" "ScriptExternal=;" "Pass=p0;"; > { pass p0 < string Script = "RenderColorTarget=;" "RenderDepthStencilTarget=;" "Clear=Color;" "Clear=Depth;" "Draw=Buffer;"; > { VertexShader = compile vs_3_0 RayTraceVS(); PixelShader = compile ps_3_0 RayTracePS(); } }