You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于SharpDX11的GPU光线/网格相交计算着色器开发求助

我来帮你一步步搞定SharpDX 11里对应HLSL缓冲区的创建和绑定问题,结合你给出的HLSL片段,我们分模块来处理:

1. 常量缓冲区(cbRaySettings)的创建与更新

你的HLSL里定义了cbuffer cbRaySettings : register(b0),对应到C#里需要创建一个匹配布局的常量缓冲区,一定要注意HLSL的内存对齐规则——比如float3会自动对齐到float4的大小(16字节),所以C#结构体的偏移要对应好:

首先定义C#侧的结构体:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct RaySettings
{
    public Vector3 RayFrom;
    public Vector3 RayDir;
    public uint TriangleCount;
}
// HLSL里该cbuffer会自动对齐到32字节,所以后续创建缓冲区时SizeInBytes设为32

然后创建常量缓冲区:

// 设备对象是你已经初始化的SharpDX.Direct3D11.Device
var cbDesc = new BufferDescription
{
    SizeInBytes = 32, // 匹配HLSL里cbuffer的实际对齐大小
    Usage = ResourceUsage.Default,
    BindFlags = BindFlags.ConstantBuffer,
    CpuAccessFlags = CpuAccessFlags.None,
    OptionFlags = ResourceOptionFlags.None
};

var raySettingsBuffer = new Buffer(device, cbDesc);

更新缓冲区数据并绑定到着色器:

// 填充数据
var settings = new RaySettings
{
    RayFrom = new Vector3(0.0f, 0.0f, 0.0f), // 替换成你的光线起点
    RayDir = new Vector3(1.0f, 0.0f, 0.0f),  // 替换成你的光线方向
    TriangleCount = (uint)yourTrianglePositionList.Count
};

// 更新GPU缓冲区
device.ImmediateContext.UpdateSubresource(ref settings, raySettingsBuffer);

// 绑定到计算着色器的b0寄存器
device.ImmediateContext.ComputeShader.SetConstantBuffer(0, raySettingsBuffer);
2. 结构化缓冲区(positionBuffer)的创建与绑定

HLSL里的StructuredBuffer<float3> positionBuffer : register(t0)需要创建结构化缓冲区并生成ShaderResourceView(SRV)供着色器访问:

假设你已经有了顶点位置的集合List<Vector3> trianglePositions:

// 创建结构化缓冲区描述
var positionBufferDesc = new BufferDescription
{
    SizeInBytes = trianglePositions.Count * Utilities.SizeOf<Vector3>(),
    Usage = ResourceUsage.Default,
    BindFlags = BindFlags.ShaderResource,
    CpuAccessFlags = CpuAccessFlags.None,
    OptionFlags = ResourceOptionFlags.BufferStructured,
    StructureByteStride = Utilities.SizeOf<Vector3>() // 每个元素的大小,和HLSL的float3一致
};

// 初始化数据到缓冲区
using var dataStream = new DataStream(trianglePositions.Count * Utilities.SizeOf<Vector3>(), true, true);
foreach (var pos in trianglePositions)
{
    dataStream.Write(pos);
}
dataStream.Position = 0;

var positionBuffer = new Buffer(device, dataStream, positionBufferDesc);

然后创建SRV并绑定:

var srvDesc = new ShaderResourceViewDescription
{
    Format = Format.Unknown, // 结构化缓冲区用Unknown格式
    ViewDimension = ShaderResourceViewDimension.Buffer,
    Buffer = new ShaderResourceViewDescription.BufferResource
    {
        FirstElement = 0,
        ElementCount = trianglePositions.Count
    }
};

var positionSrv = new ShaderResourceView(device, positionBuffer, srvDesc);

// 绑定到计算着色器的t0寄存器
device.ImmediateContext.ComputeShader.SetShaderResource(0, positionSrv);
3. 输出结果缓冲区(rayHit)的补充与创建

你的HLSL里定义了rayHit结构体,但没看到输出缓冲区,我们需要添加一个可读写的结构化缓冲区(RWStructuredBuffer)来存储相交结果,先补全HLSL代码:

struct rayHit { float3 intersection; };
RWStructuredBuffer<rayHit> hitResults : register(u0); // 新增输出缓冲区

然后在C#里创建对应的UnorderedAccessView(UAV):
首先定义C#侧的结构体:

public struct RayHit
{
    public Vector3 Intersection;
}

创建缓冲区和UAV:

// 假设你要处理1条光线,所以元素数量为1,按需调整
var hitBufferDesc = new BufferDescription
{
    SizeInBytes = Utilities.SizeOf<RayHit>(),
    Usage = ResourceUsage.Default,
    BindFlags = BindFlags.UnorderedAccess | BindFlags.ShaderResource, // 如果需要读取结果则加ShaderResource
    CpuAccessFlags = CpuAccessFlags.None,
    OptionFlags = ResourceOptionFlags.BufferStructured,
    StructureByteStride = Utilities.SizeOf<RayHit>()
};

var hitBuffer = new Buffer(device, hitBufferDesc);

// 创建UAV
var uavDesc = new UnorderedAccessViewDescription
{
    Format = Format.Unknown,
    ViewDimension = UnorderedAccessViewDimension.Buffer,
    Buffer = new UnorderedAccessViewDescription.BufferResource
    {
        FirstElement = 0,
        ElementCount = 1
    }
};

var hitUav = new UnorderedAccessView(device, hitBuffer, uavDesc);

// 绑定到计算着色器的u0寄存器
device.ImmediateContext.ComputeShader.SetUnorderedAccessView(0, hitUav);
4. 执行计算着色器

最后设置并调度计算着色器:

// 假设你已经加载了计算着色器对象computeShader
device.ImmediateContext.ComputeShader.Set(computeShader);

// 调度线程组,这里按1条光线1个线程来设置,按需调整线程组大小
device.ImmediateContext.Dispatch(1, 1, 1);

// 完成后解绑UAV,避免影响后续渲染
device.ImmediateContext.ComputeShader.SetUnorderedAccessView(0, null);
额外:从GPU读取结果到CPU

如果需要把相交结果读回CPU,需要创建一个Staging缓冲区来拷贝数据:

// 创建Staging缓冲区
var stagingDesc = new BufferDescription
{
    SizeInBytes = Utilities.SizeOf<RayHit>(),
    Usage = ResourceUsage.Staging,
    BindFlags = BindFlags.None,
    CpuAccessFlags = CpuAccessFlags.Read,
    OptionFlags = ResourceOptionFlags.BufferStructured,
    StructureByteStride = Utilities.SizeOf<RayHit>()
};

var stagingBuffer = new Buffer(device, stagingDesc);

// 拷贝GPU数据到Staging缓冲区
device.ImmediateContext.CopyResource(hitBuffer, stagingBuffer);

// 映射到CPU内存读取
var dataStream = device.ImmediateContext.MapSubresource(stagingBuffer, MapMode.Read, MapFlags.None);
var hitResult = dataStream.Read<RayHit>();
device.ImmediateContext.UnmapSubresource(stagingBuffer, 0);

// 现在hitResult里就是相交点数据了

内容的提问来源于stack exchange,提问作者Alessandro Rossi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:29:28