Sign in to follow this  

Lights and hardware vertex processing

This topic is 3586 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi ! When I enable hardware vertex processing and use my own vertex shader, lights are no longer applied (models are no more self shadowed). Is there something I missed in the API ? Or am I obliged to make my own pixel shader, taking care of light calculations by myself ? What would be the use of D3DLIGHT9 then ? (I really miss a good tutorial on this subject. All I find is either too complex or too abstract) Thanks in advance.

Share this post


Link to post
Share on other sites
enabling vertex processing means that you will have to replace the full working of the transform and lighting pipeline. That means you have to several things in shaders, including transformation, lighting and shadowing.

what i don't understand is that models are no more self shadowed? I haven't been following the t&l anymore lately, but in my memory self shadowing wasn't even supported in the t&l hardware.

in the documentation of DX9/10 (latest sdk), there's an article about replacing the existing T&L, but it requires a 'newer' video card with good shader support i think.

Share this post


Link to post
Share on other sites
Well, by self shadowing, I meant normal darkening. In the real world, it's a kind of shadow :)

Anyway...
Sadly, you confirmed my thoughts. Do you know a place where I could find pre-build shaders that I could work on ?
If none, then I'd have just a question :
I'd have to pass all the lights in the pixel shader. As far as I know, you can't transfer a C++ struct directly into the shader program. So the solution would be to create several arrays in the pixel shader :

    // General
int xLightType[MAX_LIGHT_NBR];
float3 xLightColor[MAX_LIGHT_NBR];
// Spot and point lights
float3 xLightPos[MAX_LIGHT_NBR];
float3 xLightAttenFactors[MAX_LIGHT_NBR];
float xLightRange[MAX_LIGHT_NBR];
// Spot and directionnal lights
float3 xLightDirection[MAX_LIGHT_NBR];
// Spot lights
float2 xLightCones[MAX_LIGHT_NBR];
float xLightFallof[MAX_LIGHT_NBR];



... and then update them in the main program when needed ?
I could also calculate everything in the main program and change the color of my vertice.
What'd be best ?

Share this post


Link to post
Share on other sites
Wow, awesome posts guys and well done on helping Kaloux,
Kaloux, at the very least, your vertex shader should transform the vertices to give them a position in world space. You can however then additionally specify a lighting model (light your vertices).

I hope this helps.
Take care.

Share this post


Link to post
Share on other sites
Ok thanks for these infos, I didn't thought I could do it in the vertex shader !

I've tried using the arrays I described in my previous post and I just can't get it to work properly...
In fact, I use a "for" loop to iterate through my arrays and calculate lighting, but weird things are happening.

Here is my code, I'll explain what's wrong just after :

// Vertex shader input structure
struct VS_INPUT
{
float4 Position : POSITION;
float2 Texture : TEXCOORD0;
float3 Normal : NORMAL;
};

// Vertex shader output structure
struct VS_OUTPUT
{
float4 Position : POSITION;
float2 Texture : TEXCOORD0;
float3 Normal : TEXCOORD1;
float4 Color : COLOR0;
};

// Global variables
float4x4 mWorldViewProj;

/// LIGHTS
// Light types
int LIGHT_POINT = 1;
int LIGHT_SPOT = 2;
int LIGHT_DIRECTIONAL = 3;
// General
int mLightNbr;
int mLightType[128];
float4 mLightColor[128];
// Spot and point lights
float4 mLightPos[128];
float4 mLightAttenFactors[128];
float mLightRange[128];
// Spot and directionnal lights
float4 mLightDirection[128];
// Spot lights
float mLightConeIn[128];
float mLightConeOut[128];
float mLightFallof[128];

float4 Light_PointDiffuse(float3 VertPos, float3 VertNorm, float3 LightPos,
float4 LightColor, float4 LightAttenuation, float LightRange)
{
float3 LightDir = LightPos - VertPos;
float Dist = length(LightDir);
if (Dist < LightRange)
{
float DistAttn = saturate(1 / (LightAttenuation.x +
LightAttenuation.y * Dist +
LightAttenuation.z * Dist * Dist));

float AngleAttn = saturate(dot(VertNorm, LightDir));

return LightColor * DistAttn * AngleAttn;
}
else
return float4(1, 1, 1, 1);
}

