Two constant buffers - cant get it to work

Started by
8 comments, last by QQemka 7 years, 8 months ago

Hello. I've got a problem i was tryin to resolve last hour...

I want to update 2 constant buffers to the shader: one per frame (view*projection) and one per every object (world matrix)

cbuffer cbPerFrameViewProjection : register(cb0)
{
float4x4 ViewProjection;
};

cbuffer cbPerObjectWorldMatrix : register(cb1)
{
float4x4 World;
};

With trial and error i noticed i cannot set both at once.

From what i read, i got to pass 0/1 to VSSetConstantBuffers:

0 for camera (because cb0)

and 1 for world (because cb1)

it did not work. So for temporary test, i decided to multiply the XMMATRIX (world*view*proj) on cpu and simply pass it to cbPerObjectWorldMatrix. And now:

when i set cbuffer cbPerObjectWorldMatrix : register(cb1) and first param to 1 in VSSetConstantBuffers it did NOT draw anything.

When i set cbPerObjectWorldMatrix : register(cb0) and apram to 0, it worked. Other 0/1 combinations do not work too

d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer); // works with cbPerObjectWorldMatrix : register(cb0)

Edit: first param 0 also works with cb1... and even wtih cb any number... whats goin on here

d3d11DevCon->VSSetConstantBuffers(1, 1, &cbPerObjectBuffer); // does not with cbPerObjectWorldMatrix : register(cb1)

So from what i see it COMPLETLY ignores the register cb number part...

Whats wrong?

tl;dr

How can i make 2 or more constant buffers and properly refer to and update each?

At the beginning of frame i call

d3d11DevCon->UpdateSubresource(cbPerFrameBuffer, 0, NULL, &XMMatrixTranspose(cam.GetViewMatrix()*cam.GetProjectionMatrix()), 0, 0);
d3d11DevCon->VSSetConstantBuffers(1, 1, &cbPerFrameBuffer); // 1 for cb1

And for every object

d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &XMMatrixTranspose(world.GetTransform()), 0, 0);
d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer); // 0 for cb0

Thanks in advance

Advertisement

Not saying this is your only problem, but I think you want b0 and b1 instead of cb0 and cb1. Does that shader not emit any warnings on compile?

https://msdn.microsoft.com/en-us/library/windows/desktop/dd607359(v=vs.85).aspx

lol indeed b and not cb....

Thank you so much

By the way, i am using this runtime compile function. Would hlsl compile time compilation warn me? if yes, then im switching right now... :)

Does that shader not emit any warnings on compile?

The older versions of the shader compiler (pre-Windows 10) didn't warn you at all about this, they would just silently ignore your register assignment and do it automatically. The latest version of d3dcompiler_47 will give you a proper error message.

Compiling at runtime or offline shouldn't affect your ability to capture, store, and display warnings and errors. In either case, it is up to you to be setup to do so, however.

This page should give you some info, but you should be able to pass in that last, optional variable to then parse and see if you have any warnings/errors.

I've got another strange problem. i am doin THE SAME thing in 2 different ways, and second gives wrong result.... So i want to draw the 3d object on screen. I got a class containing XYZ, rotation and scale. All the maths works fine.

What do i do now:

-count world*view*proj on cpu, send to constant buffer, render with shader -> works perfectly BUT I want gpu to multiply the world * camera

What do i want then:

-count view*proj once per frame on cpu and send to constant buffer "b1"

-count world matrix for each object on cpu and send to constant buffer "b0"

-inside shader, mul the view * world

And for some reason, option 1 (which i want to move to gpu) does not work properly.

Thats piece of code and the shader for each option

Option 1 - doing all multiplcation on cpu - works


d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &XMMatrixTranspose(world.GetTransform() * cam.GetViewMatrix()*cam.GetProjectionMatrix()), 0, 0);
d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);

Option 2 - whats wrong??


d3d11DevCon->UpdateSubresource(cbPerFrameBuffer, 0, NULL, &XMMatrixTranspose(cam.GetViewMatrix()*cam.GetProjectionMatrix()), 0, 0);
d3d11DevCon->VSSetConstantBuffers(1, 1, &cbPerFrameBuffer);
d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &XMMatrixTranspose(world.GetTransform()), 0, 0);
d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);

As you can see, it should work. I know the matrix has to be transposed, but second option counts the view*proj, trnasposes it, and then inside shader mutiples the result * world which results in world*view*proj transposed (basic math behind transposing matrices).

Thats the shader. Commented line is used in first case (working)


cbuffer cbPerFrameViewProjection : register(b1)
{
    float4x4 ViewProjection;
};

cbuffer cbPerObjectWorldMatrix : register(b0)
{
    float4x4 World;
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
};

VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR)
{

    VS_OUTPUT output;

    float4x4 wvp = mul(ViewProjection, World); // this and below line are for gpu multiplication - blank screen
    output.Pos = mul(inPos, wvp);

    //output.Pos = mul(inPos, World); // thats for cpu multipled matrix, works
    output.Color = inColor;

    return output;
}

Camera:

StaticCamera cam ({ 0.0f, 0.0f, -10.5f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, 800, 600); //look from, look at, width,height

From test and trial i see that the gpu multiplication works only for x y values between -1 and 1, and it places the object proportionally to the screen width/height... but that makes no sense at all. If i set xy to anythingf more than 1 it is blank...

I resolved it...

The multiplication order is... very non intuitive, at least i will know from now on


//float4x4 wvp = mul(ViewProjection, World); // this and below line are for gpu multiplication - blank screen
    //output.Pos = mul(inPos, wvp);

    float4x4 wvp = mul(World, ViewProjection); // Multiplication order - works
    output.Pos = mul(inPos, wvp);

If your matrices on the CPU are stored in row-major order, you need to tell HLSL about this fact:


cbuffer cbPerObjectWorldMatrix : register(b0)
{
    row_major float4x4 World;
};

If you don't do this, HLSL will interpret the matrix using column-major storage ordering, which will have the effect of transposing the data... and if your data is transposed, the correct matrix multiplication order becomes the opposite of what you expect.

Edit: I decided to post his in general section.

This topic is closed to new replies.

Advertisement