Jump to content
  • Advertisement
Sign in to follow this  
Nevermore6

Trouble passing multiple lights

This topic is 795 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a lightstruct in C++ which holds the color and direction of the light.

 

const int NUM_LIGHTS = 1;

struct lightStruct {
XMFLOAT4 Color;
XMFLOAT4 Direction;
};

 

And this is how I create my buffer and update it.

 

void PBRMaterial::CreateLightBuffer(ID3D11Device* device, ID3D11Buffer** lightBuffer, std::vector<lightStruct*> lightStructs){

D3D11_BUFFER_DESC cbDesc;
cbDesc.ByteWidth = sizeof(lightStruct) * NUM_LIGHTS;
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
cbDesc.StructureByteStride = 0;

D3D11_SUBRESOURCE_DATA InitData;
InitData.pSysMem = &lightStructs[0];
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;

if (FAILED(device->CreateBuffer(&cbDesc, &InitData, lightBuffer)))
{
throw GameException("ID3D11Device::CreateLightBuffer() failed.");
}
}

void PBRMaterial::SetLightBuffer(ID3D11DeviceContext* deviceContext, ID3D11Buffer** lightBuffer){

deviceContext->VSSetConstantBuffers(0, 1, lightBuffer);
}

 

On the shader side I declare my variables as such:

 

#define NUM_LIGHTS 1

struct DIRECTIONAL_LIGHT_DATA {
float4 Color;
float4 Direction;
};

cbuffer cbDirectionalLight : register(b0)
{
DIRECTIONAL_LIGHT_DATA directionalLights[NUM_LIGHTS];
};

 

Now, I don't get any errors but my shader only outputs black. I have been stuck on this for two days now and I can't come up with a solution. For debug purposes I also tried outputting the light's color directly like this:

 

OUT.rgb = directionalLights[0].Color.rgb;// ambient + diffuse + specular;
OUT.a = 1;

But that also just shows up black. Anyone have a thought on what the issue might be? Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Your lightstructs vector does not store the light data. It stores pointers to the data instead. So it should be a std::vector<lightstruct> instead of std::vector<lightstruct*>

In general for debugging you can use render doc. With this you can directly inspect if a certain buffer is set correctly or if the values are correct

Share this post


Link to post
Share on other sites

I did as you suggested and changed the vector but nothing seemed to have changed.

I also tried to use render doc but when I press F12(capture) the programm freezes... :(

Share this post


Link to post
Share on other sites

Ok another thing I noticed. In which shader are you trying to use the lights?

If it is in the Pixel Shader you are not setting the constant buffer, because you bind it only to the vertex shader with deviceContext->VSSetConstantBuffers(0, 1, lightBuffer);

Share this post


Link to post
Share on other sites

I am using the Color variable in the pixel shader and the direction variable in the vertex shader.
I got RenderDoc to work and it only shows the constant buffer which is declared on the shader side during the pixel shader pipeline state and not during the vertex shader pipeline state. This makes me think that I am trying to initialize a cbuffer which is not there.

Share this post


Link to post
Share on other sites

Did you tried to get the real information for your Constantbuffers from the ID3D11ShaderReflection interface for both vertex- and pixelshader? Maybe there are some differences.

Share this post


Link to post
Share on other sites

Ok another thing I noticed. In which shader are you trying to use the lights? If it is in the Pixel Shader you are not setting the constant buffer, because you bind it only to the vertex shader with deviceContext->VSSetConstantBuffers(0, 1, lightBuffer);

 

DaSutt is right. You don't bind the CB to the PS. 

Share this post


Link to post
Share on other sites

I am using effect files so do I then also need to create two constant buffers there or just one?
And do I then need to bind them like this?

deviceContext->VSSetConstantBuffers(0, 1, lightBuffer);
deviceContext->PSSetConstantBuffers(0, 1, lightBuffer);

just for completion, this is my entire shader

#include "include\\Common.fxh"

/************* Resources *************/
//Light
#define NUM_LIGHTS 1

struct DIRECTIONAL_LIGHT_DATA {
	float4 Color;
	float4 Direction;
};

cbuffer cbDirectionalLight : register(b0)
{
	DIRECTIONAL_LIGHT_DATA directionalLights[NUM_LIGHTS];
};
//per object
float4x4 WorldViewProjection : WORLDVIEWPROJECTION; 
float4x4 World : WORLD;

//per frame
float3 CameraPosition : CAMERAPOSITION;
float4 AmbientColor : AMBIENTCOLOR = { 1.0f, 1.0f, 1.0f, 1.0f };

//Texture(s)
Texture2D ColorTexture;
Texture2D NormalMap;
Texture2D SpecularMap;
Texture2D GlossMap;

//State Settings
RasterizerState DisableCulling { CullMode = NONE; };
SamplerState ColorSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = WRAP; AddressV = WRAP; };


