Sign in to follow this  
howie_007

Odd random behavior with shader

Recommended Posts

howie_007    285
I'm using the February 2010 DirectX SDK. I seem to be getting random behavior with my shader. For example, the below for loop will work or not depending on the mood of the HLSL compiler. It was working at one point but at this moment, it's not. Since the compiler unrolls the loop anyways, I unrolled it manually and it's working again. The calls to get the handle also sometimes causes odd behaviors. I don't fully understand why this is the case. For example, getting the handle to the matrices would cause the wrong light to be on (and cause my test game to slow down considerably) but yet getting the handle to all the other global data seemed to work fine. Sometimes the odd behavior will disappear if switching to shader level 3 or back to 2 depending. This HLSL stuff is really causing me to question my sanity.
//-----------------------------------------------------------------------------
// #defines
//-----------------------------------------------------------------------------

// Make sure this matches in lightlst.h
#define MAX_LIGHTS          5  // 12 max for shader 2, more for shader 3

#define ELT_NONE            0
#define ELT_DIRECTIONAL     1
#define ELT_POINT_INFINITE  2
#define ELT_POINT_RADIUS    3
#define ELT_SPOT            4

//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------

// Lighting only matrix - rigid body transform
// Rotations in x,y,z order, z pos inverted, z sin inverted
float4x4 worldMatrix;
float4x4 worldMatrixTranspose;

// Pos only matrix
// Rotations in z,y,x order
float4x4 worldViewProjMatrix;
texture material;

// Light related globals
bool enableLights;
int lightType[MAX_LIGHTS];
float4 lightPos[MAX_LIGHTS];
float4 lightDif[MAX_LIGHTS];
bool lightEnable[MAX_LIGHTS];
float lightRadius[MAX_LIGHTS];
float4 ambient;

//-----------------------------------------------------------------------------
// Structor Definitions
//-----------------------------------------------------------------------------

struct VS_INPUT
{
	float4 pos	  : POSITION;
	float2 uv0    : TEXCOORD0;
	float3 normal : NORMAL;
};

struct VS_OUTPUT
{
    float4 pos    : POSITION;
	float2 uv0    : TEXCOORD0;
    float4 color  : COLOR0;
};

struct PS_OUTPUT
{
	float4 color : COLOR;
};

//-----------------------------------------------------------------------------
// Texture samplers
//-----------------------------------------------------------------------------
sampler textureSampler = 
sampler_state
{
    Texture = <material>;
};

//-----------------------------------------------------------------------------
// Point Radius light shader function
//-----------------------------------------------------------------------------
float4 CalcPointRadiusLight( int i, float4 vPos, float3 vNormal )
{
	float4 color = float4( 0.f, 0.f, 0.f, 0.f );
	
	// Light vector
	float3 lVec = (float3)(lightPos[i] - mul( vPos, worldMatrix ));
	
	// Get light distance
	float dist = sqrt(length(lVec));
	
	float3 dir = (float3)normalize( lVec );
	float diffuse = max(0.0, dot(dir, mul( vNormal, (float3x3)worldMatrixTranspose )));
	
	if( diffuse > 0.0f )
	{
		if( dist < lightRadius[i] )
		{
			color = float4( (float3)lightDif[i] * diffuse, 1.0 );
		}
		else
		{
			// Use (lightRadius[i] / dist) as a scaler against the diffuse
			color = float4( (float3)(lightDif[i] * diffuse) * (lightRadius[i] / dist), 1.0 );
		}
	}

	return color;
}

//-----------------------------------------------------------------------------
// Point Infinite light shader function
//-----------------------------------------------------------------------------
float4 CalcPointInfiniteLight( int i, float4 vPos, float3 vNormal )
{
	float4 color = float4( 0.f, 0.f, 0.f, 0.f );
	
	float3 dir = (float3)normalize( lightPos[i] - mul( vPos, worldMatrix ) );
	float diffuse = max(0.0, dot(dir, mul( vNormal, (float3x3)worldMatrixTranspose )));
	
	if( diffuse > 0.0f )
	{
		color = float4( (float3)lightDif[i] * diffuse, 1.0 );
	}

	return color;
}

