Interior Light Information to Custom Shader
by Robert Luke · in Torque Game Engine Advanced · 06/11/2007 (6:35 pm) · 16 replies
I am trying to get a custom shader working properly indoors. This has been a nightmare. When outside, the sun's direction is passed to a custom shader as register c24. But, when the character is inside, it sets light 1 at a position way far away and the direction of the light as straight down.
That is the main issue. No matter what I try, I am unable to pass a light's position, direction or color to a dts custom shader when inside a dif. I looked to the tgea demo and was surprised to see the spaceorc get light correctly by an interior light. The problem is, the spaceorc is using a procedural shader. If I set up a custom shader for the spaceorc, it no longer gets the light's information, but instead gets that default straight down light direction.
Ok, I thought I had a good place to start to look through the engine code. All I had to do was make the customMaterial work like material so that a custom shader would get the same variables passed to it as a procedural shader. After spending a significant amount of time reverse engineering the code, I am unable to determine why the custom shaders don't get the right information.
Specifically, the function getDynamicLightingMaterial() in matInstance.h is where I stopped my adventure for the truth. When looking at the values in the array
root->dynamicLightingMaterials_Single
I notice that they are all null. So, there appears to be no connection between the custom material and the light. So the light information doesn't get into the scenegraph in the TSMesh::render() function.
The only forum I could find that was related to this topic was
http://www.garagegames.com/mg/forums/result.thread.php?qt=28286
This guy appears to have figured out how to make dynamic lights work in a previous version of the engine. Of course this info is dated, and as he states at the bottom of the thread, he tried to merge it with a more recent version of the engine and it didn't work.
So, does anybody have an answer? As I said, it appears that this stuff was put into the engine, but is just not complete. Meaning, it worked for procedural shaders but not custom shaders. If this really isn't in the engine, it's inexcusable. Shaders are the reason to buy tgea instead of tge. This has to be in the engine.
That is the main issue. No matter what I try, I am unable to pass a light's position, direction or color to a dts custom shader when inside a dif. I looked to the tgea demo and was surprised to see the spaceorc get light correctly by an interior light. The problem is, the spaceorc is using a procedural shader. If I set up a custom shader for the spaceorc, it no longer gets the light's information, but instead gets that default straight down light direction.
Ok, I thought I had a good place to start to look through the engine code. All I had to do was make the customMaterial work like material so that a custom shader would get the same variables passed to it as a procedural shader. After spending a significant amount of time reverse engineering the code, I am unable to determine why the custom shaders don't get the right information.
Specifically, the function getDynamicLightingMaterial() in matInstance.h is where I stopped my adventure for the truth. When looking at the values in the array
root->dynamicLightingMaterials_Single
I notice that they are all null. So, there appears to be no connection between the custom material and the light. So the light information doesn't get into the scenegraph in the TSMesh::render() function.
The only forum I could find that was related to this topic was
http://www.garagegames.com/mg/forums/result.thread.php?qt=28286
This guy appears to have figured out how to make dynamic lights work in a previous version of the engine. Of course this info is dated, and as he states at the bottom of the thread, he tried to merge it with a more recent version of the engine and it didn't work.
So, does anybody have an answer? As I said, it appears that this stuff was put into the engine, but is just not complete. Meaning, it worked for procedural shaders but not custom shaders. If this really isn't in the engine, it's inexcusable. Shaders are the reason to buy tgea instead of tge. This has to be in the engine.
About the author
#2
Your custom material must define the dynamicLightingMaterial and dynamicLightingMaskMaterial properties.
The atlas system has similar materials in it. Look at AtlasDynamicLightingMaskShader and AtlasDynamicLightingShader in common/lighting/sgShaders.cs. Those point at the two pixel/vertex shaders that you should be able to grok the lighting out of.
I hope this points you in a good direction. I plan on looking into this more closely soon.
06/12/2007 (9:20 am)
I haven't looked too closely into this yet, but here's the general flow that I see after peeking at it:Your custom material must define the dynamicLightingMaterial and dynamicLightingMaskMaterial properties.
The atlas system has similar materials in it. Look at AtlasDynamicLightingMaskShader and AtlasDynamicLightingShader in common/lighting/sgShaders.cs. Those point at the two pixel/vertex shaders that you should be able to grok the lighting out of.
I hope this points you in a good direction. I plan on looking into this more closely soon.
#3
Here's the basics of linking:
-the main/root material (the one bound to a texture and applied to an object) only processes directional dynamic lighting, static lighting (light maps), or, for objects that ignore lighting, process no lighting.
-the dynamic lighting material, which is linked off of the root materials "dynamicLightingMaterial" property, only processes point and spot dynamic lighting.
-the dynamic lighting mask material ("dynamicLightingMaskMaterial") processes dynamic point and spot lighting that is using a mask cubemap.
Here's a quick example of the material definitions from atlas:
The constants "$dynamiclight" and "$dynamiclightmask" are built into the engine and tell TGEA that your shader expects the dynamic lighting or mask texture respectively in the assigned texture unit.
How to create a dynamic point and spot lighting shader:
The lighting system has several built-in shader functions that help simplify dynamic lighting and ensure the it's similar to other in-game lighting - just include the the shader header "lightingSystem/shdrLib.h" to access them.
The header includes the following functions:
-getDynamicLightingCoord - used by vertex shaders to get the coords used for sampling the lighting texture. Expects the vertex and light positions in object space, the current object to world transform, and the lighting transform - all are supplied in the expected format by the engine, so just pass them in. Returns the float3 coords used to lookup the lighting texture - just pass this on to the pixel shader.
-getDynamicLighting - used to sample the dynamic lighting texture. Expects the dynamic lighting texture, the lighting texture coords supplied by the vertex shader, and the light color - all supplied in the correct format by the engine or vertex shader.
The atlas custom shaders are very good examples of minimal dynamic lighting shaders.
The atlas dynamic lighting vertex shader "atlasSurfaceDynamicLightingV.hlsl":
The atlas dynamic lighting pixel shader "atlasSurfaceDynamicLightingP.hlsl":
I highlighted the lighting related code, these few changes handle all of the base lighting calculations.
Let me know if this helps!
06/13/2007 (11:24 pm)
The lighting system works with materials by linking multiple lighting materials together and using the material necessary for a particular lighting task - similar to how fallbacks work. For procedural materials everything is generated and setup automatically, custom materials need to be setup manually.Here's the basics of linking:
-the main/root material (the one bound to a texture and applied to an object) only processes directional dynamic lighting, static lighting (light maps), or, for objects that ignore lighting, process no lighting.
-the dynamic lighting material, which is linked off of the root materials "dynamicLightingMaterial" property, only processes point and spot dynamic lighting.
-the dynamic lighting mask material ("dynamicLightingMaskMaterial") processes dynamic point and spot lighting that is using a mask cubemap.
Here's a quick example of the material definitions from atlas:
new CustomMaterial(AtlasDynamicLightingMaskMaterial)
{
texture[0] = "$dynamiclight";
texture[1] = "$dynamiclightmask";
shader = AtlasDynamicLightingMaskShader;
version = 1.1;
preload = true;
};
new CustomMaterial(AtlasDynamicLightingMaterial)
{
texture[0] = "$dynamiclight";
shader = AtlasDynamicLightingShader;
version = 1.1;
preload = true;
};
new CustomMaterial(AtlasMaterial)
{
shader = AtlasShader;
version = 1.1;
dynamicLightingMaterial = AtlasDynamicLightingMaterial;
dynamicLightingMaskMaterial = AtlasDynamicLightingMaskMaterial;
preload = true;
};The constants "$dynamiclight" and "$dynamiclightmask" are built into the engine and tell TGEA that your shader expects the dynamic lighting or mask texture respectively in the assigned texture unit.
How to create a dynamic point and spot lighting shader:
The lighting system has several built-in shader functions that help simplify dynamic lighting and ensure the it's similar to other in-game lighting - just include the the shader header "lightingSystem/shdrLib.h" to access them.
The header includes the following functions:
-getDynamicLightingCoord - used by vertex shaders to get the coords used for sampling the lighting texture. Expects the vertex and light positions in object space, the current object to world transform, and the lighting transform - all are supplied in the expected format by the engine, so just pass them in. Returns the float3 coords used to lookup the lighting texture - just pass this on to the pixel shader.
-getDynamicLighting - used to sample the dynamic lighting texture. Expects the dynamic lighting texture, the lighting texture coords supplied by the vertex shader, and the light color - all supplied in the correct format by the engine or vertex shader.
The atlas custom shaders are very good examples of minimal dynamic lighting shaders.
The atlas dynamic lighting vertex shader "atlasSurfaceDynamicLightingV.hlsl":
#define IN_HLSL
#include "../shdrConsts.h"
#include "atlas.h"
[b]#include "../lightingSystem/shdrLib.h"[/b]
struct VertLightConnectData
{
float4 hpos : POSITION;
[b]float3 lightingCoord : TEXCOORD0;[/b]
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
VertLightConnectData main( VertData IN,
uniform float4x4 modelView : register(C0),
uniform float3 eyePos : register(VC_EYE_POS),
uniform float morphT : register(C49),
uniform float4x4 objTrans : register(VC_OBJ_TRANS),
[b]uniform float4 lightPos : register(VC_LIGHT_POS1),
uniform float4x4 lightingMatrix : register(VC_LIGHT_TRANS)[/b]
)
{
VertLightConnectData OUT;
// Apply morph calculations.
float4 realPos = IN.position + (IN.morphCoord * morphT);
realPos.w = 1;
// Transform and return.
OUT.hpos = mul(modelView, realPos);
// Let's get some lighting calcs in here.
[b]OUT.lightingCoord = getDynamicLightingCoord(IN.position, lightPos, objTrans, lightingMatrix);[/b]
return OUT;
}The atlas dynamic lighting pixel shader "atlasSurfaceDynamicLightingP.hlsl":
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
#define IN_HLSL
#include "../shdrConsts.h"
[b]#include "../lightingSystem/shdrLib.h"[/b]
struct ConnectData
{
[b]float3 lightingCoord : TEXCOORD0;[/b]
};
struct Fragout
{
float4 col : COLOR0;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
Fragout main( ConnectData IN,
[b]uniform sampler3D dlightMap : register(S0),
uniform float4 lightColor : register(PC_DIFF_COLOR)[/b]
)
{
Fragout OUT;
[b]OUT.col = getDynamicLighting(dlightMap, IN.lightingCoord, lightColor);[/b]
// alpha is sum(r,g,b) so we can filter unlit pixels with alpha test.
OUT.col.w = OUT.col.x + OUT.col.y + OUT.col.z;
return OUT;
}I highlighted the lighting related code, these few changes handle all of the base lighting calculations.
Let me know if this helps!
#4
06/14/2007 (8:33 am)
John can you put this in a TDN article? It's far to useful to just be buried in the forums.
#5
You could probably post this on TDN and get the ball rolling, then John or someone else could come along later and give it any additional editing love that it might need.
Of course that's easy for me to say. Wiki editing makes my brain hurt.
:)
06/14/2007 (8:50 am)
@Mark, You could probably post this on TDN and get the ball rolling, then John or someone else could come along later and give it any additional editing love that it might need.
Of course that's easy for me to say. Wiki editing makes my brain hurt.
:)
#6
John, please feel free to edit and add for completeness.
06/14/2007 (12:20 pm)
Done, the article can be viewed here.John, please feel free to edit and add for completeness.
#7
06/14/2007 (8:25 pm)
Thanks a bunch John, that is much appreciated.
#8
06/15/2007 (12:29 pm)
Hey Mark, awesome - I updated the section titles, everything else looks great.
#9
06/15/2007 (12:32 pm)
We got some shadowing bugs (possibly) for you to look at as well John, if you have time. We get some really funky colours inside of large interiors. I'll start a new thread, though.
#10
I added this to my project and get proper lighting on my characters from point sources. I still have one problem though. The engine appears to believe there is always a sun. So, when inside, it defaults the sun's position to somewhere far overhead and it's direction as (0 0 -1). It also creates a shadow straight down.
I tried to get rid of this by multiplying the lighting by the intesity of the light source. My thought was that the value of the sun's intensity indoor would be (0 0 0), it's not. So instead of getting black, I get a low gray value. Another strange thing is that the intensity indoor was affected by the color and ambient of the actual sun even though the interior is completely enclosed.
I decided to check the direction of the sun to determine if the object is inside. If the z direction is less than -.99 I don't light the object and just let the dynamic lights do their thing. This gets rid of the lighting, but I still have the straight down shadows.
If anybody knows how to tell the engine/shader that the object is inside and that there is no sun that would be great. Otherwise no prob.
Again, thank you everyone. After having all my problems I decided to change my game to being entirely outdoors. Now I don't have to. Thank you thank you thank you.
06/19/2007 (3:56 pm)
Props to everyone. I was out of town for a few days and when I returned I had a complete answer. I got to get of town more often.I added this to my project and get proper lighting on my characters from point sources. I still have one problem though. The engine appears to believe there is always a sun. So, when inside, it defaults the sun's position to somewhere far overhead and it's direction as (0 0 -1). It also creates a shadow straight down.
I tried to get rid of this by multiplying the lighting by the intesity of the light source. My thought was that the value of the sun's intensity indoor would be (0 0 0), it's not. So instead of getting black, I get a low gray value. Another strange thing is that the intensity indoor was affected by the color and ambient of the actual sun even though the interior is completely enclosed.
I decided to check the direction of the sun to determine if the object is inside. If the z direction is less than -.99 I don't light the object and just let the dynamic lights do their thing. This gets rid of the lighting, but I still have the straight down shadows.
If anybody knows how to tell the engine/shader that the object is inside and that there is no sun that would be great. Otherwise no prob.
Again, thank you everyone. After having all my problems I decided to change my game to being entirely outdoors. Now I don't have to. Thank you thank you thank you.
#11
I too would like to know if there's a setting or other way to disable the sun / ambient lighting on interiors, as my game has large interior only levels, some transitional levels and some outdoor only.
Having a way to do this would be very usefull because it will make it much easier to have lighting contrasts between indoor and outdoor and also to get the lighting exactly the way I want it based on the precalced and mission lights in the scene.
06/21/2007 (1:46 am)
Quote: I added this to my project and get proper lighting on my characters from point sources. I still have one problem though. The engine appears to believe there is always a sun. So, when inside, it defaults the sun's position to somewhere far overhead and it's direction as (0 0 -1). It also creates a shadow straight down
I too would like to know if there's a setting or other way to disable the sun / ambient lighting on interiors, as my game has large interior only levels, some transitional levels and some outdoor only.
Having a way to do this would be very usefull because it will make it much easier to have lighting contrasts between indoor and outdoor and also to get the lighting exactly the way I want it based on the precalced and mission lights in the scene.
#12
This allows dts objects to receive relatively accurate lighting and shading on the terrain even when standing in another object's shadow. This also allows objects to receive relatively good lighting from static lights that do not directly illuminate dts objects.
The environmental lighting value is rarely empty, and should probably be applied.
If you want to kill off the environmental lighting when inside an interior try changing the following code in file sgLightManager.cc line 349, method LightManager::sgSetupLights:
The transition will be rough, but the lighting and shadow related to the environmental lighting should go away.
06/21/2007 (11:47 am)
The directional light source applied to dts objects in TLS is frequently called "environmental lighting", because it doesn't come directly from the sun. The value it extracted from the terrain or interior directly below the dts object and also based on zoning info.This allows dts objects to receive relatively accurate lighting and shading on the terrain even when standing in another object's shadow. This also allows objects to receive relatively good lighting from static lights that do not directly illuminate dts objects.
The environmental lighting value is rarely empty, and should probably be applied.
If you want to kill off the environmental lighting when inside an interior try changing the following code in file sgLightManager.cc line 349, method LightManager::sgSetupLights:
// players, vehicles, ...
if(obj->overrideOptions)
{
if(outside)
{
light.mType = LightInfo::Vector;
light.mDirection = sun->mDirection;
[b]light.mColor = ambientColor * directionalFactor;
light.mAmbient = ambientColor * ambientFactor;
}
else
{
light.mColor = ColorF(0, 0, 0);
light.mAmbient = ColorF(0, 0, 0);
}[/b]
}The transition will be rough, but the lighting and shadow related to the environmental lighting should go away.
#13
I suppose this would mean if I wanted inside and outside for my dif, then I'd really need to have a completely seperate inside dif and an outside section slotted over it, so the outside section can still have ambient. Or would there be a better way?
Thanks again
06/23/2007 (8:20 am)
Thanks very much for the swift and concise reply, that info will certainly come in very usefull!I suppose this would mean if I wanted inside and outside for my dif, then I'd really need to have a completely seperate inside dif and an outside section slotted over it, so the outside section can still have ambient. Or would there be a better way?
Thanks again
#14
The two ways to remove the sun's ambient from inside interiors is to set the sun's ambient to (0, 0 ,0) or, if there are some outside visible areas and you need ambient lighting for those, use zones in your interior to prevent the ambient from entering the building.
06/23/2007 (9:27 am)
Trevor, sorry about that, my last post was in response to Robert's question - environmental lighting only affects dts objects, the legacy terrain and interiors have sunlight baked into their light maps.The two ways to remove the sun's ambient from inside interiors is to set the sun's ambient to (0, 0 ,0) or, if there are some outside visible areas and you need ambient lighting for those, use zones in your interior to prevent the ambient from entering the building.
#15
-Dave Calabrese
Gaslight Studios
08/06/2008 (8:31 am)
I'm having some problems getting this to work. I created my dynamic lighting shaders and am passing in the $dynamiclight constant, however the material is constantly all black. There are no errors present, so I'm thinking there is something wrong with the lights I created. Are there any special properties one must apply to their sgLightObjects for the engine to render them into $dynamiclight?-Dave Calabrese
Gaslight Studios
#16
10/20/2008 (1:23 pm)
I have problems with $dynamiclight when the object is translucent. I get dynamic light when it's not...
Torque 3D Owner J.C. Smith