Issues with HLSL and lighting
I am trying figure out whats going on with my HLSL code but I have no way of debugging it cause C++ gives off no errors. The application just closes when I run it. I am trying to add lighting to a 3d plane I made. below is my HLSL. The problem consist when my Pixel shader method returns the struct "outColor" . If I change the return value back to the struct "psInput" , everything goes back to working again. My light vectors and colors are at the top of the fx file
// PS_INPUT - input variables to the pixel shader
// This struct is created and fill in by the
// vertex shader
cbuffer Variables
{
matrix Projection;
matrix World;
float TimeStep;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
float3 Normal : TEXCOORD0;
float3 ViewVector : TEXCOORD1;
};
float specpower = 80.0f;
float3 camPos = float3(0.0f, 9.0, -256.0f);
float3 DirectLightColor = float3(1.0f, 1.0f, 1.0f);
float3 DirectLightVector = float3(0.0f, 0.602f, 0.70f);
float3 AmbientLightColor = float3(1.0f, 1.0f, 1.0f);
/***************************************
* Lighting functions
***************************************/
/*********************************
* CalculateAmbient -
* inputs -
* vKa material's reflective color
* lightColor - the ambient color of the lightsource
* output - ambient color
*********************************/
float3 CalculateAmbient(float3 vKa, float3 lightColor)
{
float3 vAmbient = vKa * lightColor;
return vAmbient;
}
/*********************************
* CalculateDiffuse -
* inputs -
* material color
* The color of the direct light
* the local normal
* the vector of the direct light
* output - difuse color
*********************************/
float3 CalculateDiffuse(float3 baseColor, float3 lightColor, float3 normal, float3 lightVector)
{
float3 vDiffuse = baseColor * lightColor * saturate(dot(normal, lightVector));
return vDiffuse;
}
/*********************************
* CalculateSpecular -
* inputs -
* viewVector
* the direct light vector
* the normal
* output - specular highlight
*********************************/
float CalculateSpecular(float3 viewVector, float3 lightVector, float3 normal)
{
float3 vReflect = reflect(lightVector, normal);
float fSpecular = saturate(dot(vReflect, viewVector));
fSpecular = pow(fSpecular, specpower);
return fSpecular;
}
/*********************************
* LightingCombine -
* inputs -
* ambient component
* diffuse component
* specualr component
* output - phong color color
*********************************/
float3 LightingCombine(float3 vAmbient, float3 vDiffuse, float fSpecular)
{
float3 vCombined = vAmbient + vDiffuse + fSpecular.xxx;
return vCombined;
}
////////////////////////////////////////////////
// Vertex Shader - Main Function
///////////////////////////////////////////////
PS_INPUT VS(float4 Pos : POSITION, float4 Color : COLOR, float3 Normal : NORMAL)
{
PS_INPUT psInput;
float4 newPosition;
newPosition = Pos;
newPosition.y = sin((newPosition.x * TimeStep) + (newPosition.z / 3.0f)) * 5.0f;
// Pass through both the position and the color
psInput.Pos = mul(newPosition , Projection );
psInput.Color = Color;
psInput.ViewVector = normalize(camPos - psInput.Pos);
return psInput;
}
///////////////////////////////////////////////
// Pixel Shader
///////////////////////////////////////////////
//Anthony!!!!!!!!!!! Find out how color works when multiplying them
float4 PS(PS_INPUT psInput) : SV_Target
{
float3 normal = -normalize(psInput.Normal);
float3 vAmbient = CalculateAmbient(psInput.Color, AmbientLightColor);
float3 vDiffuse = CalculateDiffuse(psInput.Color, DirectLightColor, normal, DirectLightVector);
float fSpecular = CalculateSpecular(psInput.ViewVector, DirectLightVector, normal);
float4 outColor;
outColor.rgb = LightingCombine(vAmbient, vDiffuse, fSpecular);
outColor.a = 1.0f;
//Below is where the error begins
return outColor;
}
// Define the technique
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}
Below is some of my c++ code. Reason I am showing this is because it is pretty much what creates the surface normals for my shaders to evaluate. for the lighting
modelObject.numIndices = sizeof(indices) / sizeof(DWORD);
// compute normals for each face in the model
for (unsigned int i = 0; i < modelObject.numIndices; i+=3)
{
D3DXVECTOR3 v0 = vertices[indices[i]].pos;
D3DXVECTOR3 v1 = vertices[indices[i + 1]].pos;
D3DXVECTOR3 v2 = vertices[indices[i + 2]].pos;
D3DXVECTOR3 normal;
D3DXVECTOR3 cross;
D3DXVec3Cross(&am开发者_如何学Gop;cross, &D3DXVECTOR3(v2 - v0), &D3DXVECTOR3(v1 - v0));
D3DXVec3Normalize(&normal, &cross);
// assign the computed normal to each vertex in this face
vertices[indices[i]].normal = normal;
vertices[indices[i + 1]].normal = normal;
vertices[indices[i + 2]].normal = normal;
}
and below is my c++ code, in it's entirety. showing the drawing and also calling on the passes
#include "MyGame.h"
typedef struct
{
ID3D10Effect* pEffect;
ID3D10EffectTechnique* pTechnique;
//vertex information
ID3D10Buffer* pVertexBuffer;
ID3D10Buffer* pIndicesBuffer;
ID3D10InputLayout* pVertexLayout;
UINT numVertices;
UINT numIndices;
}ModelObject;
ModelObject modelObject;
// World Matrix
D3DXMATRIX WorldMatrix;
// View Matrix
D3DXMATRIX ViewMatrix;
// Projection Matrix
D3DXMATRIX ProjectionMatrix;
ID3D10EffectMatrixVariable* pProjectionMatrixVariable = NULL;
//grid information
#define NUM_COLS 16
#define NUM_ROWS 16
#define CELL_WIDTH 32
#define CELL_HEIGHT 32
#define NUM_VERTSX (NUM_COLS + 1)
#define NUM_VERTSY (NUM_ROWS + 1)
// timer variables
LARGE_INTEGER timeStart;
LARGE_INTEGER timeEnd;
LARGE_INTEGER timerFreq;
double currentTime;
float anim_rate;
// Variable to hold how long since last frame change
float lastElaspedFrame = 0;
// How long should the frames last
float frameDuration = 0.5;
bool MyGame::InitDirect3D()
{
if(!DX3dApp::InitDirect3D())
{
return false;
}
// Get the timer frequency
QueryPerformanceFrequency(&timerFreq);
float freqSeconds = 1.0f / timerFreq.QuadPart;
lastElaspedFrame = 0;
D3D10_RASTERIZER_DESC rastDesc;
rastDesc.FillMode = D3D10_FILL_WIREFRAME;
rastDesc.CullMode = D3D10_CULL_FRONT;
rastDesc.FrontCounterClockwise = true;
rastDesc.DepthBias = false;
rastDesc.DepthBiasClamp = 0;
rastDesc.SlopeScaledDepthBias = 0;
rastDesc.DepthClipEnable = false;
rastDesc.ScissorEnable = false;
rastDesc.MultisampleEnable = false;
rastDesc.AntialiasedLineEnable = false;
ID3D10RasterizerState *g_pRasterizerState;
mpD3DDevice->CreateRasterizerState(&rastDesc, &g_pRasterizerState);
//mpD3DDevice->RSSetState(g_pRasterizerState);
// Set up the World Matrix
D3DXMatrixIdentity(&WorldMatrix);
D3DXMatrixLookAtLH(&ViewMatrix, new D3DXVECTOR3(200.0f, 60.0f, -20.0f), new D3DXVECTOR3(200.0f, 50.0f, 0.0f), new D3DXVECTOR3(0.0f, 1.0f, 0.0f));
// Set up the projection matrix
D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, (float)D3DX_PI * 0.5f, (float)mWidth/(float)mHeight, 0.1f, 100.0f);
pTimeVariable = NULL;
if(!CreateObject())
{
return false;
}
return true;
}
//These are actions that take place after the clearing of the buffer and before the present
void MyGame::GameDraw()
{
static float rotationAngle = 0.0f;
// create the rotation matrix using the rotation angle
D3DXMatrixRotationY(&WorldMatrix, rotationAngle);
rotationAngle += (float)D3DX_PI * 0.0f;
// Set the input layout
mpD3DDevice->IASetInputLayout(modelObject.pVertexLayout);
// Set vertex buffer
UINT stride = sizeof(VertexPos);
UINT offset = 0;
mpD3DDevice->IASetVertexBuffers(0, 1, &modelObject.pVertexBuffer, &stride, &offset);
mpD3DDevice->IASetIndexBuffer(modelObject.pIndicesBuffer, DXGI_FORMAT_R32_UINT, 0);
pTimeVariable->SetFloat((float)currentTime);
// Set primitive topology
mpD3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Combine and send the final matrix to the shader
D3DXMATRIX finalMatrix = (WorldMatrix * ViewMatrix * ProjectionMatrix);
pProjectionMatrixVariable->SetMatrix((float*)&finalMatrix);
// make sure modelObject is valid
// Render a model object
D3D10_TECHNIQUE_DESC techniqueDescription;
modelObject.pTechnique->GetDesc(&techniqueDescription);
// Loop through the technique passes
for(UINT p=0; p < techniqueDescription.Passes; ++p)
{
modelObject.pTechnique->GetPassByIndex(p)->Apply(0);
// draw the cube using all 36 vertices and 12 triangles
mpD3DDevice->DrawIndexed(modelObject.numIndices,0,0);
}
}
//Render actually incapsulates Gamedraw, so you can call data before you actually clear the buffer or after you
//present data
void MyGame::Render()
{
// Get the start timer count
QueryPerformanceCounter(&timeStart);
currentTime += anim_rate;
DX3dApp::Render();
QueryPerformanceCounter(&timeEnd);
anim_rate = ( (float)timeEnd.QuadPart - (float)timeStart.QuadPart ) / timerFreq.QuadPart;
}
bool MyGame::CreateObject()
{
VertexPos vertices[NUM_VERTSX * NUM_VERTSY];
for(int z=0; z < NUM_VERTSY; ++z)
{
for(int x = 0; x < NUM_VERTSX; ++x)
{
vertices[x + z * NUM_VERTSX].pos.x = (float)x * CELL_WIDTH;
vertices[x + z * NUM_VERTSX].pos.z = (float)z * CELL_HEIGHT;
vertices[x + z * NUM_VERTSX].pos.y = (float)(rand() % CELL_HEIGHT);
vertices[x + z * NUM_VERTSX].color = D3DXVECTOR4(1.0, 0.0f, 0.0f, 0.0f);
}
}
DWORD indices[NUM_COLS * NUM_ROWS * 6];
int curIndex = 0;
for(int z=0; z < NUM_ROWS; ++z)
{
for(int x = 0; x < NUM_COLS; ++x)
{
int curVertex = x + (z * NUM_VERTSX);
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
curIndex += 6;
}
}
modelObject.numIndices = sizeof(indices) / sizeof(DWORD);
// compute normals for each face in the model
for (unsigned int i = 0; i < modelObject.numIndices; i+=3)
{
D3DXVECTOR3 v0 = vertices[indices[i]].pos;
D3DXVECTOR3 v1 = vertices[indices[i + 1]].pos;
D3DXVECTOR3 v2 = vertices[indices[i + 2]].pos;
D3DXVECTOR3 normal;
D3DXVECTOR3 cross;
D3DXVec3Cross(&cross, &D3DXVECTOR3(v2 - v0), &D3DXVECTOR3(v1 - v0));
D3DXVec3Normalize(&normal, &cross);
// assign the computed normal to each vertex in this face
vertices[indices[i]].normal = normal;
vertices[indices[i + 1]].normal = normal;
vertices[indices[i + 2]].normal = normal;
}
//Create Layout
D3D10_INPUT_ELEMENT_DESC layout[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT, 0 , 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT, 0 , 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL",0,DXGI_FORMAT_R32G32B32A32_FLOAT, 0 , 28, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
UINT numElements = (sizeof(layout)/sizeof(layout[0]));
modelObject.numVertices = sizeof(vertices)/sizeof(VertexPos);
//Create buffer desc
D3D10_BUFFER_DESC bufferDesc;
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(VertexPos) * modelObject.numVertices;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
//Create the buffer
HRESULT hr = mpD3DDevice->CreateBuffer(&bufferDesc, &initData, &modelObject.pVertexBuffer);
if(FAILED(hr))
return false;
bufferDesc.ByteWidth = sizeof(DWORD) * modelObject.numIndices;
bufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
initData.pSysMem = indices;
hr = mpD3DDevice->CreateBuffer(&bufferDesc, &initData, &modelObject.pIndicesBuffer);
if(FAILED(hr))
return false;
/////////////////////////////////////////////////////////////////////////////
//Set up fx files
LPCWSTR effectFilename = L"effect.fx";
modelObject.pEffect = NULL;
hr = D3DX10CreateEffectFromFile(effectFilename,
NULL,
NULL,
"fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS,
0,
mpD3DDevice,
NULL,
NULL,
&modelObject.pEffect,
NULL,
NULL);
if(FAILED(hr))
return false;
pProjectionMatrixVariable = modelObject.pEffect->GetVariableByName("Projection")->AsMatrix();
pTimeVariable = modelObject.pEffect->GetVariableByName("TimeStep")->AsScalar();
//Dont sweat the technique. Get it!
LPCSTR effectTechniqueName = "Render";
modelObject.pTechnique = modelObject.pEffect->GetTechniqueByName(effectTechniqueName);
if(modelObject.pTechnique == NULL)
return false;
//Create Vertex layout
D3D10_PASS_DESC passDesc;
modelObject.pTechnique->GetPassByIndex(0)->GetDesc(&passDesc);
hr = mpD3DDevice->CreateInputLayout(layout, numElements,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&modelObject.pVertexLayout);
if(FAILED(hr))
return false;
return true;
}
There is an application, an executable file that ships with DirectX, fxc.exe. You can use that to get rid of syntax errors in your shaders!
Try turning up the direct3d debug output. Start the directx control panel then go to the Direct3D 10 tab. Add you application to the scope list then check "Force On" in the debug layer category.
You should find that D3D gives you more debug output.
精彩评论