Custom material shader: light color not being set - RESOLVED
by Sean H. · in Torque 3D Professional · 04/30/2011 (4:34 pm) · 32 replies
I'm attempting to use a custom shader which uses the incoming light color as the color of the object. The final color of the shader is simply the color of the light. This shader should work correctly in basic lighting.
vertex shader:
pixel shader:
However, the light color is not being passed through to the shader. Instead, objects are being rendered with a solid black color. The shader seems to be working correctly; I get no compile errors or warnings when using the shader. I'm using this shader in the empty room mission so objects which use this shader *should* be rendered with the color of the sun.
Any ideas why this isn't working? I have to wonder if any of the light information is actually being passed to custom material shaders.
vertex shader:
struct VertData
{
float3 position : POSITION;
};
struct ConnectData
{
float4 hpos : POSITION;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
ConnectData main( VertData IN,
uniform float4x4 modelview : register(C0)
)
{
ConnectData OUT;
OUT.hpos = mul(modelview, float4(IN.position.xyz,1));
return OUT;
}pixel shader:
uniform float4 inLightColor[4];
struct Fragout
{
float4 col : COLOR0;
};
Fragout main()
{
Fragout OUT;
OUT.col.rgb = inLightColor[0].rgb;
OUT.col.a = 1;
return OUT;
}However, the light color is not being passed through to the shader. Instead, objects are being rendered with a solid black color. The shader seems to be working correctly; I get no compile errors or warnings when using the shader. I'm using this shader in the empty room mission so objects which use this shader *should* be rendered with the color of the sun.
Any ideas why this isn't working? I have to wonder if any of the light information is actually being passed to custom material shaders.
#2
if I set it to output red, gideon is rendered as red. the shader works as expected. the value for the light color is what I need and it should be stored in the inLightColor array variable.
also, the light color obviously is a reasonable color since the weapon and ground plane are being rendered properly.
05/01/2011 (8:07 pm)
Nicolas, I can set the output of the shader to any color I want.if I set it to output red, gideon is rendered as red. the shader works as expected. the value for the light color is what I need and it should be stored in the inLightColor array variable.
also, the light color obviously is a reasonable color since the weapon and ground plane are being rendered properly.
#3
Edit: And, instead use the classical vertex program entry point:
in the VS add the include file for the T3D already prepared structs
and use this version of the vertex program entry point:
Finally, pass the color of light through the output struct. Like:
Also uses the same struct on VertexShader that in the PixelShader.
05/01/2011 (8:18 pm)
In the definition of the custommaterial you've added this?forwardLit = true;
Edit: And, instead use the classical vertex program entry point:
ConnectData main( VertData IN,
uniform float4x4 modelview : register(C0)
)in the VS add the include file for the T3D already prepared structs
#include "hlslStructs.h"
and use this version of the vertex program entry point:
ConnectData main( VertexIn_PNTTTB IN, uniform float4x4 modelview, uniform float4 inLightPos[3], uniform float4 inLightColor[4] )
Finally, pass the color of light through the output struct. Like:
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};Also uses the same struct on VertexShader that in the PixelShader.
#4
I've set forwardLit = true on the custom material.
I took your advice and modified the shader a bit. It's still rendering completely black. Here is the new shader code:
vertex shader:
pixel shader:
Again, code compiles and runs with no warnings or errors. And again, it's rendering completely black. Has anyone actually confirmed that light color is being properly set for custom material shaders?
05/01/2011 (10:27 pm)
Alfio - I've set forwardLit = true on the custom material.
I took your advice and modified the shader a bit. It's still rendering completely black. Here is the new shader code:
vertex shader:
#include "shaders/common/hlslstructs.h"
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
ConnectData main( VertexIn_PNTTTB IN,
uniform float4x4 modelview,
uniform float4 inLightPos[3],
uniform float4 inLightColor[4]
)
{
ConnectData OUT;
OUT.inColor = inLightColor[0].rgba;
OUT.hpos = mul(modelview, float4(IN.pos.xyz,1));
return OUT;
}pixel shader:
struct Fragout
{
float4 col : COLOR0;
};
struct ConnectData
{
float4 inColor : TEXCOORD1;
};
Fragout main(ConnectData IN)
{
Fragout OUT;
OUT.col = IN.inColor;
OUT.col.a = 1;
return OUT;
}Again, code compiles and runs with no warnings or errors. And again, it's rendering completely black. Has anyone actually confirmed that light color is being properly set for custom material shaders?
#5
05/01/2011 (11:12 pm)
Try this PS:#include "torque.hlsl"
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};
float4 main( ConnectData IN ) : COLOR
{
float4 OutColor = IN.inColor;
OutColor.r -= 0.5; // Decrement the red channel
return hdrEncode(OutColor);
}
#6
Material:
Shader definition:
VS:
PS:
05/02/2011 (12:48 am)
An complete example...Material:
singleton CustomMaterial( gideon_head )
{
mapTo = "head_d";
sampler["DiffSampler"] = "head_d";
sampler["NormalSampler"] = "head_n";
sampler["SpecSampler"] = "head_s";
shader = TestShader;
version = 3.0;
forwardLit = true;
};Shader definition:
singleton ShaderData( TestShader )
{
DXVertexShaderFile = "shaders/common/testV.hlsl";
DXPixelShaderFile = "shaders/common/testP.hlsl";
pixVersion = 3.0;
};VS:
#include "shaders/common/hlslstructs.h"
struct ConnectData
{
float4 hpos : POSITION;
float3 WorldNormal : NORMAL;
float3 WorldTangent : TANGENT;
float3 WorldBinormal : BINORMAL;
float2 TexCoord : TEXCOORD0;
float4 inColor : TEXCOORD1;
float3 LightVec : TEXCOORD2;
float3 EyeVec : TEXCOORD3;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
ConnectData main( VertexIn_PNTTTB IN,
uniform float4x4 modelview,
uniform float4x4 objTrans,
uniform float3 eyePos,
uniform float4 inLightPos[3],
uniform float4 inLightColor[4]
)
{
ConnectData OUT;
float3 WorldSpacePos = mul(objTrans, IN.pos).xyz;
// -----------------------------------------------------------------
// Texture Coordinate
// -----------------------------------------------------------------
OUT.TexCoord = IN.uv0;
// -----------------------------------------------------------------
// Calculate the Normal, Tangent, and Binormal
// -----------------------------------------------------------------
OUT.WorldNormal = normalize(mul(objTrans, IN.normal));
float3 c1 = normalize( cross( OUT.WorldNormal, float3(0.0, 0.0, 1.0) ));
float3 c2 = cross( OUT.WorldNormal, float3(0.0, 1.0, 0.0) );
if( length(c1) > length(c2) )
{
OUT.WorldTangent = c1;
} else {
OUT.WorldTangent = c2;
}
OUT.WorldTangent = normalize(mul(objTrans, OUT.WorldTangent));
OUT.WorldBinormal = normalize(mul(objTrans, cross(OUT.WorldTangent, OUT.WorldNormal).xyz));
// -----------------------------------------------------------------
// Vertex Position
// -----------------------------------------------------------------
OUT.hpos = mul(modelview, float4(IN.pos.xyz,1));
// -----------------------------------------------------------------
// Eye Vector
// -----------------------------------------------------------------
OUT.EyeVec = -(IN.pos.xyz - eyePos);
// -----------------------------------------------------------------
// Light Vector
// -----------------------------------------------------------------
float3 LightPosition = float3(inLightPos[0].x, inLightPos[1].x, inLightPos[2].x);
OUT.LightVec = LightPosition - WorldSpacePos;
// -----------------------------------------------------------------
// Colour Light
// -----------------------------------------------------------------
OUT.inColor = inLightColor[0].rgba;
return OUT;
}PS:
#include "torque.hlsl"
uniform sampler DiffSampler: register( S0 );
uniform sampler NormalSampler: register( S1 );
uniform sampler SpecSampler: register( S2 );
struct ConnectData
{
float4 hpos : POSITION;
float3 WorldNormal : NORMAL;
float3 WorldTangent : TANGENT;
float3 WorldBinormal : BINORMAL;
float2 TexCoord : TEXCOORD0;
float4 inColor : TEXCOORD1;
float3 LightVec : TEXCOORD2;
float3 EyeVec : TEXCOORD3;
};
float4 SpecularFrontOn( float3 Normals, float3 EyeVec, float3 LightVec, float4 Power, float4 Gloss)
{
float3 SpecReflect = (2 * dot(Normals, LightVec) * Normals - LightVec);
float4 Specular = pow(saturate(dot(SpecReflect, EyeVec)), Gloss) * Power;
return Specular;
}
float4 main( ConnectData IN ) : COLOR
{
float2 TexUV = IN.TexCoord.xy;
float3 EV = normalize(IN.EyeVec);
float3 LV = normalize(IN.LightVec);
float3 WN = normalize(IN.WorldNormal);
float3 TN = normalize(IN.WorldTangent);
float3 BN = normalize(IN.WorldBinormal);
float4 Diff = normalize(tex2D(DiffSampler, TexUV));
float3 Normal = normalize(tex2D(NormalSampler, TexUV).xyz * 2.0 - 1.0);
float3 N = (WN * Normal.z ) + (Normal.x * BN + Normal.y * -TN);
float4 DotLN = dot(LV, normalize(N));
float4 Spec = SpecularFrontOn(N, EV, LV, 0.28, normalize(tex2D(SpecSampler, TexUV).a));
float4 OutColor = (Diff + (DotLN * Diff) + Spec);
return hdrEncode(OutColor);
}
#7
My issue is that the light color isn't being set in the shader. I tried the shader code you posted above and I'm still having this same problem.
You may not have noticed it, but your pixel shader isn't making use of ConnectData.inColor. it's only using the diffuse texture color and specular.
here's a small exercise for you Alfio to demonstrate my problem, open your pixel shader and, at the last line, set OutColor=IN.inColor, which should be the light color.
If you do this, you'll see it renders completely black no matter what the color of the sun is.
Again, I have to ask, has anyone *ever* verified that light information is being properly set for custom material shaders?
05/02/2011 (6:39 pm)
Alfio-My issue is that the light color isn't being set in the shader. I tried the shader code you posted above and I'm still having this same problem.
You may not have noticed it, but your pixel shader isn't making use of ConnectData.inColor. it's only using the diffuse texture color and specular.
here's a small exercise for you Alfio to demonstrate my problem, open your pixel shader and, at the last line, set OutColor=IN.inColor, which should be the light color.
If you do this, you'll see it renders completely black no matter what the color of the sun is.
Again, I have to ask, has anyone *ever* verified that light information is being properly set for custom material shaders?
#8
The code in the post #6, i have pasted it to give to others an starting point.
05/03/2011 (7:03 am)
In the post #5 i used the color input, and it works great. If you set the color of light on the blue, my object is rendered in blue.The code in the post #6, i have pasted it to give to others an starting point.
#10
05/03/2011 (8:08 am)
Richard, the forward rendering work great, but T3D expose only 4 lights to the external shaders. So, as i have done, u can mix Deffered and Forward Rendering to have a decent result.
#11
05/03/2011 (10:22 am)
4 eh? Better than nothing I suppose - but can you choose which 4?
#12
Material:
singleton CustomMaterial( gideon_head )
{
mapTo = "head_d";
shader = TestShader;
version = 3.0;
forwardLit = true;
};
Shader definition:
singleton ShaderData( TestShader )
{
DXVertexShaderFile = "shaders/lightV.hlsl";
DXPixelShaderFile = "shaders/testP.hlsl";
pixVersion = 3.0;
};
lightV.hlsl:
#include "shaders/common/hlslstructs.h"
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};
ConnectData main( VertexIn_PNTTTB IN,
uniform float4x4 modelview,
uniform float4 inLightPos[3],
uniform float4 inLightColor[4]
)
{
ConnectData OUT;
OUT.inColor = inLightColor[0].rgba;
OUT.hpos = mul(modelview, float4(IN.pos.xyz,1));
return OUT;
}
testP.hlsl:
#include "shaders/common/torque.hlsl"
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};
float4 main( ConnectData IN ) : COLOR
{
float4 OutColor = IN.inColor;
OutColor.r -= 0.5; // Decrement the red channel
return hdrEncode(OutColor);
}
I get no errors or warnings at all and gideon's head is rendering completely black. Is there anything wrong with what I've done here?
05/03/2011 (10:38 am)
@Alfio here's a complete example of what I'm doing. Hopefully you can take a look and see what I'm doing wrong:Material:
singleton CustomMaterial( gideon_head )
{
mapTo = "head_d";
shader = TestShader;
version = 3.0;
forwardLit = true;
};
Shader definition:
singleton ShaderData( TestShader )
{
DXVertexShaderFile = "shaders/lightV.hlsl";
DXPixelShaderFile = "shaders/testP.hlsl";
pixVersion = 3.0;
};
lightV.hlsl:
#include "shaders/common/hlslstructs.h"
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};
ConnectData main( VertexIn_PNTTTB IN,
uniform float4x4 modelview,
uniform float4 inLightPos[3],
uniform float4 inLightColor[4]
)
{
ConnectData OUT;
OUT.inColor = inLightColor[0].rgba;
OUT.hpos = mul(modelview, float4(IN.pos.xyz,1));
return OUT;
}
testP.hlsl:
#include "shaders/common/torque.hlsl"
struct ConnectData
{
float4 hpos : POSITION;
float4 inColor : TEXCOORD1;
};
float4 main( ConnectData IN ) : COLOR
{
float4 OutColor = IN.inColor;
OutColor.r -= 0.5; // Decrement the red channel
return hdrEncode(OutColor);
}
I get no errors or warnings at all and gideon's head is rendering completely black. Is there anything wrong with what I've done here?
#13
NO, u can't. Normally the first is ever the SunLight, and the remaining three should be the first three entered on scene.
...but maybe i'm wrong
Would be a good idea to modify the source of shadergen to return all the lights, and then, somehow, the shader will use only those with a certain object/light distance range. In any case, if the range is too high, or if there are too many lights in the range. Becomes heavy for the video card, go to calculate 20 or more lights loop.
@Sean: A u sure the path is right?
EDIT:
Another major problem concerns the occlusion of the lights from other objects in the scene. So we are forced to use the deferred rendering system included in T3D, to cast shadows on objects using custom shaders.
05/03/2011 (10:57 am)
@Richard: From my tests, i can tell u....NO, u can't. Normally the first is ever the SunLight, and the remaining three should be the first three entered on scene.
...but maybe i'm wrong
Would be a good idea to modify the source of shadergen to return all the lights, and then, somehow, the shader will use only those with a certain object/light distance range. In any case, if the range is too high, or if there are too many lights in the range. Becomes heavy for the video card, go to calculate 20 or more lights loop.
@Sean: A u sure the path is right?
singleton ShaderData( TestShader )
{
DXVertexShaderFile = "shaders/lightV.hlsl";
DXPixelShaderFile = "shaders/testP.hlsl";
pixVersion = 3.0;
};EDIT:
Another major problem concerns the occlusion of the lights from other objects in the scene. So we are forced to use the deferred rendering system included in T3D, to cast shadows on objects using custom shaders.
#14
05/03/2011 (11:51 am)
I'm going to HOPE that forward rendered objects receive the sun + the 3 most powerful lights (that is, strongest strength, attenuated based on distance) and not just the first 3 in the scene...
#15
05/03/2011 (11:55 am)
It *should* be receiving the the 3 most important lights for that object at its current position (which means it can change as the object moves and the 3 nearest/most powerful lights change).
#16
Yes it does. You even have a per-light "priority" which you can set to have them prefer on light over others. Still in practice it doesn't work as well as one would like. As you move around a new light is suddenly more importaint and you switch to it instantly.
I'm thinking if i find the time to change it to merge lights together by blending their properties, but i worry if that will cause things to move around too much.
Another option is when switch from one light set to another we animate the change so it occurs over a second or so.
Anyway... lights should be used sparingly in the forward lighting mode at the moment. If you want lots of lights... that is what deferred is for.
05/03/2011 (2:03 pm)
Quote:I'm going to HOPE that forward rendered objects receive the sun + the 3 most powerful lights
Yes it does. You even have a per-light "priority" which you can set to have them prefer on light over others. Still in practice it doesn't work as well as one would like. As you move around a new light is suddenly more importaint and you switch to it instantly.
I'm thinking if i find the time to change it to merge lights together by blending their properties, but i worry if that will cause things to move around too much.
Another option is when switch from one light set to another we animate the change so it occurs over a second or so.
Anyway... lights should be used sparingly in the forward lighting mode at the moment. If you want lots of lights... that is what deferred is for.
#17
yes that is the correct path. I know the shader is working correctly and that the objects and shader files are set up correctly because I can specify a shader output color. If there was a path or compile problem, I would see the error logged in the console and I wouldn't be able to control the output color. the fact that I can set OutColor = float4(1,0,0,0) and see gideon rendered as red means that the shader is set up correctly. does that make sense?
so, I know the shader is set up correctly, so what's wrong with the code?
@Matt and Tom, I would greatly appreciate it if you guys would give me some help here. please see my previous post(or my original post) and let me know if you can see why this shader is rendering as complete black. Also, consider the fact that I can modify the shader output and see the results correctly in-game, I get no compile errors or warnings, and I haven't made any source code changes.
just to give some context, I've been writing hlsl shaders in TGEA 1.7.1 for about 2 years now. I've implemented various lighting techniques and brdf's in hlsl for TGEA 1.7.1. I'm by no means a newbie to torque or shader programming. I added a very robust dynamic lighting system to TGEA 1.7.1 which uses a custom stencil buffer shadow implementation.
however, I've never written a shader for TGEA 1.8 or any version of torque since the new shader constant handle system was added. I'm banging my head against the wall over this one, because it's holding me back from being able to migrate my old shaders from TGEA 1.7.1.
05/03/2011 (8:44 pm)
@Alfio- yes that is the correct path. I know the shader is working correctly and that the objects and shader files are set up correctly because I can specify a shader output color. If there was a path or compile problem, I would see the error logged in the console and I wouldn't be able to control the output color. the fact that I can set OutColor = float4(1,0,0,0) and see gideon rendered as red means that the shader is set up correctly. does that make sense?
so, I know the shader is set up correctly, so what's wrong with the code?
@Matt and Tom, I would greatly appreciate it if you guys would give me some help here. please see my previous post(or my original post) and let me know if you can see why this shader is rendering as complete black. Also, consider the fact that I can modify the shader output and see the results correctly in-game, I get no compile errors or warnings, and I haven't made any source code changes.
just to give some context, I've been writing hlsl shaders in TGEA 1.7.1 for about 2 years now. I've implemented various lighting techniques and brdf's in hlsl for TGEA 1.7.1. I'm by no means a newbie to torque or shader programming. I added a very robust dynamic lighting system to TGEA 1.7.1 which uses a custom stencil buffer shadow implementation.
however, I've never written a shader for TGEA 1.8 or any version of torque since the new shader constant handle system was added. I'm banging my head against the wall over this one, because it's holding me back from being able to migrate my old shaders from TGEA 1.7.1.
#18
@Sean: The problem you're experiencing seems very strange. No one doubts your knowledge in the field, but sometimes even a pro can make trivial mistakes. Do not get angry if i asked you for the paths. =)
05/04/2011 (4:27 am)
@Tom: As always u a the big brother. Thanks for the clarification. You're becoming my guardian angel XD@Sean: The problem you're experiencing seems very strange. No one doubts your knowledge in the field, but sometimes even a pro can make trivial mistakes. Do not get angry if i asked you for the paths. =)
#19
thats ironic because i thought the tone of my last post was far from angry. if you thought my last post was angry, it wasn't because you asked me whether my path was correct, it's because of the strange problem I am having.
05/04/2011 (6:07 am)
Quote:
Do not get angry if i asked you for the paths. =)
thats ironic because i thought the tone of my last post was far from angry. if you thought my last post was angry, it wasn't because you asked me whether my path was correct, it's because of the strange problem I am having.
#20
My platform:
Windows 7 Ultimate 64Bit
ATI Radeon HD 5450
June 2010 DirectX SDK
05/04/2011 (6:18 am)
I just tried with the debug version of the T3D, and also with DirectX in DebugMode. But i can not recreate your error.My platform:
Windows 7 Ultimate 64Bit
ATI Radeon HD 5450
June 2010 DirectX SDK
Torque 3D Owner Nicolas Buquet
Nicolas Buquet
www.buquet-net.com/cv/