Unity中的ComputeShader:为什么这些值都是错误的?

问题描述 投票:0回答:1

以下是在 C# 中定义对象的方式,以便 Unity 能够使用它:

(请注意:我留下了所有字段——甚至是这个问题中未使用的字段——以防问题出现在与我正在搜索的地方看似无关的地方)

[StructLayout(LayoutKind.Explicit)]
public struct CSOrbitFunction
{
    [FieldOffset(0)]
    public OrbitTypes type; // sizeof(enum-int) == 4

    #region IOffsetOrbitFunction Members
    [FieldOffset(4)]
    public float offsetX;
    [FieldOffset(8)] // sizeof(float) == 4
    public float offsetY;
    [FieldOffset(12)]
    public float offsetZ;
    #endregion

    #region output
    [FieldOffset(16)]
    public float outX;
    [FieldOffset(20)] // sizeof(float) == 4
    public float outY;
    [FieldOffset(24)]
    public float outZ;
    #endregion

    #region ILagueKeplerOrbitFunction Members
    [FieldOffset(28)]
    public double periapsis;


    [FieldOffset(36)] // sizeof(double) == 8
    public double apoapsis;

    [FieldOffset(44)]
    public int durationSeconds;
    #endregion

    [FieldOffset(48)]
    public int previous; // linked list

    [FieldOffset(52)]
    public int id;

    public static int SizeInBytes = 56;
}

值以完全标准的方式传递给着色器:

CSOrbitFunction[] functions = new CSOrbitFunction[1];
var f = new CSOrbitFunction();
f.periapsis = 10.0;
f.apoapsis = 40.0;
f.durationSeconds = 10;
functions[0] = f;

int sizeInBytes = CSOrbitFunction.SizeInBytes;
ComputeBuffer b = new ComputeBuffer(functions.Length, sizeInBytes);
b.SetData(functions);

ComputeShader shader = new ComputeShader();
shader.SetBuffer(0, "functions", computeBuffer);

着色器是这样“调用”的(仍然很标准)

    var timeMs_ID = Shader.PropertyToID("timeMs");
    shader.SetInt(timeMs_ID, (int)timeMs);

    // Run the shader
    shader.Dispatch(0, functions.Length, 1, 1);

    // Read result (overwrite input)
    computeBuffer.GetData(functions);

这是着色器本身:

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain


// Must match exactly CSOrbitFunction.cs
struct CSOrbitFunction
{
    int type; // from enum OrbitTypes
    
    // shared by all types
    float offsetX;
    float offsetY;
    float offsetZ;
    
    // store result
    float outX;
    float outY;
    float outZ;    
    
    // if the type is LAGUE_KEPLER
    double periapsis;
    double apoapsis;
    int durationSeconds;
    
    // linked list
    int previous;
    
    int id;
};


RWStructuredBuffer<CSOrbitFunction> functions;
int timeMs;

void foobar(uint3 id : SV_DispatchThreadID);

[numthreads(1024,1,1)] // dimensions
void CSMain (uint3 id : SV_DispatchThreadID)
{
    foobar(id);
}


void foobar(uint3 id : SV_DispatchThreadID)
{
    functions[id.x].outX = (float)functions[id.x].periapsis;
    functions[id.x].outY = (float)functions[id.x].apoapsis;
    functions[id.x].outZ = (float)functions[id.x].durationSeconds;
}

======================

现在,问题来了。

GetData 之后,值如下:

outX、outY 和 outZ 都是错误的。然而,当值发生变化时,确实会发生一些事情。另外,近点和远点似乎是正确的。

作为调试测试,我尝试在 foobar 中执行此操作(如下),它确实被调用并在 outX 中返回该值。

functions[id.x].outX = 666.666;

那么为什么它只在近点和远点失败呢?是不是因为float和double之间存在转换问题?

unity-game-engine hlsl compute-shader
1个回答
0
投票

有两个基本问题。

  1. 由于某种原因,“double”在语法上是允许的,但不起作用。我不确定我做错了什么(FieldOffsets 似乎是正确的),但随后强制转换为浮动失败了。所以我把所有的双打都改为浮动。 cos、sin 和 sqrt 等函数无论如何都采用浮点数。

  2. 当像我一样声明为“全局”变量时,PI 不起作用。仅当它在函数内部声明时才有效。我可能对 HLSL 着色器太陌生,不了解这些怪癖。
  3. 之后,一切似乎都正常进行。

© www.soinside.com 2019 - 2024. All rights reserved.