Game Development Community

Crosscheck: Per-Instance Variables, and Shaders

by Kirk Longendyke · in Torque Game Engine Advanced · 09/14/2007 (9:10 pm) · 8 replies

So, mainly to make sure I'm following this correctly, I did a bit of research and came up with

A (mostly crappy) Object To Shader Code-flow Example

So let me start out by saying that the net effect of this particular little line of hackishness is not likely to blow a bunch of air up anyones skirts. The example provied is arbitrarily small to make it as simple as possible to follow the logic, not so it'll be a drop-in totally usefull rescource.

That being said, just as with datablocks, theres times you'll want to change stock behavior from per type-of-asset, to per-asset, and that's where this comes in. (couple things I have in mind, in case someone wants to turn arround and also do some leg-work are: paletswapping on a texture based on the current mObjectColor setup, multplying the alphachanel of a second damage texture laying on top of a healthy texture based on the object's health so it get's dirtier/more cracked/bloodier, whatever based on the damage it's taken, or simply proprly scrolling tank-treds basedon the tanks movement speed. The only one I'm personally working on atm is the first, so the rest would be things to get back to at some point.)

Now then, for clarity, we'll be starting our code-journey at the material end, and work our way back from there with the following setup:

Engine:
Materials.cc/cpp
void Material::setShaderConstants( const SceneGraphData &sgData, U32 stageNum )
{
...
   if (!mOverrideColor)
       GFX->setPixelShaderConstF( PC_MAT_SPECCOLOR, (float*)&specular[stageNum], 1 );
   else
	   GFX->setPixelShaderConstF( PC_MAT_SPECCOLOR, (float*)&sgData.mObjectColor, 1 );
...
}

Script:
new Material(buggy_body001a)
{
...
	OverrideColor = true;
...
};

This is to ensure that only those flagged materials update, since you'll likely have a few you don't want to bother with.

now sgData get's it's info from struct RenderInst, so we parse in a ColorF mObjectColor; into renderInstMgr.h

In order to have a point of reffernece for that RenderInst, we go into
tsMesh.cc/cpp
void TSMesh::render(S32 frame, S32 matFrame, TSMaterialList * materials)
{
   if( vertsPerFrame <= 0 ) return;

   RenderInst *coreRI = gRenderInstManager.allocInst();
   coreRI->type = RenderInstManager::RIT_Mesh;
   coreRI->calcSortPoint( smObject, smSceneState->getCameraPosition() );

   if (smObject) coreRI->mObjectColor = smObject->mObjectColor; //goes fatal if not assigned...
...
}

smObject refferences a sceneObject (wich is one of the reasons it looks like I'll be neeing to upate the guiobjectview this end once the actual palletswappers written on out, but that's beyond the scope of this case study), so we need to add yet another mObjectColor to that definition, as well as add in:
void SceneObject::initPersistFields()
{
...
   addField("ObjectColor", TypeColorF, Offset(mObjectColor, SceneObject));
...
}

so that we can dynamicly update our values.

Wich brings us to the highly unoptimised quick-hack finish of the lil example:
U32 GameBase::packUpdate(NetConnection *, U32 mask, BitStream *stream)
{
...
   stream->writeFloat(mObjectColor.red, 7);
   stream->writeFloat(mObjectColor.green, 7);
   stream->writeFloat(mObjectColor.blue, 7);
   stream->writeFloat(mObjectColor.alpha, 7);
...
}

void GameBase::unpackUpdate(NetConnection *con, BitStream *stream)
{
...
   mObjectColor.red = stream->readFloat(7);
   mObjectColor.green = stream->readFloat(7);
   mObjectColor.blue = stream->readFloat(7);
   mObjectColor.alpha = stream->readFloat(7);
...
}

aaand finally, what's an explaination involving shaders without crappy programmer-art:

http://img507.imageshack.us/my.php?image=23793758sm9.jpg
http://img507.imageshack.us/my.php?image=35320906rx6.jpg
http://img509.imageshack.us/my.php?image=47990172qb3.jpg


Miss anything? There a cleaner way to accomplish this? Any tips on refining things for the stated three intended usage cases?

