Advertisement

HLSL Addition of two float4 yields zero

Started by August 10, 2019 08:15 PM
14 comments, last by VanillaSnake21 5 years, 5 months ago

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?

 

 

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

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.

Advertisement
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.

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

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?

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.

 

 

 

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

@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);

 

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

Advertisement

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.

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

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.

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?

You didn't come into this world. You came out of it, like a wave from the ocean. You are not a stranger here. -Alan Watts

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.

This topic is closed to new replies.

Advertisement