// Name: Simple Vertex Shader
// Type: Vertex shader
// Desc: Vertex transformation and texture coord pass-through
//
VS_OUTPUT main( in VS_INPUT Input )
{
VS_OUTPUT Output; //create an output vertex

float3 Position3D = Input.Position;
Output.Position = mul(Input.Position, mWorldViewProj); //apply vertex transformation
Output.Texture = Input.Texture; //copy original texcoords.
Output.Normal = Input.Normal;
Output.Color[0] = 1.0f;
Output.Color[1] = 1.0f;
Output.Color[2] = 1.0f;
Output.Color[3] = 1.0f;

if (mLightNbr != 0)
{
for (int i = 0; i < mLightNbr; i++)
{
if (mLightType[i] == 1) // Point light
{
Output.Color *= Light_PointDiffuse(Position3D, Input.Normal, mLightPos[i], mLightColor[i], mLightAttenFactors[i], mLightRange[i]);
}
}
}

return Output; //return output vertex
}


Maybe 128 is a bit too much :)
Anyway, if I use this shader, everything is plain black. However, if I replace :
Output.Color *= Light_PointDiffuse(Position3D, Input.Normal, mLightPos[i], mLightColor[i], mLightAttenFactors[i], mLightRange[i]);

...by :
Output.Color *= Light_PointDiffuse(Position3D, Input.Normal, mLightPos[0], mLightColor[0], mLightAttenFactors[0], mLightRange[0]);

... it works !

I made some tests and checked that the loop is executed only once in both cases (I have only one light in my scene).
Am I doing something wrong with the loop ?

Something else that annoys me is that the following code doesn't work as expected :
if (mLightType[i] == LIGHT_POINT)
...

That's why I replaced "LIGHT_POINT" by "1" in my code, and it worked. Strange...

Share this post


Link to post
Share on other sites

Hi,

Actually you can use structs in HLSL (instead of those numerous arrays), and as far as I remember, they even map quite well to C++ structures. Need to verify that.

Good luck!

Share this post


Link to post
Share on other sites
Yes I can use structs, but how would I fill them from C++ ?
AFAIK, one can only send floats, integers, booleans, matrices, vectors and an array of any of these, but no struct.
Or do you use ID3DXConstantTable::SetValue() ?

Anyway, here is my final vertex shader :
// Vertex shader input structure
struct VS_INPUT
{
float4 Position : POSITION;
float2 Texture : TEXCOORD0;
float3 Normal : NORMAL;
};

// Vertex shader output structure
struct VS_OUTPUT
{
float4 Position : POSITION;
float2 Texture : TEXCOORD0;
float4 Color : COLOR0;
};

// Global variables
float4x4 mWorldViewProj;
float4x4 mWorld;
float4x4 mRot;

/// LIGHTS
// Light types
// LIGHT_NONE 0
// LIGHT_POINT 1
// LIGHT_SPOT 2
// LIGHT_DIRECTIONAL 3
// Data
float4 mLightAmbient;
int mLightType[4];
float4 mLightColor[4];
float4 mLightPos[4];
float4 mLightAttenFactors[4];

float4 Light_PointDiffuse(float3 VertPos, float3 VertNorm, float3 LightPos,
float4 LightColor, float4 LightAttenuation)
{
float3 LightDir = LightPos - VertPos;
float Dist = length(LightDir);

float DistAttn = saturate(1 / (LightAttenuation.x +
LightAttenuation.y * Dist +
LightAttenuation.z * Dist * Dist));

float AngleAttn = saturate(dot(VertNorm, LightDir));

return LightColor * DistAttn * AngleAttn;
}

VS_OUTPUT main( in VS_INPUT Input )
{
VS_OUTPUT Output; //create an output vertex

float3 Position3D = mul(Input.Position, mWorld);
Input.Normal = mul(Input.Normal, mRot);
Output.Position = mul(Input.Position, mWorldViewProj);
Output.Texture = Input.Texture;
Output.Color = mLightAmbient;

for (int i = 0; i < 4; i++)
{
if (mLightType[i] == 1) // Point light
{
Output.Color += Light_PointDiffuse(Position3D, Input.Normal, mLightPos[i], mLightColor[i], mLightAttenFactors[i]);
}
}

saturate(Output.Color);

return Output;
}






Notes :
# Range check is done in the main program.
# Only 4 lights are sent to the vertex shader. I took the 4 nearest ones.
# Only supporting point lights.


Oh, and just a few questions remaining :
What are the limitations regarding the constant number ? (Edit : 256 with vs_2_0)
Does a floa4 takes 4 constant slots ? Same question for an array ?

The thing is that I'm going to add vertex blending in this shader...

[Edited by - Kaloux on February 16, 2008 7:42:30 AM]

Share this post


Link to post
Share on other sites

This topic is 3586 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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