//-----------------------------------------------------------------------------
// Directional light shader function
//-----------------------------------------------------------------------------
float4 CalcDirLight( int i, float3 vNormal )
{
	float4 color = float4( 0.f, 0.f, 0.f, 0.f );
	float3 dir = (float3)mul( lightPos[i], worldMatrix );
	float diffuse = max(0.0, dot(dir, vNormal));
	
	if( diffuse > 0.0f )
	{
		color = float4( (float3)lightDif[i] * diffuse, 1.0 );
	}
	
	return color;
}

//-----------------------------------------------------------------------------
// Directional light shader function
//-----------------------------------------------------------------------------
float4 CalcLight( int i, float4 vPos, float3 vNormal )
{
	float4 color = float4( 0.f, 0.f, 0.f, 0.0 );
	
	if( lightEnable[i] )
	{
		if( lightType[i] == ELT_POINT_INFINITE )
		{
			color = CalcPointInfiniteLight( i, vPos, vNormal );
		}
		else if( lightType[i] == ELT_POINT_RADIUS )
		{
			color = CalcPointRadiusLight( i, vPos, vNormal );
		}
		else if( lightType[i] == ELT_DIRECTIONAL )
		{
			color = CalcDirLight( i, vNormal );
		}
	}
	
	return color;
}

//-----------------------------------------------------------------------------
// Main vertex shader function
//-----------------------------------------------------------------------------
VS_OUTPUT v_shader( VS_INPUT IN )
{
    VS_OUTPUT OUT;

	// Add the ambient
	OUT.color = ambient;
	
	if( enableLights )
	{
		//for( int i = 0; i < MAX_LIGHTS; i++ )
		//{
		//	OUT.color += CalcLight( i, IN.pos, IN.normal );
		//}
		
		OUT.color += CalcLight( 0, IN.pos, IN.normal );
		OUT.color += CalcLight( 1, IN.pos, IN.normal );
		OUT.color += CalcLight( 2, IN.pos, IN.normal );
		OUT.color += CalcLight( 3, IN.pos, IN.normal );
		OUT.color += CalcLight( 4, IN.pos, IN.normal );
	}
	 
	OUT.pos = mul( IN.pos, worldViewProjMatrix );

	OUT.uv0 = IN.uv0;
	OUT.color = min(1, OUT.color);

	return OUT;
}

//-----------------------------------------------------------------------------
// Main pixel shader function
//-----------------------------------------------------------------------------
PS_OUTPUT p_shader( VS_OUTPUT IN )
{
    PS_OUTPUT OUT;

	OUT.color = tex2D( textureSampler, IN.uv0 ) * IN.color;

    return OUT;
}

//-----------------------------------------------------------------------------
// Effects
//-----------------------------------------------------------------------------

technique effect0
{
    pass Pass0
    {
		VertexShader = compile vs_2_0 v_shader();
		PixelShader  = compile ps_2_0 p_shader();
    }
}



Here's my shader wrapper.
/************************************************************************
*    FILE NAME:       shader.cpp
*
*    DESCRIPTION:     shader class singleton
************************************************************************/

// Standard lib dependencies
#include <assert.h>

// Game lib dependencies
#include "genfunc.h"
#include "xwindow.h"

// Physical component dependency
#include "shader.h"

// Required namespace(s)
using namespace std;

/************************************************************************
*    desc:  Constructer                                                             
************************************************************************/
CShader::CShader()
       : pActiveShader(NULL),
	     hLightType(NULL),
		 hLightPos(NULL),
		 hLightDif(NULL),
		 hLightEnable(NULL),
		 hLightRad(NULL),
		 hEnableLights(NULL),
		 hAmbient(NULL),
		 hMaterial(NULL),
		 hWorldMatrix(NULL),
		 hWorldMatrixTranspose(NULL),
		 hWorldViewProjMatrix(NULL)
{
}   // Constructer


/************************************************************************
*    desc:  Destructer                                                             
************************************************************************/
CShader::~CShader()
{
    // Release the materials
	DeleteMapDirectXPointers( effectsLst );

}   // Destructer


