开发者

Trying to pass struct with Vector4 array to cbuffer

开发者 https://www.devze.com 2023-04-09 07:33 出处:网络
I\'m playing around with SlimDX (with DX10/11) a bit and I got some nice results so far, but I\'m stuck on passing an array of Vector4s to the shaders.

I'm playing around with SlimDX (with DX10/11) a bit and I got some nice results so far, but I'm stuck on passing an array of Vector4s to the shaders.

If I try the following struct:

[StructLayout(LayoutKind.Sequential)]
        public struct PerFrameBuffer
        {
            public Vector4 Position;
            public Matrix World;
            public Matrix View;
            public Matrix Projection;

            [MarshalAs( UnmanagedType.ByValArray, SizeConst=2)]
            public Vector4[] Lights;
        }

and try to store it in the following cbuffer:

cbuffer cPerFrame : register( b0 )
{

    float4 xPosition;
    matrix xWorld;
    matrix xView;
    matrix xProjection;

    float4 pointLights[2];
}

I don't get any errors, but the values in the matrices are broken.

However when I declare my struct in c# as follows:

[StructLayout(LayoutKind.Sequential)]
        public struct PerFrameBuffer
        {
            public Vector4 Position;
            public Matrix World;
            public Matrix View;
            public Matrix Projection;
            public Vector4 Light1;
            public Vector4 Light2;
        }

Then everything works fine as ex开发者_StackOverflow中文版pected.

I don't really want to make 64 fields in the struct and fill them up like that (I could with reflection but still). How can I use an array to pass the Vector4's to my constantbuffer?

If by any means this is a dumb idea and should be done in another way, please let me know. It's my first time programming directx and shader related stuff.

To be complete:

Declaration of the buffer in C#

 cPerFrameBuffer = new SlimDX.Direct3D11.Buffer(device, new BufferDescription
            {
                Usage = ResourceUsage.Default,
                SizeInBytes = Marshal.SizeOf(typeof(PerFrameBuffer)),
                BindFlags = BindFlags.ConstantBuffer
            });
            context.VertexShader.SetConstantBuffer(cPerFrameBuffer, 0);

How I'm updating the buffer:

var cb = new AbstractDXManager.PerFrameBuffer()
   {
       Position = new Vector4(camera.Position, 1.0f),
       Projection = Matrix.Transpose(camera.ProjectionMatrix),
       View = Matrix.Transpose(camera.ViewMatrix),
       World = Matrix.Transpose(Matrix.Identity),

   };
   cb.Lights = new Vector4[2];
   cb.Lights[0] = cb.Position;
   cb.Lights[1] = new Vector4(20, 20, 20, 1);
   var context = device.ImmediateContext;

   using (DataStream data = new DataStream(Marshal.SizeOf(typeof(PerFrameBuffer)), true, true))
   {
       data.Write(cb);
       data.Position = 0;
       context.UpdateSubresource(new DataBox(0, 0, data), cPerFrameBuffer, 0);
   }

Thanks in advance


I had the same problem. I changed buffer writing. Now it works

This is my struct

[StructLayout(LayoutKind.Sequential,Pack=1)]
public struct WorldConstants
{
    public Matrix View;
    public Matrix Projection;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public Color4 [] DiffuseColor;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public Color4[] AmbientColor;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public Vector4[] LightDirection;
    public Vector4 ViewPosition;
}

I used StructToPtr to get the alligned data.

        using (DataStream stream = new DataStream(streamSize, true, true))
        {
            int rawsize = Marshal.SizeOf(typeof(ElementT));
            IntPtr buffer = Marshal.AllocHGlobal(rawsize);
            foreach (var element in elements)
            {
                Marshal.StructureToPtr(element, buffer, false);
                stream.WriteRange(buffer,rawsize);
            }
            Marshal.FreeHGlobal(buffer);

Unfortunately this causes an additional copy of the data. In my case I didn't notice any performance problems.

0

精彩评论

暂无评论...
验证码 换一张
取 消