#1
09/15/2007 (10:08 am)
That looks good to me. You should convert this post to a TDN article!
#2
09/15/2007 (6:36 pm)
Love to, however, Seems I've hit a snag getting a 'proper' implementation up and running that makes me question a few of my assumptions...

After converting that material hack over to a custommaterial, and using
void CustomMaterial::setShaderConstants( const SceneGraphData &sgData,
                                         U32 stageNum )
{
   if (mOverrideColor) GFX->setVertexShaderConstF( PC_USERDEF1, (float*)&sgData.mObjectColor, 1 );

instead, aplied the following simple-shader:

#define IN_HLSL
#include "shdrConsts.h"
//-----------------------------------------------------------------------------
// Structures                                                                  
//-----------------------------------------------------------------------------
struct ConnectData
{
   float2 texCoord        : TEXCOORD0;
   float2 bumpCoord       : TEXCOORD1;
   float3 lightVec        : TEXCOORD2;
};


struct Fragout
{
   float4 col : COLOR0;
};


//-----------------------------------------------------------------------------
// Main                                                                        
//-----------------------------------------------------------------------------
Fragout main( ConnectData IN,
              uniform sampler2D diffuseMap      : register(S0),
              uniform sampler2D bumpMap         : register(S1),
              uniform float4    ambient         : register(PC_DIFF_COLOR),
              uniform float4    colorpicker     : register(PC_USERDEF1)
)
{
   Fragout OUT;

   OUT.col = tex2D(diffuseMap, IN.texCoord);
   float4 bumpNormal = tex2D(bumpMap, IN.bumpCoord);

   IN.lightVec = IN.lightVec * 2.0 - 1.0;
   float4 bumpDot = saturate( dot(bumpNormal.xyz * 2.0 - 1.0, IN.lightVec.xyz) );
   OUT.col *= bumpDot + ambient;

   //float4 someColor = float4(1.0, 0.0, 0.0, 1.0);
   //OUT.col = OUT.col * someColor;

   OUT.col = OUT.col * colorpicker;


   return OUT;
}

now the someColor calc works as expeted, giving everything a simeple red tone, however switching over to the colorpicker register sends it into all black...
#3
09/15/2007 (9:10 pm)
Looks like you're using the value in a pixel shader, but you are setting a vertex shader constant.

Change this:

if (mOverrideColor) GFX->setVertexShaderConstF( PC_USERDEF1, (float*)&sgData.mObjectColor, 1 );

to this:

if (mOverrideColor) GFX->setPixelShaderConstF( PC_USERDEF1, (float*)&sgData.mObjectColor, 1 );

Oh, and one other thing, it's possible you missed the step that copies the mObjectColor from the RenderInstance to the SceneGraphData structure.
#4
09/15/2007 (9:26 pm)
Actually Con::printf'ed that, it's being sent.
as to the other... DHO! yeah... that was it alright.... apreciate it. now where to shove that on the tdn...
#5
09/17/2007 (9:25 am)
Awesome, good to hear. I'd just shove it under the Materials block in this page: http://tdn.garagegames.com/wiki/TorqueShaderEngine
#6
09/17/2007 (3:45 pm)
Done. Seperated it into Research, and Usage Case, and left a stubbed section for useages at the bottom of the research area, on the off chance someone want's to toss in a few of thiers. Also need to get arround to converting and stubbing out that huge mess o thread about the material based effects at some point... Mebbey tomorrow-thursday if nobody beats me to it.
#7
09/18/2007 (1:07 pm)
Awesome man, thanks!
#8
12/08/2008 (10:23 am)
I have been working with Brian to try to update this resource to TGEA 1.7.1. I have it working in a debug build,
however, when I try to run a release build, I get a crash on startup. ("This program has encountered a problem and needs to close...")

When debugging this error, the call stack showed this: Spiritus Astrum.exe!ColorF::ColorF() + 0x1f C++
I tried removing various parts of the resource to find the error, and I I believe I tracked the error down to the ColorF mObjectColor; definition from sceneobject.h
Uncommenting this allows allows me to get into the game, but I get a crash when I try to load a mission.
If I remove this line from sceneobject.cpp: mObjectColor = ColorF(1,0,0,1); I can get into the mission.

I'm not sure why a seemingly simple colorF definition and initialization would work in debug, and then crash in release. Any ideas?

Thanks