/************************************************************************
*    desc:  Get the instance of the shader singleton class                                                             
************************************************************************/
CShader & CShader::Instance()
{
    static CShader shader;

    return shader;
}


/************************************************************************
*    desc:  Load the shader from file path
*  
*    param: string & filePath - path to shader fx file
*    param: string & idStr - Name id for this shader
* 
*    return: bool - true on success or false on fail
************************************************************************/
bool CShader::LoadFromFile( string & filePath, string & idStr )
{
	HRESULT hr;

    // See if this shader has already been loaded
    map<string, LPD3DXEFFECT>::iterator iter = effectsLst.find( idStr );

    // If it's not found, load the shader and add it to the list
    if( iter == effectsLst.end() )
    {
        LPD3DXEFFECT pShader = NULL;
		LPD3DXBUFFER pBufferError = NULL;

        // Try to load the shader into memory
        if( FAILED( hr = D3DXCreateEffectFromFile( CXWindow::Instance().GetXDevice(),
							  filePath.c_str(),
							  NULL,
							  NULL,
							  D3DXFX_NOT_CLONEABLE,
                              NULL,
							  &pShader,
							  &pBufferError ) ) )
		{
			PostMsg( "Load Shader Error",
					 "Error creating shader. %s", pBufferError->GetBufferPointer() );

			return false;
		}

        // Add the material to our list
        effectsLst.insert(make_pair(idStr, pShader));
    }

	return true;

}	// LoadFromFile


/************************************************************************
*    desc:  Set the active shader
*  
*    param: string & idStr - path to shader fx file
* 
*    return: bool - true on success or false on fail
************************************************************************/
bool CShader::SetActiveShader( string & idStr )
{
	// See if this shader has already been loaded
    map<string, LPD3DXEFFECT>::iterator iter = effectsLst.find( idStr );

	// re-init the handles
	hLightType = NULL;
	hLightPos = NULL;
	hLightDif = NULL;
	hLightEnable = NULL;
	hLightRad = NULL;
	hEnableLights = NULL;
	hAmbient = NULL;
	hMaterial = NULL;
	hWorldMatrix = NULL;
	hWorldMatrixTranspose = NULL;
	hWorldViewProjMatrix = NULL;

	// If it's not found, set the pointer
    if( iter != effectsLst.end() )
	{
		pActiveShader = iter->second;

		// Get the handle to the global shader variables
		hLightType = pActiveShader->GetParameterByName( NULL, "lightType" );
		hLightPos = pActiveShader->GetParameterByName( NULL, "lightPos" );
		hLightDif = pActiveShader->GetParameterByName( NULL, "lightDif" );
		hLightEnable = pActiveShader->GetParameterByName( NULL, "lightEnable" );
		hLightRad = pActiveShader->GetParameterByName( NULL, "lightRadius" );
		hEnableLights = pActiveShader->GetParameterByName( NULL, "enableLights" );
		hAmbient = pActiveShader->GetParameterByName( NULL, "ambient" );
		hMaterial = pActiveShader->GetParameterByName( NULL, "material" );

		hWorldMatrix = pActiveShader->GetParameterByName( NULL, "worldMatrix" );
		hWorldMatrixTranspose = pActiveShader->GetParameterByName( NULL, "worldMatrixTranspose" );
		hWorldViewProjMatrix = pActiveShader->GetParameterByName( NULL, "worldViewProjMatrix" );

		return true;
	}

	assert(!("Shader Not Found!"));

	return false;

}	// SetActiveShader


