Pixel shader only outputs alpha

Started by
11 comments, last by BattleMetalChris 13 years, 1 month ago
This is my pixel shader, it takes a number of point lights and applies diffuse lighting to the mesh:

float4 PS( VS_OUTPUT input ) : SV_Target
{
float4 finalColour = (float4)0;
Light_Point p_light;

for (int i = 0; i < NumPointLights; i++)
{
p_light = PointLights;
float3 lightVec = (float3)input.Pos - p_light.position;

float4 ambientTerm;
float4 diffuseTerm;
float4 specularTerm;
float attenuation;
float distance = length(lightVec);

ambientTerm = Ambient;
float dotP = dot(normalize(-lightVec), input.Normal);
diffuseTerm = mul(dotP, p_light.colour); // diffuse light striking surface
diffuseTerm = mul(diffuseTerm, Diffuse);
specularTerm = (float4)0;

attenuation = 1 / (p_light.attenuation1 * pow(distance, 2) + p_light.attenuation2 * distance + p_light.attenuation3);

float4 tempColour = mul(diffuseTerm, attenuation);
finalColour = finalColour + tempColour;

}

return finalColour;

}


The problem is, no matter what finalColour is at the end, the colour of the pixel is a greyscale colour, the value of the output's alpha. So if finalColour is (0.3, 0.2, 0.1, 1.0) then the pixel ends up (1.0, 1.0, 1.0, 1.0). In desperation, I changed the end to:


finalColour = (0.0f, 0.0f, 0.0f, 1.0f);
return finalColour;


and the same thing happens. Here I get a white pixel despite the R,G and B values being 0.

Any ideas what's going on?
Advertisement
If return float4(not white) yields white, then the problem doesn't lie in your shader, so you've posted the wrong code. Post the blending code etc. instead.
I've not set any kind of blending, anywhere. It should just write straight to the backbuffer.
Of course it should. Post some other code then, or better try using PIX to debug a pixel that gets the wrong color. If you can replace your shader with another that only does "return float4(1.0f, 0.0f, 0.0f, 1.0f)" and it's still white it obviously has nothing to do with the shader.
I'm not really sure what else to post :unsure:

I've used PIX to debug the shader. The colour that gets written just seems to be different to the colour returned by the pixel shader - running through the shader in PIX's debugger shows everything in the shader working fine.


Here's how I set up the device:


void DX10Renderer::initialise()
{
// create swap chain

DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory( &scd, sizeof( scd ) );
scd.BufferCount = 1;

scd.BufferDesc.Width = m_width;
scd.BufferDesc.Height = m_height;
scd.BufferDesc.RefreshRate.Numerator = 60;
scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
//scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
//scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

scd.SampleDesc.Count = 1;
scd.SampleDesc.Quality = 1;

scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = m_hWnd;
scd.Windowed = true;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = 0;

// create device

HRESULT result;
UINT createDeviceFlags = 0;

#if defined(DEBUG) || defined(_DEBUG)
createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
#endif

result = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, D3D10_SDK_VERSION, &scd, &m_swapChain, &m_d3dDevice);
DXerror(result);

D3D10_RASTERIZER_DESC rasterizerState;
rasterizerState.CullMode = D3D10_CULL_BACK;
rasterizerState.FillMode = D3D10_FILL_SOLID;
rasterizerState.FrontCounterClockwise = true;
rasterizerState.DepthBias = false;
rasterizerState.DepthBiasClamp = 0;
rasterizerState.SlopeScaledDepthBias = 0;
rasterizerState.DepthClipEnable = true;
rasterizerState.ScissorEnable = false;
rasterizerState.MultisampleEnable = false;
rasterizerState.AntialiasedLineEnable = true;

ID3D10RasterizerState* pRS;
m_d3dDevice->CreateRasterizerState( &rasterizerState, &pRS);
m_d3dDevice->RSSetState(pRS);



// create render target

DXerror(m_swapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), reinterpret_cast<void**>(&m_backBuffer)));
DXerror(m_d3dDevice->CreateRenderTargetView(m_backBuffer, 0, &m_renderTargetView));
m_backBuffer->Release(); // need this because the call to GetBuffer adds an extra COM reference

// create depth buffer

D3D10_TEXTURE2D_DESC descDepth;
descDepth.Width = m_width;
descDepth.Height = m_height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D32_FLOAT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D10_USAGE_DEFAULT;
descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
DXerror(m_d3dDevice->CreateTexture2D( &descDepth, NULL, &m_depthBuffer ));

// Create the depth stencil view
D3D10_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
DXerror(m_d3dDevice->CreateDepthStencilView( m_depthBuffer, &descDSV, &m_depthStencilView ));

m_d3dDevice->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView);

// set viewport

D3D10_VIEWPORT vp;
vp.Height = m_height;
vp.Width = m_width;
vp.MaxDepth = 1;
vp.MinDepth = 0;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
m_d3dDevice->RSSetViewports(1, &vp);

}


Here's my draw routine


