Default Material as CustomMaterial
by Jeff Faust · in Torque Game Engine Advanced · 06/29/2007 (7:48 am) · 17 replies
I'm interested in reproducing the base default Material as a CustomMaterial as a starting point for further refinement. Does anyone know how to do this?
By "default Material", I mean whatever is produced by materials of this form on dts objects:
The resulting material and shaders are actually somewhat complicated as it handles dynamic lighting and fog in addition to basic texture mapping and shading.
I can almost get fog working, but have not been able to get the shader to respond to dynamic lighting. I believe this lighting link on TDN offers some clues as to how dynamic lighting is handled, but it only shows specialized Atlas examples and I have not yet figured out the correct variation for dts objects.
Need a rational? I've been working on a solution to allow player and object alpha-fading (the ability to fade-in or fade-out). Rather than force these calculations on all shaders, I've implemented a solution for custom shaders. Now, the trick is to reproduce the look that these objects have by default, then when a fade is needed, the default material is replaced with a custom material for the duration of the fade.
By "default Material", I mean whatever is produced by materials of this form on dts objects:
new Material(default_mat)
{
baseTex[0] = "base_texture";
}The resulting material and shaders are actually somewhat complicated as it handles dynamic lighting and fog in addition to basic texture mapping and shading.
I can almost get fog working, but have not been able to get the shader to respond to dynamic lighting. I believe this lighting link on TDN offers some clues as to how dynamic lighting is handled, but it only shows specialized Atlas examples and I have not yet figured out the correct variation for dts objects.
Need a rational? I've been working on a solution to allow player and object alpha-fading (the ability to fade-in or fade-out). Rather than force these calculations on all shaders, I've implemented a solution for custom shaders. Now, the trick is to reproduce the look that these objects have by default, then when a fade is needed, the default material is replaced with a custom material for the duration of the fade.
About the author
Jeff Faust creates special effects indie middleware and games for Faust Logic. --- Blog: Effectronica.com --- Twitter: @FaustLogic
#2
What I've been doing is studying the procedural shaders that get created for the base material. The procedural shaders for dynamic lighting are more raw and a little different from the ones that John Kabus describes, but I can sort-of identify the common parts.
The main problem is in the handling of fog. For some reason, fog color is added in as the camera moves very close to the object. There must be a problem with the fog coordinates.
Another problem is that all the dynamic lighting and fog coloring shuts off when transparent is set to true for the material. This would me necessary to get proper shading during alpha-fades.
06/29/2007 (1:03 pm)
Thanks Mark, that thread was of some help. I'm now getting a response that looks more or less correct from dynamic lighting. (Have not tried a dynamic lighting mask material yet.)What I've been doing is studying the procedural shaders that get created for the base material. The procedural shaders for dynamic lighting are more raw and a little different from the ones that John Kabus describes, but I can sort-of identify the common parts.
The main problem is in the handling of fog. For some reason, fog color is added in as the camera moves very close to the object. There must be a problem with the fog coordinates.
Another problem is that all the dynamic lighting and fog coloring shuts off when transparent is set to true for the material. This would me necessary to get proper shading during alpha-fades.
#3
06/29/2007 (1:21 pm)
Wish I could help you more Jeff. I've got a ways to go before I understand what you already know. :)
#4
I was sort of hoping this was really obvious and I was just missing something. It seems to me that without this info it will be really difficult for anyone to create custom shaders for objects that aren't lacking somehow in the way they deal with standard things like fog and lighting.
06/29/2007 (1:39 pm)
Thanks just the same, Mark.I was sort of hoping this was really obvious and I was just missing something. It seems to me that without this info it will be really difficult for anyone to create custom shaders for objects that aren't lacking somehow in the way they deal with standard things like fog and lighting.
#5
I can't promise anything, but I'll try to see if someone can ping the thread with some up to date info.
06/29/2007 (1:53 pm)
@Jeff: I'm almost positive values of those types are available (fog, etc and how to pass them to custom shaders) but honestly over my head on this.I can't promise anything, but I'll try to see if someone can ping the thread with some up to date info.
#6
Let's forget dynamic lighting for a moment and just try to create a custom material that fogs correctly.
To the best of my knowledge, the procedural shader generator creates these shaders for the base portion of the default material.
Vertex Shader:
06/29/2007 (3:10 pm)
OK, I guess I should go into a little more detail... Let's forget dynamic lighting for a moment and just try to create a custom material that fogs correctly.
To the best of my knowledge, the procedural shader generator creates these shaders for the base portion of the default material.
Vertex Shader:
//*****************************************************************************
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct VertData
{
float2 texCoord : TEXCOORD0;
float2 lmCoord : TEXCOORD1;
float3 T : TEXCOORD2;
float3 B : TEXCOORD3;
float3 N : TEXCOORD4;
float3 normal : NORMAL;
float4 position : POSITION;
};
struct ConnectData
{
float4 hpos : POSITION;
float4 shading : COLOR;
float2 outTexCoord : TEXCOORD0;
float2 fogCoord : TEXCOORD1;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
ConnectData main( VertData IN,
uniform float4x4 modelview : register(C0),
uniform float4 inLightColor : register(C25),
uniform float3 inLightVec : register(C24),
uniform float3 eyePos : register(C20),
uniform float3 fogData : register(C22),
uniform float4x4 objTrans : register(C12)
)
{
ConnectData OUT;
OUT.hpos = mul(modelview, IN.position);
OUT.shading = saturate( dot(-inLightVec, IN.normal) );
OUT.shading.w = 1.0;
OUT.shading *= inLightColor;
OUT.outTexCoord = IN.texCoord;
// fog setup
float3 transPos = mul( objTrans, IN.position );
OUT.fogCoord.x = 1.0 - ( distance( IN.position, eyePos ) / fogData.z );
OUT.fogCoord.y = (transPos.z - fogData.x) * fogData.y;
return OUT;
}Pixel Shader://*****************************************************************************
// TGEA -- HLSL procedural shader
//*****************************************************************************
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct ConnectData
{
float4 shading : COLOR;
float2 texCoord : TEXCOORD0;
float2 fogCoord : TEXCOORD1;
};
struct Fragout
{
float4 col : COLOR0;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
Fragout main( ConnectData IN,
uniform float4 ambient : register(C3),
uniform sampler2D diffuseMap : register(S0),
uniform sampler2D fogMap : register(S1)
)
{
Fragout OUT;
OUT.col = IN.shading + ambient;
OUT.col *= tex2D(diffuseMap, IN.texCoord);
float4 fogColor = tex2D(fogMap, IN.fogCoord);
OUT.col.rgb = lerp(OUT.col.rgb, fogColor.rgb, fogColor.a);
return OUT;
}So I copy these under new names and create a new ShaderData:new ShaderData(basicWithFogShader)
{
DXVertexShaderFile = "shaders/AFX/basicWithFogShaderV.hlsl";
DXPixelShaderFile = "shaders/AFX/basicWithFogShaderP.hlsl";
};Now I create a CustomMaterial. This is a TGE-style orc player, but the alpha has been stripped from player.png:new CustomMaterial(customPlayerMaterial)
{
mapTo = "player";
texture[0] = "player";
texture[1] = "$fog";
shader = basicWithFogShader;
preload = true;
};This nearly works. In a foggy scene, the the fog color adds up on the player and it at a distance it gradually fades into the fog. On a lightly fogged scene, the fog color adds up on the player as the camera moves in close to the player. This does not happen with the default shader:new Material(defaultPlayerMaterial)
{
mapTo = "player";
baseTex[0] = "player";
};
#7
You should be able to slap that into a custom shader and get the same results as the procedural shaders.
06/29/2007 (3:29 pm)
If you look in example/shaders/procedural, you'll find the procedural shaders that are created. Shouldn't be too hard to find one with "clean" fog code. Here's the second one I looked at://*****************************************************************************
// TGEA -- HLSL procedural shader
//*****************************************************************************
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct VertData
{
float2 texCoord : TEXCOORD0;
float2 lmCoord : TEXCOORD1;
float3 T : TEXCOORD2;
float3 B : TEXCOORD3;
float3 N : TEXCOORD4;
float3 normal : NORMAL;
float4 position : POSITION;
};
struct ConnectData
{
float4 hpos : POSITION;
float4 shading : COLOR;
float2 outTexCoord : TEXCOORD0;
float2 fogCoord : TEXCOORD1;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
ConnectData main( VertData IN,
uniform float4x4 modelview : register(C0),
uniform float4 inLightColor : register(C25),
uniform float3 inLightVec : register(C24),
uniform float3 eyePos : register(C20),
uniform float3 fogData : register(C22),
uniform float4x4 objTrans : register(C12)
)
{
ConnectData OUT;
OUT.hpos = mul(modelview, IN.position);
OUT.shading = saturate( dot(-inLightVec, IN.normal) );
OUT.shading.w = 1.0;
OUT.shading *= inLightColor;
OUT.outTexCoord = IN.texCoord;
// fog setup
float3 transPos = mul( objTrans, IN.position );
OUT.fogCoord.x = 1.0 - ( distance( IN.position, eyePos ) / fogData.z );
OUT.fogCoord.y = (transPos.z - fogData.x) * fogData.y;
return OUT;
}You should be able to slap that into a custom shader and get the same results as the procedural shaders.
#8
This must be TDN'd. Jeff, anything you can add once you work through it all will be super helpful.
06/29/2007 (3:37 pm)
*Clicks the "watch" checkmark*This must be TDN'd. Jeff, anything you can add once you work through it all will be super helpful.
#9
When used in a CustomMaterial like this:
06/29/2007 (3:56 pm)
@ Brian -- You have recommended exactly what I was doing. If you compare the vertex shader you pulled out of example/shaders/procedural to the one I found the same way, posted earlier in this thread, you'll see that they are functionality identical. (EDIT: I think we must have cross-posted on our last two entries.)When used in a CustomMaterial like this:
new CustomMaterial(customPlayerMaterial)
{
mapTo = "player";
texture[0] = "player";
texture[1] = "$fog";
shader = basicWithFogShader; // made from procedural
preload = true;
};I get the problem described above... in light fog settings, say:visibleDistance = "800";
fogDistance = "500";
fogColor = "0.4 0.4 0.4 1.0";The fog color adds back into the player as the camera moves in closely, something that does not happen with a basic Material.
#10
Basic Material on the Left -- CustomMaterial on the Right.
06/29/2007 (4:12 pm)
Here is a side-by-side pic to illustrate the difference between material results:
Basic Material on the Left -- CustomMaterial on the Right.
#11
06/30/2007 (12:20 pm)
It's prob not the shader that's the problem then. Might be related to shader constant values passed in.
#12
The fogging problem comes in when the fog texture is sampled in the pixel shader.
Shaders used in both cases are identical and I've ruled out different fogCoord values (calculated in the vertex shader). Identical fogCoords produce different alpha values.
All this suggests that alpha in the fogMap texture is different between the Material and the CustomMaterial.
It's a maze of twisty passages, but now I'm diving into the code that builds the fog texture.
07/01/2007 (8:05 am)
At this point I agree that the shader is fine, but it does not appear to be the passed-in shader constants either, (my first assumption also). The fogging problem comes in when the fog texture is sampled in the pixel shader.
float4 fogColor = tex2D(fogMap, IN.fogCoord); OUT.col.rgb = lerp(OUT.col.rgb, fogColor.rgb, fogColor.a);As the camera closes in on the player, the fogColor returned by tex2D() has a different alpha value for CustomMaterial than with Material.
Shaders used in both cases are identical and I've ruled out different fogCoord values (calculated in the vertex shader). Identical fogCoords produce different alpha values.
All this suggests that alpha in the fogMap texture is different between the Material and the CustomMaterial.
It's a maze of twisty passages, but now I'm diving into the code that builds the fog texture.
#13
What must be happening... as the camera closes in on the player, out-of-bounds fog texture coordinates are computed. For the clamped texture of Materials, this produces an acceptable value, but for the un-clamped texture of CutomMaterials, the out-of-bounds texture coordinates are picking up a repeated area of the texture and producing bad values.
This change in CustomMaterial::setupStages() in engine/materials/customMaterial.cpp seems to correct the problem. (Added code in bold.)
Other textures, by casual code inspection, appear to be treated consistently between Materials and CustomMaterials.
07/01/2007 (8:34 am)
Found it! The GFX->setTexture() calls for the fog texture (and others) are in a different place for CustomMaterials than for Materials. For Materials, the fog texture also has its UV address modes set to Clamp. For CustomMaterials this is not done.What must be happening... as the camera closes in on the player, out-of-bounds fog texture coordinates are computed. For the clamped texture of Materials, this produces an acceptable value, but for the un-clamped texture of CutomMaterials, the out-of-bounds texture coordinates are picking up a repeated area of the texture and producing bad values.
This change in CustomMaterial::setupStages() in engine/materials/customMaterial.cpp seems to correct the problem. (Added code in bold.)
case Fog:
{
[b]GFX->setTextureStageAddressModeU( i, GFXAddressClamp );
GFX->setTextureStageAddressModeV( i, GFXAddressClamp );[/b]
GFX->setTexture( i, sgData.fogTex );
break;
}Other textures, by casual code inspection, appear to be treated consistently between Materials and CustomMaterials.
#14
07/01/2007 (11:43 am)
Nice catch Jeff, I'll make the appropriate changes.
#15
07/01/2007 (11:52 am)
@Brian, beat you to it.
#16
Now I'm able to make a CustomMaterial that's very close to the default material (dynamic lighting works but not dynamic lighting masks yet), but my real goal is to modify my default CustomMaterial to respond to dynamic alpha changes. I already have the alpha fading working, but for proper render ordering it must have translucent=true.
Currently, when translucent=true, I lose the dynamic lighting. I believe the following comment found in engine/renderInstance/renderTranslucentMgr.cpp offers a clue:
07/01/2007 (12:36 pm)
Hi guys, glad to see that fix get folded in right away.Now I'm able to make a CustomMaterial that's very close to the default material (dynamic lighting works but not dynamic lighting masks yet), but my real goal is to modify my default CustomMaterial to respond to dynamic alpha changes. I already have the alpha fading working, but for proper render ordering it must have translucent=true.
Currently, when translucent=true, I lose the dynamic lighting. I believe the following comment found in engine/renderInstance/renderTranslucentMgr.cpp offers a clue:
// z sorting and stuff is not working in this mgr... // lighting on hold until this gets fixed...Is this where my problem is and if so, what's the status of dynamic lighting on translucent objects?
#17
Anyway, I found a key place for a simple change and not only did the translucent switching start working, but the dynamic lighting stopped shutting off also. Seems the two problems were related and things we're not quite as bad as the comment cited above was suggesting.
Right now, on a custom material, I'm getting a seamless transition from opaque to fading transparency that appears to work with both standard fog coloring and dynamic lighting.
07/02/2007 (8:02 am)
Well, I lucked out. I was having trouble switching a non-translucent object to a translucent one on-the-fly whenever my custom alpha-fade value dropped below 1. This is a bit tricky because opaque and transparent objects belong in different places in the scene's rendering order. Anyway, I found a key place for a simple change and not only did the translucent switching start working, but the dynamic lighting stopped shutting off also. Seems the two problems were related and things we're not quite as bad as the comment cited above was suggesting.
Right now, on a custom material, I'm getting a seamless transition from opaque to fading transparency that appears to work with both standard fog coloring and dynamic lighting.
Torque 3D Owner Mark Dynna