尝试将带有Vector4数组的struct传递给cbuffer

时间:2011-09-27 17:34:46

标签: c# slimdx

我正在使用SlimDX(使用DX10 / 11),到目前为止我得到了一些不错的结果,但我坚持将一个Vector4s数组传递给着色器。

如果我尝试以下结构:

[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;
        }

并尝试将其存储在以下cbuffer中:

cbuffer cPerFrame : register( b0 )
{

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

    float4 pointLights[2];
}

我没有收到任何错误,但是矩阵中的值被破坏了。

但是当我在c#中声明我的结构如下:

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

然后一切都按预期工作正常。

我真的不想在结构中创建64个字段并将其填充(我可以使用反射但仍然可以)。如何使用数组将Vector4传递给我的constantbuffer?

如果无论如何这是一个愚蠢的想法,应该以另一种方式完成,请告诉我。这是我第一次编写directx和着色器相关的东西。

完成:

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

我如何更新缓冲区:

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

提前致谢

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。我改变了缓冲区写作。现在它可以工作

这是我的结构

[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;
}

我使用StructToPtr来获取所有对齐的数据。

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

不幸的是,这会导致数据的额外副本。就我而言,我没有注意到任何性能问题。