/************* Data Structures *************/

struct VS_INPUT
{
	float4 ObjectPosition: POSITION;
	float2 TextureCoordinate : TEXCOORD;
	float3 Normal : NORMAL;
	float3 Tangent: TANGENT;
};

struct VS_OUTPUT 
{
    float4 Pos: SV_Position;
	float3 Normal : NORMAL;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
	float2 TextureCoordinate : TEXCOORD;
	float3 LightDirection : TEXCOORD1;
	float3 ViewDirection : TEXCOORD2;
};

/************* Vertex Shader *************/

VS_OUTPUT vertex_shader(VS_INPUT IN)
{
    VS_OUTPUT OUT = (VS_OUTPUT)0;
    
    OUT.Pos = mul(IN.ObjectPosition, WorldViewProjection);
	OUT.Normal = normalize(mul(float4(IN.Normal, 0), World).xyz);
	OUT.Tangent = normalize(mul(float4(IN.Tangent, 0), World).xyz);
	OUT.Binormal = cross(OUT.Normal, OUT.Tangent);
	OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);
	OUT.LightDirection = normalize(-directionalLights[0].Direction.xyz);
	
	float3 worldPosition = mul(IN.ObjectPosition, World).xyz;
	OUT.ViewDirection = normalize(CameraPosition - worldPosition);
    
    return OUT;
}

/************* Pixel Shader *************/

float4 pixel_shader(VS_OUTPUT IN) : SV_Target
{
	float4 OUT = (float4)0;

	float3 sampledNormal = (2 * NormalMap.Sample(ColorSampler, IN.TextureCoordinate).xyz) - 1;
	float3x3 tbn = float3x3(IN.Tangent, IN.Binormal, IN.Normal);
	sampledNormal = mul(sampledNormal, tbn);
	float3 lightDirection = normalize(IN.LightDirection);
	float3 viewDirection = normalize(IN.ViewDirection);
	float n_dot_l = dot(lightDirection, sampledNormal);

	float4 color = ColorTexture.Sample(ColorSampler, IN.TextureCoordinate);

	float3 ambient = AmbientColor.rgb * AmbientColor.a * color.rgb;

	float3 diffuse = (float3)0;
	float3 specular = (float3)0;

	if (n_dot_l > 0)
	{
		diffuse = directionalLights[0].Color.rgb * directionalLights[0].Color.a *saturate(n_dot_l) * color.rgb;

		//sampled
		float4 sampledSpecular = SpecularMap.Sample(ColorSampler, IN.TextureCoordinate);
		half smoothness = GlossMap.Sample(ColorSampler, IN.TextureCoordinate);
		float SpecularPower = pow(2, 1 + smoothness * 10);

		float3 reflectionVector = normalize(2 * n_dot_l * sampledNormal - lightDirection);

		//specular = SpecularColor.rgb * SpecularColor.a * min(pow(saturate(dot(reflectionVector, viewDirection)), SpecularPower), color.w);
		specular = sampledSpecular * min(pow(saturate(dot(reflectionVector, viewDirection)), SpecularPower), color.w);
	}

	OUT.rgb = ambient + diffuse + specular;
	OUT.a = color.a;
	return OUT;
}

/************* Techniques *************/

technique11 main11
{
    pass p0
    {
        SetVertexShader(CompileShader(vs_5_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_5_0, pixel_shader()));

        SetRasterizerState(DisableCulling);
    }
}

Share this post


Link to post
Share on other sites

When using the effect system there's no need to create and bind the buffers on your own. Updating is done through the effect's variables (in this case I guess using ID3DX11EffectVariable::SetRawValue) and then calling ID3DX11EffectPass::Apply().

Share this post


Link to post
Share on other sites
And do I then need to bind them like this? deviceContext->VSSetConstantBuffers(0, 1, lightBuffer); deviceContext->PSSetConstantBuffers(0, 1, lightBuffer);

 

That's correct.

I don't remember how to use the old (and deprecated for a long time now) D3D11 effect system, perhaps it has a call to bind the buffer to both shader stages at once.

[EDIT]: Apparently there is :)

 

But as you are not using the effect system to bind the buffers but rather call the context yourself, you should bind the buffer to both stages.

Edited by N.I.B.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • 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!