Well I may have found a bug (that or there is something wrong with my normal map shader). The effect seems to work fine in the above download (try it and see), however I tryed to apply the effect to my custom terrain chunks (created via memblocks) and the thing freaked out. The texture did not display at all, the lighting was very off, ect...
Ive narrowed the problem down to the vertex Input TANGENT value. While it works fine with most other objects (cubes, spheres, ect) it produces strange results with a custom made quad (a simple two poly mesh created via memblocks). I included the code I use to make the memblock mesh so you can look at it, but I dont think there is anything wrong with it.
Heres the dbpro source (commented where the problem is)...
`***********************
`NORMAL MAP
`
`Written by Jeff Wieland
`01.18.06
`
`Special Thanks
` Pieter Germishuys
` Ninja Matt
`***********************
sync on: sync rate 0
autocam off: position camera 500,500,-250: set camera range 10000,1
global looptime as float
dim ticktock(499)
global ticktock as integer
global ttpos as integer
global ttavg as float
load image "CrateBase.tga",1
load image "CrateNormal.tga",2
`-----------------------------------------------------
`***
`Heres the problem, use a cube (or any other model) and things work fine
`however, use this simple make mesh from memblock code and the texture wont display!
`I simplified my quad generation code, I cant see anything wrong with it!
`If you look into the hlsl shader, youll see the problem seems to be
`related to the input vertex TANGENT
`****
`---
`works fine
`---
`make object cube 1,100: position object 1,500,500,500
`---
`no texture is displayed
`---
makequad()
`-----------------------------------------------------
texture object 1,0,1: texture object 1,1,2
`and why is this matrix (or any object) being drawn over the crate?
`make matrix 1,1000,1000,10,10
load effect "normalmap.fx",1,0
set object effect 1,1
`---
`main loop
`---
`loopstart
loopstart = timer(): looptime = 0.001
do
set cursor 0,0
print "FPS = ";screen fps()
if mouseclick() = 1 then move camera 200*looptime
if mouseclick() = 2 then move camera -200*looptime
rotate camera wrapvalue(camera angle x()-mousemovey()), wrapvalue(camera angle y()+mousemovex()),0
null = make vector4(1)
set vector4 1,camera position x(),camera position y(),camera position z(),0.0
set effect constant vector 1, "light0pos", 1
null = delete vector4(1)
`--------
`LOOPTIME
`--------
loopend = timer()
a# = loopend-loopstart: if a# <= 0.0: repeat: loopend = timer(): a# = loopend-loopstart: until a# > 0.0: endif
looptime = a#/1000.0: loopstart = loopend
sync
loop
`*****************************************************************************
`FUNCTIONS
`*****************************************************************************
function makequad()
lod = 0
posinc = 36
scale# = 1.0 / (2^lod)
step# = 1000.0 / (2^lod)
offset# = 0.0
uvoff# = 0.0
uvstep# = 1.0
local color as dword
color = rgb(255,255,255)
obj = 1
mem = 1
polys = ( ((2^lod)*(2^lod)) * 2 )
size = (polys*36*3) + 12
make memblock mem,size
write memblock dword mem,0,338
write memblock dword mem,4,36
write memblock dword mem,8,polys*3
pos=12
for a = 0 to (2^lod)-1
for b = 0 to (2^lod)-1
y# = 0.0
x# = 0.0+(a): z# = 0.0+(b): writevertexdata(mem,pos,(x#*step#)+offset#,y#,(z#*step#)+offset#,0.000,1.000,0.000,color,(uvoff#+(a*uvstep#)), (uvoff#+(b*uvstep#))): inc pos,posinc
x# = 0.0+(a): z# = 1.0+(b): writevertexdata(mem,pos,(x#*step#)+offset#,y#,(z#*step#)+offset#,0.000,1.000,0.000,color,(uvoff#+(a*uvstep#)), (uvoff#+uvstep#+(b*uvstep#))): inc pos,posinc
x# = 1.0+(a): z# = 1.0+(b): writevertexdata(mem,pos,(x#*step#)+offset#,y#,(z#*step#)+offset#,0.000,1.000,0.000,color,(uvoff#+uvstep#+(a*uvstep#)), (uvoff#+uvstep#+(b*uvstep#))): inc pos,posinc
x# = 1.0+(a): z# = 1.0+(b): writevertexdata(mem,pos,(x#*step#)+offset#,y#,(z#*step#)+offset#,0.000,1.000,0.000,color,(uvoff#+uvstep#+(a*uvstep#)), (uvoff#+uvstep#+(b*uvstep#))): inc pos,posinc
x# = 1.0+(a): z# = 0.0+(b): writevertexdata(mem,pos,(x#*step#)+offset#,y#,(z#*step#)+offset#,0.000,1.000,0.000,color,(uvoff#+uvstep#+(a*uvstep#)), (uvoff#+(b*uvstep#))): inc pos,posinc
x# = 0.0+(a): z# = 0.0+(b): writevertexdata(mem,pos,(x#*step#)+offset#,y#,(z#*step#)+offset#,0.000,1.000,0.000,color,(uvoff#+(a*uvstep#)), (uvoff#+(b*uvstep#))): inc pos,posinc
next b
next a
make mesh from memblock obj,mem
make object obj,obj,0
`set object wireframe obj,1
delete memblock mem
delete mesh 1
endfunction
function writevertexdata(mem,pos,X# as float,Y# as float,Z# as float,NX# as float,NY# as float,NZ# as float,color as dword,TU# as float,TV# as float)
write memblock float mem,pos,X#
write memblock float mem,pos+4,Y#
write memblock float mem,pos+8,Z#
write memblock float mem,pos+12,0.0
write memblock float mem,pos+16,1.0
write memblock float mem,pos+20,0.0
write memblock dword mem,pos+24,rgb(255,255,255)
write memblock float mem,pos+28,TU#
write memblock float mem,pos+32,TV#
endfunction
`====
`TICK
`====
`starts the timer
function tick()
ticktock = timer()
endfunction
`====
`TOCK
`====
`ends the timer
function tock()
ticktock(ttpos) = timer() - ticktock
inc ttpos: if ttpos > 499 then ttpos = 0
a# = 0.0
for pos = 0 to 499
a# = a# + ticktock(pos)
next pos
ttavg = a#/500.0
endfunction
And the HLSL source (also commented)...
//////////////////////////////////////////////
// Normal Map Shader
//////////////////////////////////////////////
// Written by - Jeff Wieland
// 01.18.06
//
// Special Thanks
// Pieter Germishuys
// Ninja Matt
//////////////////////////////////////////////
////////////////
// UN-TWEAKS
////////////////
matrix WorldViewProj: WorldViewProjection;
matrix World: World;
/////////////
// TWEAKS
/////////////
float4 light0pos <> = {1.0f, -1.0f, 1.0f, 0.0f};
/////////////////////////
// DATA STRUCTS
/////////////////////////
//application to vertex shader
struct a2v
{
float4 pos: POSITION;
float3 normal: NORMAL;
float2 uv: TEXCOORD0;
float3 tangent: TANGENT;
float3 binormal: BINORMAL;
};
//vertex shader to pixel shader
struct v2p
{
float4 pos: POSITION;
float2 uv: TEXCOORD0;
float3 lightvec: TEXCOORD2;
float att: TEXCOORD3;
};
//pixel shader to frame
struct p2f
{
float4 color: COLOR;
};
///////////////////
// VERTEX SHADER
///////////////////
void VS(in a2v IN, out v2p OUT)
{
//project the vertex onto the screen
OUT.pos = mul(IN.pos,WorldViewProj);
//get the world position of the vertex
float4 posworld = mul(IN.pos, World);
//calc a vector from light to vertex
float3 light = normalize(light0pos - posworld);
//create our Tangent Binormal & Normal matrix
//***
// The problem is right here, use the IN tangent and things go to hell (with the custom quad)
// however use a fake tangent and things work fine (well the txture displays at least...)
//***
float3 tangent = IN.tangent;
//float3 tangent = (0.0, 1.0, 0.0);
float3x3 TBNMatrix = float3x3(tangent, IN.binormal , IN.normal);
//multiply our light by the TBN matrix
OUT.lightvec = mul(TBNMatrix, light);
//calculate the attenuation
OUT.att = 1/( 1 + ( 0.005 * distance(light0pos.xyz, posworld) ) );
OUT.uv = IN.uv;
}
///////////////////
// TEXTURES
///////////////////
texture colormap <string name = ""; >;
sampler colormapsamp = sampler_state
{ texture = (colormap); };
texture normalmap <string name = ""; >;
sampler normalmapsamp = sampler_state
{ texture = (normalmap); };
//////////////////////////
// PIXEL SHADER
//////////////////////////
void PS(in v2p IN, out p2f OUT)
{
//start with the base color
float4 color = tex2D(colormapsamp, IN.uv);
//uncompress a normal map
float3 normal = 2.0f * tex2D(normalmapsamp, IN.uv).rgb - 1.0f;
//normalize the light
float3 light = normalize(IN.lightvec);
//set the output color
float diffuse = saturate(dot(normal, light));
//multiply the attenuation with the color
OUT.color = IN.att * color * diffuse;
}
//////////////////////////
// TECHNIQUE
//////////////////////////
technique T
{
pass p0
{
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_2_0 PS();
}
}
I also put the entire (now buggy) project back together so you can download it and play with it.
Help!
All you need is zeal