Is this supposed to happen, or is curving the normals allowed and im just screwing something up...
Posted 04 January 2009 - 07:44 AM
Posted 04 January 2009 - 07:57 AM
Posted 04 January 2009 - 08:02 AM
cbuffer cb
{
matrix wvp;
float3 ldir;
float3 eye;
};
Texture2D normal;
Texture2D displace;
SamplerState sstate
{
Filter=ANISOTROPIC;
AddressU = Clamp;
AddressV = Clamp;
};
struct VS_INPUT
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float3 tangent : TANGENT;
uint VertID : SV_VertexID; //verTex ID, used for consistent tetrahedron generation
};
struct GS_INPUT
{
float4 Pos : POSITION; //Position
float3 vPos : POSVIEW; //view pos
float3 Norm : NORMAL; //Normal
float3 Tex : TEXCOORD0; //Texture coordinate
float3 Tangent : TANGENT; //Normalized Tangent vector
uint VertID : VertID; //verTex ID, used for consistent tetrahedron generation
};
struct PS_INPUT
{
float4 Pos : SV_Position;
float4 planeDist : TEXCOORD0;
float3 vPos : TEXCOORD1;
float3 Norm : TEXCOORD2; // Normal of the first vert
float3 TanT : TEXCOORD3; // Tangent of the first vert
float3 Tex : TEXCOORD4; // Texture Coordinate of the first vert
float3 pos0 : TEXCOORD5; // Position of the first vert
float4 GtxNx : TEXCOORD6; // Gradient of the tetrahedron for X texcoord
float4 GtyNx : TEXCOORD7; // Gradient of the tetrahedron for Y texcoord
float4 GtzNx : TEXCOORD8; // Gradient of the tetrahedron for Z texcoord
float4 GTxNy : TEXCOORD9; // Gradient of the tetrahedron for X Tangent
float4 GTyNy : TEXCOORD10; // Gradient of the tetrahedron for Y Tangent
float4 GTzNy : TEXCOORD11; // Gradient of the tetrahedron for Z Tangent
float3 GNz : TEXCOORD12; // Gradient of the tetrahedron for X Normal
};
GS_INPUT vs(VS_INPUT input)
{
GS_INPUT output = (GS_INPUT)0;
output.Pos.xyz = input.pos;
output.Pos.w=1;
output.vPos=input.pos;
output.Tex.xy = input.uv.xy;
output.Tex.z=0.0f;
output.Norm = input.normal;
output.Tangent = input.tangent;
output.VertID = input.VertID;
return output;
}
float RayDistToPlane( float3 vPoint, float3 vDir, float3 A, float3 planeNorm )
{
float Nom = dot( planeNorm, float3(A - vPoint) );
float DeNom = dot( planeNorm, vDir );
return Nom/DeNom;
}
void CalcGradients( inout PS_INPUT V0, inout PS_INPUT V1, inout PS_INPUT V2, inout PS_INPUT V3, float3 N0, float3 N1, float3 N2, float3 N3 )
{
float dotN0 = dot(N0, V0.vPos - V3.vPos);
float dotN1 = dot(N1, V1.vPos - V2.vPos);
float dotN2 = dot(N2, V2.vPos - V1.vPos);
float dotN3 = dot(N3, V3.vPos - V0.vPos);
//Tex
float3 Gtx = ( V0.Tex.x / dotN0 )*N0;
Gtx += ( V1.Tex.x / dotN1 )*N1;
Gtx += ( V2.Tex.x / dotN2 )*N2;
Gtx += ( V3.Tex.x / dotN3 )*N3;
float3 Gty = ( V0.Tex.y / dotN0 )*N0;
Gty += ( V1.Tex.y / dotN1 )*N1;
Gty += ( V2.Tex.y / dotN2 )*N2;
Gty += ( V3.Tex.y / dotN3 )*N3;
float3 Gtz = ( V0.Tex.z / dotN0 )*N0;
Gtz += ( V1.Tex.z / dotN1 )*N1;
Gtz += ( V2.Tex.z / dotN2 )*N2;
Gtz += ( V3.Tex.z / dotN3 )*N3;
//Tangent
float3 GTx = ( V0.TanT.x / dotN0 )*N0;
GTx += ( V1.TanT.x / dotN1 )*N1;
GTx += ( V2.TanT.x / dotN2 )*N2;
GTx += ( V3.TanT.x / dotN3 )*N3;
float3 GTy = ( V0.TanT.y / dotN0 )*N0;
GTy += ( V1.TanT.y / dotN1 )*N1;
GTy += ( V2.TanT.y / dotN2 )*N2;
GTy += ( V3.TanT.y / dotN3 )*N3;
float3 GTz = ( V0.TanT.z / dotN0 )*N0;
GTz += ( V1.TanT.z / dotN1 )*N1;
GTz += ( V2.TanT.z / dotN2 )*N2;
GTz += ( V3.TanT.z / dotN3 )*N3;
//Normal
float3 GNx = ( V0.Norm.x / dotN0 )*N0;
GNx += ( V1.Norm.x / dotN1 )*N1;
GNx += ( V2.Norm.x / dotN2 )*N2;
GNx += ( V3.Norm.x / dotN3 )*N3;
float3 GNy = ( V0.Norm.y / dotN0 )*N0;
GNy += ( V1.Norm.y / dotN1 )*N1;
GNy += ( V2.Norm.y / dotN2 )*N2;
GNy += ( V3.Norm.y / dotN3 )*N3;
float3 GNz = ( V0.Norm.z / dotN0 )*N0;
GNz += ( V1.Norm.z / dotN1 )*N1;
GNz += ( V2.Norm.z / dotN2 )*N2;
GNz += ( V3.Norm.z / dotN3 )*N3;
V0.Norm = V0.Norm;
V0.TanT = V0.TanT;
V0.Tex = V0.Tex;
V0.pos0 = V0.vPos;
V0.GtxNx.xyz = Gtx;
V0.GtyNx.xyz = Gty;
V0.GtzNx.xyz = Gtz;
V0.GTxNy.xyz = GTx;
V0.GTyNy.xyz = GTy;
V0.GTzNy.xyz = GTz;
V0.GtxNx.w = GNx.x;
V0.GtyNx.w = GNx.y;
V0.GtzNx.w = GNx.z;
V0.GTxNy.w = GNy.x;
V0.GTyNy.w = GNy.y;
V0.GTzNy.w = GNy.z;
V0.GNz = GNz;
V1.Norm = V0.Norm;
V1.TanT = V0.TanT;
V1.Tex = V0.Tex;
V1.pos0 = V0.vPos;
V1.GtxNx.xyz = Gtx;
V1.GtyNx.xyz = Gty;
V1.GtzNx.xyz = Gtz;
V1.GTxNy.xyz = GTx;
V1.GTyNy.xyz = GTy;
V1.GTzNy.xyz = GTz;
V1.GtxNx.w = GNx.x;
V1.GtyNx.w = GNx.y;
V1.GtzNx.w = GNx.z;
V1.GTxNy.w = GNy.x;
V1.GTyNy.w = GNy.y;
V1.GTzNy.w = GNy.z;
V1.GNz = GNz;
V2.Norm = V0.Norm;
V2.TanT = V0.TanT;
V2.Tex = V0.Tex;
V2.pos0 = V0.vPos;
V2.GtxNx.xyz = Gtx;
V2.GtyNx.xyz = Gty;
V2.GtzNx.xyz = Gtz;
V2.GTxNy.xyz = GTx;
V2.GTyNy.xyz = GTy;
V2.GTzNy.xyz = GTz;
V2.GtxNx.w = GNx.x;
V2.GtyNx.w = GNx.y;
V2.GtzNx.w = GNx.z;
V2.GTxNy.w = GNy.x;
V2.GTyNy.w = GNy.y;
V2.GTzNy.w = GNy.z;
V2.GNz = GNz;
V3.Norm = V0.Norm;
V3.TanT = V0.TanT;
V3.Tex = V0.Tex;
V3.pos0 = V0.vPos;
V3.GtxNx.xyz = Gtx;
V3.GtyNx.xyz = Gty;
V3.GtzNx.xyz = Gtz;
V3.GTxNy.xyz = GTx;
V3.GTyNy.xyz = GTy;
V3.GTzNy.xyz = GTz;
V3.GtxNx.w = GNx.x;
V3.GtyNx.w = GNx.y;
V3.GtzNx.w = GNx.z;
V3.GTxNy.w = GNy.x;
V3.GTyNy.w = GNy.y;
V3.GTzNy.w = GNy.z;
V3.GNz = GNz;
}
void GSCreateTetra( in GS_INPUT A, in GS_INPUT B, in GS_INPUT C, in GS_INPUT D,
inout TriangleStream<PS_INPUT> DisplaceStream )
{
float3 AView = normalize( A.vPos - eye);
float3 BView = normalize( B.vPos - eye);
float3 CView = normalize( C.vPos - eye);
float3 DView = normalize( D.vPos - eye);
PS_INPUT Aout;
Aout.Pos = A.Pos;
Aout.vPos = A.vPos;
Aout.Norm = A.Norm;
Aout.Tex = A.Tex;
Aout.TanT = A.Tangent;
PS_INPUT Bout;
Bout.Pos = B.Pos;
Bout.vPos = B.vPos;
Bout.Norm = B.Norm;
Bout.Tex = B.Tex;
Bout.TanT = B.Tangent;
PS_INPUT Cout;
Cout.Pos = C.Pos;
Cout.vPos = C.vPos;
Cout.Norm = C.Norm;
Cout.Tex = C.Tex;
Cout.TanT = C.Tangent;
PS_INPUT Dout;
Dout.Pos = D.Pos;
Dout.vPos = D.vPos;
Dout.Norm = D.Norm;
Dout.Tex = D.Tex;
Dout.TanT = D.Tangent;
float3 AB = C.vPos-B.vPos;
float3 AC = D.vPos-B.vPos;
float3 planeNormA = normalize( cross( AC, AB ) );
AB = D.vPos-A.vPos;
AC = C.vPos-A.vPos;
float3 planeNormB = normalize( cross( AC, AB ) );
AB = B.vPos-A.vPos;
AC = D.vPos-A.vPos;
float3 planeNormC = normalize( cross( AC, AB ) );
AB = C.vPos-A.vPos;
AC = B.vPos-A.vPos;
float3 planeNormD = normalize( cross( AC, AB ) );
Aout.planeDist.x = Aout.planeDist.y = Aout.planeDist.z = 0.0f;
Aout.planeDist.w = RayDistToPlane( A.vPos, AView, B.vPos, planeNormA );
Bout.planeDist.x = Bout.planeDist.z = Bout.planeDist.w = 0.0f;
Bout.planeDist.y = RayDistToPlane( B.vPos, BView, A.vPos, planeNormB );
Cout.planeDist.x = Cout.planeDist.y = Cout.planeDist.w = 0.0f;
Cout.planeDist.z = RayDistToPlane( C.vPos, CView, A.vPos, planeNormC );
Dout.planeDist.y = Dout.planeDist.z = Dout.planeDist.w = 0.0f;
Dout.planeDist.x = RayDistToPlane( D.vPos, DView, A.vPos, planeNormD );
CalcGradients( Aout, Bout, Cout, Dout, planeNormA, planeNormB, planeNormC, planeNormD );
DisplaceStream.Append( Cout );
DisplaceStream.Append( Bout );
DisplaceStream.Append( Aout );
DisplaceStream.Append( Dout );
DisplaceStream.Append( Cout );
DisplaceStream.Append( Bout );
DisplaceStream.RestartStrip();
}
[maxvertexcount(18)]
void gs(triangle GS_INPUT In[3], inout TriangleStream<PS_INPUT> DisplaceStream)
{
//Don't extrude anything that's facing too far away from us
//Just saves geometry generation
float3 AB = In[1].Pos - In[0].Pos;
float3 AC = In[2].Pos - In[0].Pos;
float3 triNorm = cross( AB, AC );
float lenTriNorm = length( triNorm );
triNorm /= lenTriNorm;
//Extrude along the Normals
GS_INPUT v[6];
[unroll] for( int i=0; i<3; i++ )
{
float4 PosNew = In[i].Pos;
float4 PosExt = PosNew + float4(In[i].Norm* /*this is max displacement*/ 0.5f ,0);
v[i].vPos = PosNew.xyz;
v[i+3].vPos = PosExt.xyz;
v[i].Pos = mul( PosNew, wvp);
v[i+3].Pos = mul( PosExt, wvp);
v[i].Tex = float3(In[i].Tex.xy,0);
v[i+3].Tex = float3(In[i].Tex.xy,1);
v[i].Norm = In[i].Norm;
v[i+3].Norm = In[i].Norm;
v[i].Tangent = In[i].Tangent;
v[i+3].Tangent = In[i].Tangent;
}
// Make sure that our prism hasn't "flipped" on itself after the extrusion
AB = v[4].vPos - v[3].vPos;
AC = v[5].vPos - v[3].vPos;
float3 topNorm = cross( AB, AC );
float lenTop = length( topNorm );
topNorm /= lenTop;
if(
lenTriNorm < 0.005f || //avoid tiny triangles
dot( topNorm, triNorm ) < 0.95f || //make sure the top of our prism hasn't flipped
abs((lenTop-lenTriNorm)/lenTriNorm) > 10.0f//11.0f //make sure we don't balloon out too much
)
{
[unroll] for( int i=0; i<3; i++ )
{
float4 PosNew = In[i].Pos;
float4 PosExt = PosNew + float4(In[i].Norm* /*g_MinDisplacement*/ -0.5f,0);
v[i].vPos = PosNew.xyz;
v[i+3].vPos = PosExt.xyz;
v[i].Pos = mul( PosNew, wvp);
v[i+3].Pos = mul( PosExt, wvp);
}
}
int index[6] = {0,1,2,3,4,5};
// Create 3 tetrahedra
GSCreateTetra( v[index[4]], v[index[5]], v[index[0]], v[index[3]], DisplaceStream );
GSCreateTetra( v[index[5]], v[index[0]], v[index[1]], v[index[4]], DisplaceStream );
GSCreateTetra( v[index[0]], v[index[1]], v[index[2]], v[index[5]], DisplaceStream );
}
#define MAX_DIST 1000000000.0f
#define MAX_STEPS 64
#define MIN_STEPS 4
#define STEP_SIZE (1.0f/4096.0f)
#define OFFSET_MAX 0.1f //maximum we can cover is 1/10th of the entire texture in one march
float4 ps(PS_INPUT input) : SV_Target
{
float4 modDist = float4(0,0,0,0);
modDist.x = input.planeDist.x > 0 ? input.planeDist.x : MAX_DIST;
modDist.y = input.planeDist.y > 0 ? input.planeDist.y : MAX_DIST;
modDist.z = input.planeDist.z > 0 ? input.planeDist.z : MAX_DIST;
modDist.w = input.planeDist.w > 0 ? input.planeDist.w : MAX_DIST;
// find distance to the rear of the tetrahedron
float fDist = min( modDist.x, modDist.y );
fDist = min( fDist, modDist.z );
fDist = min( fDist, modDist.w );
// find the texture coords of the entrance point
float3 texEnter;
float3 relPos = input.vPos-input.pos0;
texEnter.x = dot( input.GtxNx.xyz,relPos ) + input.Tex.x;
texEnter.y = dot( input.GtyNx.xyz,relPos ) + input.Tex.y;
texEnter.z = dot( input.GtzNx.xyz,relPos ) + input.Tex.z;
// find the exit position
float3 viewExitDir = normalize( input.vPos - eye)*fDist;
float3 viewExit = input.vPos + viewExitDir;
// find the texture coords of the exit point
float3 texExit;
relPos = viewExit-input.pos0;
texExit.x = dot( input.GtxNx.xyz,relPos ) + input.Tex.x;
texExit.y = dot( input.GtyNx.xyz,relPos ) + input.Tex.y;
texExit.z = dot( input.GtzNx.xyz,relPos ) + input.Tex.z;
// March along the Texture space view ray until we either hit something
// or we exit the tetrahedral prism
float3 tanGrad = texExit - texEnter;
float fTanDist = length( float3(tanGrad.xy,0) ); //length in 2d texture space
if( fTanDist > OFFSET_MAX )
discard;
int iSteps = min( ceil( fTanDist / STEP_SIZE ), MAX_STEPS-MIN_STEPS ) + MIN_STEPS;
tanGrad /= iSteps-1.0f;
float3 TexCoord = float3(0,0,0);
bool bFound = false;
float height = 0;
int i = 0;
for( i=0; (i<iSteps && !bFound); i++ )
{
TexCoord = texEnter + i*tanGrad;
height = displace.SampleLevel(sstate, float2(TexCoord.xy), 0 );
height = max( height, -0.5f /*min displacement*/);
if( TexCoord.z <= height )
{
bFound = true;
}
}
if( !bFound )
discard;
// lookup the normal from the normal map
float3 texNormal = normal.Sample(sstate, TexCoord.xy );
texNormal *= 2.0;
texNormal -= float3(1,1,1);
float3 foundPos = input.vPos + viewExitDir*((float)i/(float)iSteps);
relPos = foundPos - input.pos0;
float3 nTanT;
nTanT.x = dot( input.GTxNy.xyz,relPos ) + input.TanT.x;
nTanT.y = dot( input.GTyNy.xyz,relPos ) + input.TanT.y;
nTanT.z = dot( input.GTzNy.xyz,relPos ) + input.TanT.z;
float3 nNormT;
float3 GNx = float3( input.GtxNx.w, input.GtyNx.w, input.GtzNx.w );
float3 GNy = float3( input.GTxNy.w, input.GTyNy.w, input.GTzNy.w );
nNormT.x = dot( GNx,relPos ) + input.Norm.x;
nNormT.y = dot( GNy,relPos ) + input.Norm.y;
nNormT.z = dot( input.GNz,relPos ) + input.Norm.z;
//float3 nBiNormT = normalize( cross( nNormT, nTanT ) );
//float3x3 BTNMatrix = float3x3( nBiNormT, nTanT, nNormT );
//texNormal = normalize( mul( texNormal, BTNMatrix ) ); //world space bump
// Move the light orientation into Texture space
float3 lightDir = ldir;
float3 viewDir = normalize( -viewExitDir );
// dot with Texture space light vector
float lightAmt = saturate( dot( lightDir, texNormal ) );
float4 lightColor = float4(1,1,1,1);
// Get the Diffuse and Specular Textures
float4 diffuse = float4(1,1,1,1);
float specular = diffuse.a;
// Calculate specular power
float3 halfAngle = normalize( viewDir + lightDir );
float4 spec = pow( saturate(dot( halfAngle, texNormal )), 64 );
float4 col=lightColor*diffuse*lightAmt + spec*specular;
col.a=1.0f;
// Return combined lighting
return col;
}
technique10 vdm
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, vs()));
SetGeometryShader(CompileShader(gs_4_0, gs()));
SetPixelShader(CompileShader(ps_4_0, ps()));
}
}
Posted 04 January 2009 - 08:48 AM
Posted 04 January 2009 - 11:14 AM
0 members, 1 guests, 0 anonymous users