Jump to content
  • Advertisement
VanillaSnake21

DX11 HLSL Addition of two float4 yields zero

Recommended Posts

I'm running into a somewhat unexpected situation while trying to get my lighting to work in the vertex shader. I'm getting black color throughought the frame for some reason and I've decided to run it through the graphics debugger. What I found was that for some reason when I have two valid float4, one being float4(0.57, 0.57, 0.57, 1.0) and the other being (0.0, 0.0, 0.0, 0.0) when I add them I _sometimes_ get zero as a result. I will show what I mean in the video below.

 

(Read this after you watch the video) You can see when I run the shader on individual vertices of a triangle then on the first vertex of the triangle the result comes back as it should, on the second and third vertices though the result comes back as zero. Why is that?

 

 

Share this post


Link to post
Share on other sites
Advertisement
Posted (edited)

Have you tried using a different graphics card? I can't see why it should do that, maybe it is just broken. Or try a different driver - I have found a bug in AMD's graphics driver so it is not completely impossible that you may stumble upon one, too.

You can also try cleaning and rebuilding the solution.

If that doesn't solve the problem, please post the code here. I've only seen parts of it in the video. What I've seen appeared to be correct though.

Edited by Magogan

Share this post


Link to post
Share on other sites
44 minutes ago, Magogan said:

Have you tried using a different graphics card? I can't see why it should do that, maybe it is just broken. Or try a different driver - I have found a bug in AMD's graphics driver so it is not completely impossible that you may stumble upon one, too.

You can also try cleaning and rebuilding the solution.

If that doesn't solve the problem, please post the code here. I've only seen parts of it in the video. What I've seen appeared to be correct though.

It's an nvidia card, and no I don't have another one. I think that's like the last case scenario though, as it's highly unlikely that my trivial meddling with this 6 line shader is exposing a fault after having run numerous commercial games successfully.

Share this post


Link to post
Share on other sites
Posted (edited)

Yeah, it's unlikely. But it's equally unlikely that 0 + 0.57 = 0. The debugger might just show the wrong values. Is the ID3D11Device created in debug mode (a flag for the CreateDevice(AndSwapChain) method)? Are the shaders compiled in debug mode? Is the program running in debug mode?

Edited by Magogan

Share this post


Link to post
Share on other sites
8 minutes ago, Magogan said:

Yeah, it's unlikely. But it's equally unlikely that 0 + 0.57 = 0. The debugger might just show the wrong values. Is the ID3D11Device created in debug mode (a flag for the CreateDevice(AndSwapChain) method)? Are the shaders compiled in debug mode? Is the program running in debug mode?

Everything is in debug mode. It might be that the debugger showing the wrong values but nevertheless the out.color is still coming back black.

 

The thing is that if I remove the the summation then it works 

As in instead of doing

 Finalcolor = (diffuse + specular) * lightcolor 

 

If I just do

 finalcolor = diffuse * lightcolor 

 

It works and the scene renders as it should with proper diffuse lighting.

 

But I've made it so specular should always be zero anyways so it makes no sense why adding a zero specular to non zero diffuse produces a result of zero.

I'm also not sure if it's connected in any way but if you see in the video as I hover over the variables the last component of the vector (the w) is "not in scope".

 

Another thing which might be related is that I'm passing the material properties via a constant buffer.

Then the diffuse is calculated as such

Float4 diffuse = matDiffuse × saturate(dot(norm, lightdir)); 

The matDiffuse is passed through a constant buffer which looks like this

	Cbuffer material{
	Float4 matDiffuse;
	Float4 matSpecular;
	Float4 matAmbient;
	} 

 

Could it be that the buffer is somehow corrupt.

I'm on my phone just typing this up from mem, I'll post some full code shortly.

 

 

 

Share this post


Link to post
Share on other sites
Posted (edited)

@Magogan

This is the shader code:

cbuffer ProjectionMatrices : register (b0)
{
	
	matrix View;
	matrix Projection;
}

cbuffer WorldMatrices : register (b1)
{
	matrix World;
}


cbuffer CameraPosition : register (b5)
{
	float3 EyePosition;
};

cbuffer DirectionalLight : register (b2)
{
	float3 LightDirection;
	float4 LightColor;
};

cbuffer LightingVariables : register (b4)
{
	float4 AmbientLight;
};

cbuffer Material : register (b3)
{
	float Ka, Kd, Ks, A;
};

struct TexturedLitVertex
{
	float4 Pos :   SV_POSITION;
	float4 Color:  COLOR;
	float2 Uv:     TEXCOORD;
};