/************************************************************************
*    desc:  Set the lighting
*  
*    param: CLightLst & lightLst - lighting list
************************************************************************/
void CShader::SetLighting( CLightLst & lightLst )
{
	if( pActiveShader != NULL )
	{
		if( hLightPos != NULL && hLightDif != NULL && hLightEnable != NULL && hLightRad != NULL && hLightType != NULL )
		{
			INT lightType[MAX_LIGHTS];
			D3DXVECTOR4 lightPos[MAX_LIGHTS];
			D3DXVECTOR4 lightDif[MAX_LIGHTS];
			FLOAT lightRadius[MAX_LIGHTS];
			BOOL lightEnable[MAX_LIGHTS];

			ZeroMemory( lightEnable, sizeof(lightEnable) );

			for( unsigned int i = 0; i < lightLst.GetCount(); i++ )
			{
				CPoint pos = lightLst.GetLight(i)->GetPos();
				float * diffuse = lightLst.GetLight(i)->diffuse;

				if( lightLst.GetLight(i)->type == ELT_DIRECTIONAL )
				{
					pos = lightLst.GetLight(i)->dir;
				}

				lightPos[i].x = pos.x;
				lightPos[i].y = pos.y;
				lightPos[i].z = pos.z;
				lightPos[i].w = 0.f;

				lightDif[i].x = diffuse[0];
				lightDif[i].y = diffuse[1];
				lightDif[i].z = diffuse[2];
				lightDif[i].w = 1.f;

				lightEnable[i] = lightLst.GetLight(i)->enable;
				lightRadius[i] = lightLst.GetLight(i)->radius;
				lightType[i] = lightLst.GetLight(i)->type;
			}

			// Copy the data to the shader
			pActiveShader->SetIntArray( hLightType, &lightType[0], lightLst.GetCount() );
			pActiveShader->SetVectorArray( hLightPos, &lightPos[0], lightLst.GetCount() );
			pActiveShader->SetVectorArray( hLightDif, &lightDif[0], lightLst.GetCount() );
			pActiveShader->SetBoolArray( hLightEnable, &lightEnable[0], MAX_LIGHTS );
			pActiveShader->SetFloatArray( hLightRad, &lightRadius[0], lightLst.GetCount() );
		}
	}

}	// SetLighting


/************************************************************************
*    desc:  Set the light pos
*  
*    param: CLightLst & lightLst - lighting list
************************************************************************/
void CShader::SetLightPos( CLightLst & lightLst )
{
	if( pActiveShader != NULL && hLightPos != NULL )
	{
		D3DXVECTOR4 lightPos[MAX_LIGHTS];

		for( unsigned int i = 0; i < lightLst.GetCount(); i++ )
		{
			CPoint pos = lightLst.GetLight(i)->GetPos();

			if( lightLst.GetLight(i)->type == ELT_DIRECTIONAL )
			{
				pos = lightLst.GetLight(i)->dir;
			}

			lightPos[i].x = pos.x;
			lightPos[i].y = pos.y;
			lightPos[i].z = pos.z;
			lightPos[i].w = 0.f;
		}

		// Copy the data to the shader
		pActiveShader->SetVectorArray( hLightPos, &lightPos[0], lightLst.GetCount() );
	}

}	// SetLightPos


/************************************************************************
*    desc:  Set the light radius
*  
*    param: CLightLst & lightLst - lighting list
************************************************************************/
void CShader::SetLightRadius( CLightLst & lightLst )
{
	if( pActiveShader != NULL && hLightRad != NULL )
	{
		FLOAT lightRadius[MAX_LIGHTS];

		for( unsigned int i = 0; i < lightLst.GetCount(); i++ )
		{
			lightRadius[i] = lightLst.GetLight(i)->radius;
		}

		// Copy the data to the shader
		pActiveShader->SetFloatArray( hLightRad, &lightRadius[0], lightLst.GetCount() );
	}

}	// SetLightRadius


/************************************************************************
*    desc:  Set the enabled lights
*  
*    param: CLightLst & lightLst - lighting list
************************************************************************/
void CShader::SetLightEnable( CLightLst & lightLst )
{
	if( pActiveShader != NULL && hLightEnable != NULL )
	{
		BOOL lightEnable[MAX_LIGHTS];
		ZeroMemory( lightEnable, sizeof(lightEnable) );

		for( unsigned int i = 0; i < lightLst.GetCount(); i++ )
		{
			lightEnable[i] = lightLst.GetLight(i)->enable;
		}

		// Copy the data to the shader
		pActiveShader->SetBoolArray( hLightEnable, &lightEnable[0], MAX_LIGHTS );
	}

}	// SetLightEnable


/************************************************************************
*    desc:  global enable for all lights
*  
*    param: CLightLst & lightLst - lighting list
************************************************************************/
void CShader::EnableLighting( bool value )
{
	if( pActiveShader != NULL && hEnableLights != NULL )
	{
		// Get the handle to the light arrays
		pActiveShader->SetBool( hEnableLights, value );
	}

}	// EnableLighting