void DX10Renderer::draw(float deltaTime)
{
using rendering::Renderable;
using rendering::ShaderBase;

std::vector<Renderable>& renderables = m_resourceManager->getRenderables();
std::vector<Light>& lights = m_resourceManager->getAllLights();

assignLights(renderables, lights);

const FLOAT clearColour[4] = {0.0f, 0.0f, 0.0f, 1.0f};
m_d3dDevice->ClearRenderTargetView(m_renderTargetView, clearColour);
m_d3dDevice->ClearDepthStencilView( m_depthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0 );

int shaderID = -1;
int materialID = -1;
int meshID = -1;
for (std::vector<Renderable>::iterator it = renderables.begin(); it != renderables.end(); ++it)
{
if (it->shaderID() != shaderID) shaderID = it->updatePerShader(&m_viewMatrix, &m_projMatrix);
if (it->materialID() != materialID) materialID = it->updatePerMaterial();
if (it->meshID() != meshID) meshID = it->updatePerMesh();

D3DXMATRIX rotate;
D3DXMatrixRotationY(&rotate, deltaTime);
rotate = it->getWorldMatrix() * rotate;
it->setWM(rotate);

ID3D10EffectTechnique* technique;
D3D10_TECHNIQUE_DESC techDesc;
technique = it->getTechnique();

technique->GetDesc( &techDesc );

UINT offset = 0;

for ( UINT p = 0; p < techDesc.Passes; p++)
{
technique->GetPassByIndex( p )->Apply(0);
m_d3dDevice->DrawIndexed( it->meshIndices(), 0, 0 );
}
}

m_swapChain->Present(0, 0);

}


And here's the entire .fx file it's using:


//--------------------------------------------------------------------------------------
// File: Tutorial02.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------

struct VS_OUTPUT
{
float4 PosH : SV_POSITION;
float4 Color : COLOR0;
float3 Normal : TEXCOORD0;
float3 Pos : TEXCOORD1;
};

struct Light_Point
{
float attenuation1;
float attenuation2;
float attenuation3;
float3 position;
float4 colour;
};

struct Light_Parallel
{
float3 direction;
float4 colour;
};

struct Light_Spot
{
float attenuation1;
float attenuation2;
float attenuation3;
float3 position;
float4 colour;
float3 direction;
float coneAngle1;
float coneAngle2;
};

cbuffer matrices
{
matrix WorldMatrix;
matrix ViewMatrix;
matrix ProjectionMatrix;
};

cbuffer surfaceProperties
{
float4 Diffuse;
float4 Ambient;
float4 Specular;
};

cbuffer lights
{
Light_Point PointLights[3];
Light_Parallel ParallelLights[3];
Light_Spot SpotLights[3];
int NumPointLights;
int NumParallelLights;
int NumSpotLights;

};


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS( float4 Pos : POSITION , float4 Color : COLOR, float3 Normal : NORMAL)
{
matrix WorldView = mul(WorldMatrix, ViewMatrix); // so we don't have to calculate it twice
VS_OUTPUT output = (VS_OUTPUT)0;

output.Pos = (float3)Pos;

output.PosH = mul(Pos, WorldView);
output.PosH = mul(output.PosH, ProjectionMatrix);

output.Color = Color;

output.Normal = mul(Normal, WorldView);

return output;
}


//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( VS_OUTPUT input ) : SV_Target
{
float4 finalColour = (float4)0;
Light_Point p_light;

for (int i = 0; i < NumPointLights; i++)
{
p_light = PointLights;
float3 lightVec = (float3)input.Pos - p_light.position;

float4 ambientTerm;
float4 diffuseTerm;
float4 specularTerm;
float attenuation;
float distance = length(lightVec);

ambientTerm = Ambient;
float dotP = dot(normalize(-lightVec), input.Normal);
diffuseTerm = mul(dotP, p_light.colour); // diffuse light striking surface
diffuseTerm = mul(diffuseTerm, Diffuse);
specularTerm = (float4)0;

attenuation = 1 / (p_light.attenuation1 * pow(distance, 2) + p_light.attenuation2 * distance + p_light.attenuation3);

float4 tempColour = mul(diffuseTerm, attenuation);
finalColour = finalColour + tempColour;

}
finalColour = (0.0f, 0.0f, 0.0f, 1.0f);
return finalColour;

}


//--------------------------------------------------------------------------------------
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}


Apart from the code to create the vertex and index buffers for the mesh, they're the only parts that involve the directx device. Before I posted here I thought it might be a blending issue, but as I said, I don't set blending states anywhere at all in the code, so it should just use the default.
Hmm, here's something interesting:

This is the asm code of the shader from PIX:


// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022
//
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// ---------------- ----- ------ -------- -------- ------ ------
// SV_POSITION 0 xyzw 0 POS float
// COLOR 0 xyzw 1 NONE float
// TEXCOORD 0 xyz 2 NONE float
// TEXCOORD 1 xyz 3 NONE float
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// ---------------- ----- ------ -------- -------- ------ ------
// SV_Target 0 xyzw 0 NONE float xyzw
//
ps_4_0
dcl_output o0.xyzw
mov o0.xyzw, l(1.000000, 1.000000, 1.000000, 1.000000)
ret
// Approximately 2 instruction slots used



Note the colour being output here, it's not the same as in the source which, as I posted before, is currently


finalColour = (0.0f, 0.0f, 0.0f, 1.0f);
return finalColour;
If you comment out the entire shader and just do return float4(1.0f, 0.0f, 0.0f, 1.0f) does it still get white?


I've used PIX to debug the shader. The colour that gets written just seems to be different to the colour returned by the pixel shader - running through the shader in PIX's debugger shows everything in the shader working fine.[/quote]

Did you right-click a pixel in the render view and select debug pixel so you get a list of every write to the pixel?
Is there anything other than Initial frambuffer value and a Draw call that outputs the color?
Is the color there also white, or just on the screen?
Usually in PIX the SysValue for SV_Target is TARGET, not NONE as in your case..
Check all the warnings that you get from compiling your shader, and definitely try replacing the entire shader with return single color, and not leaving the whole thing in there. Perhaps compilation fails.
HLSL Comma operator
That comma thing helped, thanks, 'return float4(1.0f, 0.0f, 0.0f,1.0f)' displays red pixels, so that's working at least.

I'm not sure where in my original shader code that's happening though.

This topic is closed to new replies.

Advertisement