float4 calcBlinnPhongLighting(float MaterialKa, float MaterialKd, float MaterialKs, float MaterialA, float4 LColor, float3 N, float3 L, float3 H)
{
	float4 Ia = MaterialKa * AmbientLight;
	float4 Id = MaterialKd * saturate(dot(N, L));
	float4 Is = MaterialKs * pow(saturate(dot(N, H)), MaterialA);


	float4 finalColor = Ia + (Id + Is) * LColor;
	finalColor.a = 1.0f;

	return finalColor;
}


TexturedLitVertex VS_DirectionalLight(float4 Pos : POSITION, float3 Normal : NORMAL, float2 Uv : TEXCOORD0)
{
	
	TexturedLitVertex output = (TexturedLitVertex)0;

	//transform to clip space
	output.Pos = mul(Pos, World);
	output.Pos = mul(output.Pos, View);
	output.Pos = mul(output.Pos, Projection);

	//pass on the texture coordinates
	output.Uv = Uv;

	float3 N = normalize(mul(Normal, (float3x3)World));
	float3 V = normalize(EyePosition - (float3)Pos);
	float3 H = normalize(-LightDirection + V);

	//calculate lighting intesity and interpolate it as color
	float4 LightColor2 = float4( 1.0f, 1.0f, 1.0f, 1.0f );
	output.Color = calcBlinnPhongLighting(Ka, Kd, Ks, A, LightColor2, N, LightDirection, H);

	return output;
}

float4 PS_DirectionalLight(TexturedLitVertex psInput) : SV_Target
{
	

	return psInput.Color *txDiffuse.Sample(triLinearSampler, psInput.Uv);
}

 

Also just to note, this issue might stem from the constant buffers. I'm not sure I'm using them correctly, I have like 7 of them for each variable pretty much and one of the buffers doesn't really work. The LightColor parameter in the DirectionLight is always incorrect, that is why I just resorted to setting it manually in the code for now (the float4 LightColor2 parameter). Just in case I'll post my code for how I manage related constant buffers in my code

 

__declspec(align(16)) struct DirectionalLight
	{
		DirectX::XMFLOAT3 LightDirection;
		DirectX::XMFLOAT4 LightColor;

	};

	__declspec(align(16)) struct ProjectionVariables
	{
		
		DirectX::XMMATRIX View;
		DirectX::XMMATRIX Projection;
	};

	__declspec(align(16)) struct WorldMatrices
	{
		DirectX::XMMATRIX World;
	};

	__declspec(align(16)) struct LightVariables
	{
		DirectX::XMFLOAT4 AmbientLight;
	};

	__declspec(align(16)) struct CameraPosition
	{
		DirectX::XMFLOAT3 EyePosition;
	};

	__declspec(align(16)) struct Material
	{
		float Ka;
		float Kd;
		float Ks;
		float A;
	};

void InitAll(ID3D11Device* device)
	{
		//create buffers
		D3D11_BUFFER_DESC bufferDesc;
		bufferDesc.Usage = D3D11_USAGE_DEFAULT;
		bufferDesc.ByteWidth = sizeof(ProjectionVariables);
		bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		bufferDesc.CPUAccessFlags = 0;
		bufferDesc.MiscFlags = 0;
		bufferDesc.StructureByteStride = 0;
		device->CreateBuffer(&bufferDesc, NULL, &ViewProjBuffer);

		bufferDesc.ByteWidth = sizeof(WorldMatrices);
		device->CreateBuffer(&bufferDesc, NULL, &WorldMatrixBuffer);

		bufferDesc.ByteWidth = sizeof(DirectionalLight);
		device->CreateBuffer(&bufferDesc, NULL, &DirectionalLightBuffer);

		bufferDesc.ByteWidth = sizeof(LightVariables);
		device->CreateBuffer(&bufferDesc, NULL, &LightVariablesBuffer);

		bufferDesc.ByteWidth = sizeof(CameraPosition);
		device->CreateBuffer(&bufferDesc, NULL, &CameraPositionBuffer);

		bufferDesc.ByteWidth = sizeof(Material);
		device->CreateBuffer(&bufferDesc, NULL, &MaterialBuffer);

		//bind all the buffers to a device
		ID3D11DeviceContext* deviceContext;
		device->GetImmediateContext(&deviceContext);

		deviceContext->VSSetConstantBuffers(0, 1, &ViewProjBuffer);
		deviceContext->PSSetConstantBuffers(0, 1, &ViewProjBuffer);

		deviceContext->VSSetConstantBuffers(1, 1, &WorldMatrixBuffer);
		deviceContext->PSSetConstantBuffers(1, 1, &WorldMatrixBuffer);


		deviceContext->VSSetConstantBuffers(2, 1, &DirectionalLightBuffer);
		deviceContext->PSSetConstantBuffers(2, 1, &DirectionalLightBuffer);


		deviceContext->VSSetConstantBuffers(3, 1, &MaterialBuffer);
		deviceContext->PSSetConstantBuffers(3, 1, &MaterialBuffer);


		deviceContext->VSSetConstantBuffers(4, 1, &LightVariablesBuffer);
		deviceContext->PSSetConstantBuffers(4, 1, &LightVariablesBuffer);


		deviceContext->VSSetConstantBuffers(5, 1, &CameraPositionBuffer);
		deviceContext->PSSetConstantBuffers(5, 1, &CameraPositionBuffer);

		
	}