/************************************************************************
*    desc:  Invert the z of the lighting
*  
*    param: CLightLst & lightLst - lighting list
*    param: float value - Set to 1.0 or -1.0 to invert
************************************************************************/
void CShader::InvertZLighting( CLightLst & lightLst, float value )
{
	if( pActiveShader != NULL && hLightPos != NULL )
	{
		D3DXVECTOR4 lightPos[MAX_LIGHTS];

		for( unsigned int i = 0; i < lightLst.GetCount(); i++ )
		{
			CPoint pos = lightLst.GetLight(i)->GetPos();

			if( lightLst.GetLight(i)->type == ELT_DIRECTIONAL )
			{
				pos = lightLst.GetLight(i)->dir;
			}

			lightPos[i].x = pos.x;
			lightPos[i].y = pos.y;
			lightPos[i].z = pos.z;
			lightPos[i].w = 0.f;

			// Don't invert the z for directional lights
			if( lightLst.GetLight(i)->type == ELT_POINT_INFINITE ||
				lightLst.GetLight(i)->type == ELT_POINT_RADIUS )
			{
				lightPos[i].z *= value;
			}
		}

		// Copy the data to the shader
		pActiveShader->SetVectorArray( hLightPos, &lightPos[0], lightLst.GetCount() );
	}

}	// InvertZLighting


/************************************************************************
*    desc:  Set the ambient color
************************************************************************/
void CShader::SetAmbient( float r, float g, float b )
{
	if( pActiveShader != NULL && hAmbient != NULL )
	{
		pActiveShader->SetVector( hAmbient, &D3DXVECTOR4( r, g, b, 1.f) );
	}

}	// SetAmbient


/************************************************************************
*    desc:  Set the material
************************************************************************/
void CShader::SetMaterial( LPDIRECT3DTEXTURE9 pMaterial )
{
	if( pActiveShader != NULL && hMaterial != NULL )
	{
		pActiveShader->SetTexture( hMaterial, pMaterial );
	}

}	// SetMaterial


/************************************************************************
*    desc:  Set the matrix
************************************************************************/
void CShader::SetMatrix( D3DXMATRIX & worldMatrix, D3DXMATRIX & worldViewProjMatrix )
{
	if( pActiveShader != NULL )
	{
		pActiveShader->SetMatrix( "worldMatrix", &worldMatrix );
		pActiveShader->SetMatrixTranspose( "worldMatrixTranspose", &worldMatrix );
		pActiveShader->SetMatrix( "worldViewProjMatrix", &worldViewProjMatrix );

		/*if( hWorldMatrix != NULL )
		{
			pActiveShader->SetMatrix( hMaterial, &worldMatrix );
		}

		if( hWorldMatrixTranspose != NULL )
		{
			pActiveShader->SetMatrixTranspose( hWorldMatrixTranspose, &worldMatrix );
		}

		if( hWorldViewProjMatrix != NULL )
		{
			pActiveShader->SetMatrix( hWorldViewProjMatrix, &worldViewProjMatrix );
		}*/
	}

}	// SetMatrix


/************************************************************************
*    desc:  Get the active shader
* 
*    return: LPD3DXEFFECT - pointer to shader effect
************************************************************************/
LPD3DXEFFECT CShader::GetActiveShader()
{
	if( pActiveShader != NULL )
	{
		return pActiveShader;
	}
	else
	{
		assert(!("Active Shader Not Set!"));
		return NULL;
	}

}	// GetActiveShader


/************************************************************************
*    desc:  Disable the active shader
************************************************************************/
void CShader::DisableActiveShader()
{
	pActiveShader = NULL;

}	// DisableActiveShader


/************************************************************************
*    desc:  Is a shader active
* 
*    return: bool - true if shader is active
************************************************************************/
bool CShader::IsShaderActive()
{
	return (pActiveShader != NULL);
}



[Edited by - howie_007 on March 18, 2010 7:16:06 PM]

Share this post


Link to post
Share on other sites

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