Sign in to follow this  
bengaltgrs

Projective textures different in PS 2.0 than 1.1?

Recommended Posts

I have written a shader that works fine in pixel shader version 1.1, but completely changes in pixel shader version 2.0. What I am doing is projecting the texture from the camera's view as to act as a sort of flashlight. When I switch to PS 2.0 however, the projected texture seems to always be in the top left corner of the screen, and gets larger as I get closer to what it is being projected upon. I was curious as to why it might be doing this. Here is the code for the shader:
float4x4 WorldViewProj; //World * View * Projection
float4x4 World;         //World
float4x4 TexTransform;  //Texture transformation matrix
float3 EyePos;          //World position of the camera
float Ambient = 0.0f;   //Amount of ambient light
float LightFalloff;

texture LightTex;
texture ColorTex;

//Must be clamped so the light texture shows up only once
sampler LightTexSampler = sampler_state
{
    Texture = <LightTex>;
    MinFilter = LINEAR;  
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU  = Clamp;
    AddressV  = Clamp;
};

sampler ColorTexSampler = sampler_state
{
    Texture = <ColorTex>;
    MinFilter = LINEAR;  
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU  = Wrap;
    AddressV  = Wrap;
};

////////////////////////////////////////////////////////////
// Structures
////////////////////////////////////////////////////////////
struct MainA2V{
    float4 Position : POSITION;
    float2 TexCoord0 : TEXCOORD0;
};

struct MainV2P{
    float4 Position  : POSITION;
    float2 TexCoord0 : TEXCOORD0;
    float4 TexCoord1 : TEXCOORD1;
    float  Attn      : TEXCOORD2;
};

////////////////////////////////////////////////////////////
// Vertex Shaders
////////////////////////////////////////////////////////////
void MainVS(in MainA2V IN, out MainV2P OUT)
{
    //Copy color texture coordinates through
    OUT.TexCoord0 = IN.TexCoord0;
    
    //First two are the projected texture coordinates
    OUT.TexCoord1 = mul(IN.Position, TexTransform);
    
    //Position to light vector
    float3 LightVec = mul(IN.Position.xyz, (float3x3)World) - EyePos;
    
    //Distance from position to light
    float Dist = dot(LightVec, LightVec);
    
    //Compute attenuation
    OUT.Attn = (LightFalloff * LightFalloff)/Dist;
    
    //Transform model-space vertex position to screen space:
    OUT.Position = mul(IN.Position, WorldViewProj);
}

////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////
float4 MainPS(in MainV2P IN) : COLOR 
{
    //Read in values for shadow, light texture and color texture
    float4 Color    = tex2D(ColorTexSampler, IN.TexCoord0);
    float4 Light    = tex2D(LightTexSampler, IN.TexCoord1);
    
    //Compute lighting amount
    float4 I = (Light * IN.Attn) + Ambient;
    
    //Color of texture * lighting amount
    return I * Color;
}

////////////////////////////////////////////////////////////
// Techniques
////////////////////////////////////////////////////////////
technique ProjectiveTexture
{
    pass P0
    {
        VertexShader = compile vs_1_1 MainVS();
        PixelShader = compile ps_1_1 MainPS();
    
        TextureTransformFlags[0] = Projected;
        TextureTransformFlags[1] = Projected;
    }
}

Thanks for any help in advance, -Chris

Share this post


Link to post
Share on other sites
I could be wrong, but im not sure that you are doing that right at all. You shouldn't really be passing in the texture coordinates for the projected texture, you should be calculating them in the vertex shader.

Here is my shader:

float4x4 matWorld;
float4x4 matCameraWVP;
float4x4 matLightWVP;

texture texLightTexture;

sampler sampLightTextureSampler = sampler_state
{
texture = ( texLightTexture );
AddressU = CLAMP;
AddressV = CLAMP;
};

struct VS_INPUT
{
float4 position : POSITION;
float3 normal : NORMAL;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float3 normal : TEXCOORD0;
float2 texcoord : TEXCOORD1;
};

float2 ClipToScreen( float4 clipPos )
{
float2 homog = clipPos.xy / clipPos.w;

homog.xy *= 0.5f;
homog.xy += 0.5f;
homog.y = 1-homog.y;

return homog;
}


VS_OUTPUT vs_main( VS_INPUT input )
{
VS_OUTPUT output = ( VS_OUTPUT ) 0;

output.position = mul( input.position, matCameraWVP );
output.normal = mul( input.normal, matWorld);
output.texcoord = ClipToScreen( mul( input.position, matLightWVP ) );

return output;
}

float4 ps_main( VS_OUTPUT input ) : COLOR
{
return tex2D( sampLightTextureSampler, input.texcoord );
}

technique ProjectedTexture
{
pass P0
{
VertexShader = compile vs_2_0 vs_main();
PixelShader = compile ps_2_0 ps_main();
}
}


Hope that helps,

Dave

Share this post


Link to post
Share on other sites
I have not tried the code you have supplied there yet, but most of the projective texture samples I have looked at calculate the texture matrix in the app code, then send it to the shader. I assume this method would be quite a bit faster than having to calculate the texture matrix for every vertex. This may not be the case, that is just how it seems to me, is that incorrect?

-Chris

Share this post


Link to post
Share on other sites
Shader 1.1 didn't have instructions for projective texture lookup, and relied on the fixed pipe flag being set. nVidia drivers also try to guess, though I'm not sure what the guess is based on. I know they look at your microcode, but I'm not sure what they're looking for.

Anyway, In shader 2.0, use tex2Dproj. I haven't tried projection in anything other than 1.1, but as far as I know, this is the only trick to it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this