/*********************************************************************NVMH3**** File: $Id: //sw/devtools/SDK/9.5/SDK/MEDIA/HLSL/scene_lineDraw.fx#3 $ 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: Combine two methods of edge detection to make one line drawing. ******************************************************************************/ #include float Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "scene"; string ScriptOrder = "standard"; string ScriptOutput = "color"; string Script = "Technique=Technique?NV3X:NV4X:NormsOnly:DepthOnly;"; > = 0.8; // version # float4x4 WorldITXf : WorldInverseTranspose < string UIWidget="None"; >; float4x4 WorldViewProjectionXf : WorldViewProjection < string UIWidget="None"; >; float4x4 WorldViewXf : WorldView < string UIWidget="None"; >; float4x4 WorldXf : World < string UIWidget="None"; >; float4x4 ViewIXf : ViewInverse < string UIWidget="None"; >; /////////////////////////////////////////////////////////// /////////////////////////////////////// Tweakables //////// /////////////////////////////////////////////////////////// float4 ClearColor < string UIWidget = "color"; string UIName = "background"; > = {0,0,0,0.0}; float4 BlackColor < string UIWidget = "none"; string UIName = "background 2"; > = {0,0,0,0.0}; float ClearDepth = 1.0; float NPixels < string UIName = "Edge Pixels Steps"; string UIWidget = "slider"; float UIMin = 1.0f; float UIMax = 5.0f; float UIStep = 0.5f; > = 1.5f; float Threshhold < string UIName = "Edge Threshhold"; string UIWidget = "slider"; float UIMin = 0.001f; float UIMax = 0.1f; float UIStep = 0.001f; > = 0.2; float ThreshholdD < string UIName = "Depth Threshhold"; string UIWidget = "slider"; float UIMin = 0.0001f; float UIMax = 0.1f; float UIStep = 0.0001f; > = 0.2; float Far < string UIName = "Far Depth"; string UIWidget = "slider"; float UIMin = 0.1f; float UIMax = 100.0f; float UIStep = 0.01f; > = 10.2; float Near < string UIName = "Near Depth"; string UIWidget = "slider"; float UIMin = 0.01f; float UIMax = 100.0f; float UIStep = 0.01f; > = 1.2; // static data ////////////////////////////////// static float EdgeT2 = (Threshhold * Threshhold); static float DeepT2 = (ThreshholdD * ThreshholdD); static QUAD_REAL2 TexelCornerOffset = QUAD_REAL2(QuadTexOffset/(QuadScreenSize.x),QuadTexOffset/(QuadScreenSize.y)); /////////////////////////////////////////////////////////// ///////////////////////////// Render-to-Texture Data ////// /////////////////////////////////////////////////////////// DECLARE_QUAD_TEX(NormTexture,NormSampler,"X8R8G8B8") DECLARE_QUAD_TEX(DeepTexture,DeepSampler,"X8R8G8B8") DECLARE_QUAD_DEPTH_BUFFER(DepthBuffer, "D24S8") //////////////////////////// geometric data /////// /* data from application vertex buffer */ struct appdata { float3 Pos : POSITION; float4 UV : TEXCOORD0; float4 Normal : NORMAL; float4 Tangent : TANGENT0; float4 Binormal : BINORMAL0; }; /* data passed from vertex shader to pixel shader */ struct vertexOutput { float4 HPosition : POSITION; float3 WorldNormal : TEXCOORD0; float3 WorldEyeVec : TEXCOORD1; float3 EyePos : TEXCOORD2; // float4 Diff : COLOR0; }; vertexOutput simpleVS(appdata IN) { vertexOutput OUT = (vertexOutput)0; float4 Po = float4(IN.Pos,1.0); OUT.HPosition = mul(Po, WorldViewProjectionXf); float4 Nn = normalize(IN.Normal); OUT.WorldNormal = mul(WorldITXf, Nn).xyz; float4 Pw = mul(WorldXf, Po); OUT.EyePos = mul(Po,WorldViewXf); OUT.WorldEyeVec = normalize(ViewIXf[3].xyz - Pw.xyz); return OUT; } /// geom pixel shaders //// QUAD_REAL4 vecColorN(QUAD_REAL3 V) { QUAD_REAL3 Nc = 0.5 * (normalize(V.xyz) + ((1.0).xxx)); return QUAD_REAL4(Nc,1); } QUAD_REAL4 normPS(vertexOutput IN) : COLOR { return vecColorN(IN.WorldNormal); } QUAD_REAL4 deepPS(vertexOutput IN) : COLOR { QUAD_REAL d = (IN.EyePos.z-Near)/(Far-Near); return QUAD_REAL4(d.xxx,1); } void geomMRT_PS( vertexOutput IN, out QUAD_REAL4 normColor : COLOR0, out QUAD_REAL4 deepColor : COLOR1 ) { normColor = vecColorN(IN.WorldNormal); QUAD_REAL d = (IN.EyePos.z-Near)/(Far-Near); deepColor = QUAD_REAL4(d.xxx,1); } /////// edge detection ////////////// struct EdgeVertexOutput { QUAD_REAL4 Position : POSITION; QUAD_REAL2 UV00 : TEXCOORD0; QUAD_REAL2 UV01 : TEXCOORD1; QUAD_REAL2 UV02 : TEXCOORD2; QUAD_REAL2 UV10 : TEXCOORD3; QUAD_REAL2 UV12 : TEXCOORD4; QUAD_REAL2 UV20 : TEXCOORD5; QUAD_REAL2 UV21 : TEXCOORD6; QUAD_REAL2 UV22 : TEXCOORD7; }; EdgeVertexOutput edgeVS( QUAD_REAL3 Position : POSITION, QUAD_REAL3 TexCoord : TEXCOORD0 ) { EdgeVertexOutput OUT; OUT.Position = QUAD_REAL4(Position, 1); QUAD_REAL2 ctr = QUAD_REAL2(TexCoord.xy+TexelCornerOffset); QUAD_REAL2 ox = QUAD_REAL2(NPixels/QuadScreenSize.x,0.0); QUAD_REAL2 oy = QUAD_REAL2(0.0,NPixels/QuadScreenSize.y); OUT.UV00 = ctr - ox - oy; OUT.UV01 = ctr - oy; OUT.UV02 = ctr + ox - oy; OUT.UV10 = ctr - ox; OUT.UV12 = ctr + ox; OUT.UV20 = ctr - ox + oy; OUT.UV21 = ctr + oy; OUT.UV22 = ctr + ox + oy; return OUT; } ////////////////////////////////////////////////////// ////////////////////////////////// pixel shader ////// ////////////////////////////////////////////////////// // // Edge detect against gray // // Note for THIS conversion, we treat R G and B *equally* -- a better // value for the dot product for a regular color image might be something // perceptual like (.2,.7,.1) -- but in this case we are filtering 3D normals // so (0.333).xxx is good // QUAD_REAL getGray(QUAD_REAL4 c) { return(dot(c.rgb,((0.33333).xxx))); } QUAD_REAL edgeDetectGray(EdgeVertexOutput IN, uniform sampler2D ColorMap, uniform QUAD_REAL T2) { QUAD_REAL4 CC; CC = tex2D(ColorMap,IN.UV00); QUAD_REAL g00 = getGray(CC); CC = tex2D(ColorMap,IN.UV01); QUAD_REAL g01 = getGray(CC); CC = tex2D(ColorMap,IN.UV02); QUAD_REAL g02 = getGray(CC); CC = tex2D(ColorMap,IN.UV10); QUAD_REAL g10 = getGray(CC); CC = tex2D(ColorMap,IN.UV12); QUAD_REAL g12 = getGray(CC); CC = tex2D(ColorMap,IN.UV20); QUAD_REAL g20 = getGray(CC); CC = tex2D(ColorMap,IN.UV21); QUAD_REAL g21 = getGray(CC); CC = tex2D(ColorMap,IN.UV22); QUAD_REAL g22 = getGray(CC); QUAD_REAL sx = 0; sx -= g00; sx -= g01 * 2; sx -= g02; sx += g20; sx += g21 * 2; sx += g22; QUAD_REAL sy = 0; sy -= g00; sy += g02; sy -= g10 * 2; sy += g12 * 2; sy -= g20; sy += g22; QUAD_REAL dist = (sx*sx+sy*sy); QUAD_REAL result = 0; if (dist>T2) { result = 1; } return result; } // // Only the red channel since the image is grayscale already // QUAD_REAL edgeDetectR(EdgeVertexOutput IN, uniform sampler2D ColorMap, uniform QUAD_REAL T2) { QUAD_REAL4 CC; QUAD_REAL g00 = tex2D(ColorMap,IN.UV00).x; QUAD_REAL g01 = tex2D(ColorMap,IN.UV01).x; QUAD_REAL g02 = tex2D(ColorMap,IN.UV02).x; QUAD_REAL g10 = tex2D(ColorMap,IN.UV10).x; QUAD_REAL g12 = tex2D(ColorMap,IN.UV12).x; QUAD_REAL g20 = tex2D(ColorMap,IN.UV20).x; QUAD_REAL g21 = tex2D(ColorMap,IN.UV21).x; QUAD_REAL g22 = tex2D(ColorMap,IN.UV22).x; QUAD_REAL sx = 0; sx -= g00; sx -= g01 * 2; sx -= g02; sx += g20; sx += g21 * 2; sx += g22; QUAD_REAL sy = 0; sy -= g00; sy += g02; sy -= g10 * 2; sy += g12 * 2; sy -= g20; sy += g22; QUAD_REAL dist = (sx*sx+sy*sy); QUAD_REAL result = 0; if (dist>T2) { result = 1; } return result; } /////// QUAD_REAL4 edgeDetect2PS(EdgeVertexOutput IN) : COLOR { QUAD_REAL n = edgeDetectGray(IN,NormSampler,EdgeT2); QUAD_REAL d = edgeDetectR(IN,DeepSampler,DeepT2); QUAD_REAL line = 1 - (n*d); return line.xxxx; } QUAD_REAL4 normEdgePS(EdgeVertexOutput IN) : COLOR { QUAD_REAL d = 1.0 - edgeDetectGray(IN,NormSampler,EdgeT2); return d.xxxx; } QUAD_REAL4 deepEdgePS(EdgeVertexOutput IN) : COLOR { QUAD_REAL d = 1.0 - edgeDetectR(IN,DeepSampler,DeepT2); return d.xxxx; } //////////////////////////////////////////////////////////// /////////////////////////////////////// techniques ///////// //////////////////////////////////////////////////////////// technique NV3X < string Script = // these two could be a single MRT pass "Pass=Norms;" "Pass=Depth;" "Pass=ImageProc;"; > { pass Norms < string Script = "RenderColorTarget0=NormTexture;" "RenderDepthStencilTarget=DepthBuffer;" "ClearSetColor=BlackColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { VertexShader = compile vs_2_0 simpleVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; AlphaBlendEnable = false; PixelShader = compile ps_2_a normPS(); } pass Depth < string Script = "RenderColorTarget0=DeepTexture;" "RenderDepthStencilTarget=DepthBuffer;" "ClearSetColor=BlackColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { VertexShader = compile vs_2_0 simpleVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; AlphaBlendEnable = false; PixelShader = compile ps_2_a deepPS(); } pass ImageProc < string Script = "RenderColorTarget0=;" // re-use "RenderDepthStencilTarget=;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; ZWriteEnable = false; AlphaBlendEnable = false; VertexShader = compile vs_1_1 edgeVS(); PixelShader = compile ps_2_0 edgeDetect2PS(); } } technique NV4X < string Script = "Pass=NormsAndDepth;" "Pass=ImageProc;"; > { pass NormsAndDepth < string Script = "RenderColorTarget0=NormTexture;" "RenderColorTarget1=DeepTexture;" "RenderDepthStencilTarget=DepthBuffer;" "ClearSetColor=BlackColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { VertexShader = compile vs_2_0 simpleVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; AlphaBlendEnable = false; PixelShader = compile ps_2_a geomMRT_PS(); } pass ImageProc < string Script = "RenderColorTarget0=;" "RenderColorTarget1=;" "RenderDepthStencilTarget=;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; ZWriteEnable = false; AlphaBlendEnable = false; VertexShader = compile vs_1_1 edgeVS(); PixelShader = compile ps_2_0 edgeDetect2PS(); } } technique NormsOnly < string Script = "Pass=Norms;" "Pass=ImageProc;"; > { pass Norms < string Script = "RenderColorTarget0=NormTexture;" "RenderDepthStencilTarget=DepthBuffer;" "ClearSetColor=BlackColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { VertexShader = compile vs_2_0 simpleVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; AlphaBlendEnable = false; PixelShader = compile ps_2_a normPS(); } pass ImageProc < string Script = "RenderColorTarget0=;" // re-use "RenderDepthStencilTarget=;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; ZWriteEnable = false; AlphaBlendEnable = false; VertexShader = compile vs_1_1 edgeVS(); PixelShader = compile ps_2_0 normEdgePS(); } } technique DepthOnly < string Script = "Pass=Depth;" "Pass=ImageProc;"; > { pass Depth < string Script = "RenderColorTarget0=DeepTexture;" "RenderDepthStencilTarget=DepthBuffer;" "ClearSetColor=BlackColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { VertexShader = compile vs_2_0 simpleVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; AlphaBlendEnable = false; PixelShader = compile ps_2_a deepPS(); } pass ImageProc < string Script = "RenderColorTarget0=;" // re-use "RenderDepthStencilTarget=;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; ZWriteEnable = false; AlphaBlendEnable = false; VertexShader = compile vs_1_1 edgeVS(); PixelShader = compile ps_2_0 deepEdgePS(); } } ////////////// eof ///