//then I update them in code

	ConstantBuffers::WorldMatrices worldBuffer;
	worldBuffer.World = XMMatrixIdentity();
	mDeviceContext->UpdateSubresource(ConstantBuffers::WorldMatrixBuffer, 0, NULL, &worldBuffer, 0, 0);

	ConstantBuffers::Material material;
	material.Ka = 0.0f;
	material.Kd = 1.0f;
	material.Ks = 0.0f;
	material.A =  0.0f;
	mDeviceContext->UpdateSubresource(ConstantBuffers::MaterialBuffer, 0, NULL, &material, 0, 0);


	ConstantBuffers::ProjectionVariables projectionMatrices;
	projectionMatrices.View = XMMatrixTranspose(mCharacterController->GetCamera().GetViewMatrix());
	projectionMatrices.Projection = XMMatrixTranspose(mCharacterController->GetCamera().GetProjectionMatrix());
	mDeviceContext->UpdateSubresource(ConstantBuffers::ViewProjBuffer, 0, NULL, &projectionMatrices, 0, 0);

	ConstantBuffers::CameraPosition eyePos;
	eyePos.EyePosition = mCharacterController->GetCamera().GetPosition();
	mDeviceContext->UpdateSubresource(ConstantBuffers::CameraPositionBuffer, 0, NULL, &eyePos, 0, 0);

	ConstantBuffers::DirectionalLight dirLight;
	XMVECTOR ldir = { -0.577f, 0.577f, -0.577f };
	ldir = XMVector3Normalize(ldir);
	XMStoreFloat3(&dirLight.LightDirection, ldir);
	dirLight.LightColor = XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f );
	mDeviceContext->UpdateSubresource(ConstantBuffers::DirectionalLightBuffer, 0, NULL, &dirLight, 0, 0);


	ConstantBuffers::LightVariables lightVars;
	lightVars.AmbientLight = { 1.0f, 1.0f, 1.0f, 1.0f };
	mDeviceContext->UpdateSubresource(ConstantBuffers::LightVariablesBuffer, 0, NULL, &lightVars, 0, 0);

 

Edited by VanillaSnake21

Share this post


Link to post
Share on other sites

Ok, I think I found the issue. 

In the line 

 float4 Is = MaterialKs * pow(saturate(dot(N, H)), MaterialA); 

I'm actually passing in 0 for MatrialA, which as I'm looking over it is the power. I've tried passing in 1 for the power and the issue disappeared. I'm actually not sure why that is, I thought power of zero would just give me a result of 1, but apparently something else was going on. Anyways, thanks.

Share this post


Link to post
Share on other sites
Posted (edited)

0^0 is undefined.

4-component vectors in a constant buffer need to be aligned to 16 bytes and the buffer needs to be a multiple of 16 bytes in size (which is guaranteed by __declspec(align(16))). Simple add a float as padding between the two variables to achieve that.

Edited by Magogan

Share this post


Link to post
Share on other sites
13 hours ago, Magogan said:

0^0 is undefined.

 

 

Yea, 0^0 is undefined

pow(saturate(dot(N, H)), MaterialA); 

but a dot(N,H) would never really have been zero in my case, so it was always some value raised to zero which should have produced one.

Quote

4-component vectors in a constant buffer need to be aligned to 16 bytes and the buffer needs to be a multiple of 16 bytes in size (which is guaranteed by __declspec(align(16))). Simple add a float as padding between the two variables to achieve that.

What structure are you referring to that I should add a float as padding?

Share this post


Link to post
Share on other sites
23 minutes ago, VanillaSnake21 said:

 

Yea, 0^0 is undefined


pow(saturate(dot(N, H)), MaterialA); 

but a dot(N,H) would never really have been zero in my case, so it was always some value raised to zero which should have produced one.

You do realize that the dot product can be negative and saturate clamps it to the interval from 0 to 1, so it would be 0?

24 minutes ago, VanillaSnake21 said:

What structure are you referring to that I should add a float as padding?

The one that is not working (light color). Just make it float3, float, float4 in that order.

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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!