将浮点数组和浮点值复制到字节缓冲区-Java



我正在尝试将数据从两个数组和两个变量复制到字节缓冲区。字节缓冲区将为片段着色器中的统一块结构保存这些数据。我可以很好地复制第一个,但第二个总是产生索引超出范围的错误。

我尝试过使用.asFloatBuffer,尝试过将缓冲区初始化为我需要的两倍大小,并尝试过使用FloatBuffer(我需要一个ByteBuffer,但我想我应该尝试修复这个错误,然后再返回)

碎片着色器的结构:

layout (binding = 0) uniform BlobSettings {
    vec4 InnerColor;
    vec4 OuterColor;
    float RadiusInner;
    float RadiusOuter;
};

这就是我现在的代码(有点混乱,但你明白了…):

//create a buffer for the data
//blockB.get(0) contains the 'size' of the data structure I need to copy (value is 48)
//FloatBuffer blockBuffer = BufferUtil.newFloatBuffer(blockB.get(0));
ByteBuffer blockBuffer = ByteBuffer.allocateDirect(blockB.get(0) * 4);//.asFloatBuffer();
//the following data will be copied to the buffer
float outerColor[] = {0.1f,0.1f,0.1f,0.1f};
float innerColor[] = {1.0f,1.0f,0.75f,1.0f};
float innerRadius = 0.25f;
float outerRadius = 0.45f;
//copy data to buffer at appropriate offsets
//params contains the offsets (0, 16, 32, 36)
//following 4 lines using a FloatBuffer (maybe convert to ByteBuffer after loading?)
blockBuffer.put(outerColor, params.get(0), outerColor.length);
blockBuffer.put(innerColor, params.get(1), innerColor.length); //idx out of range here...
blockBuffer.put(params.get(2), innerRadius);
blockBuffer.put(params.get(3), outerRadius);
//when using ByteBuffer directly - maybe something like the following?
for (int idx=0;idx<4;idx++){
    blockBuffer.putFloat(params.get(0) + idx, outerColor[idx]) //????
}

有人能告诉我如何将这些数据正确地放入ByteBuffer吗?

根据我读取统一块规范的方式,您需要小心着色器中的定义与缓冲区中的值的匹配方式。统一块有几种布局选项。您的声明没有指定布局:

layout (binding = 0) uniform BlobSettings {
    vec4 InnerColor;
    vec4 OuterColor;
    float RadiusInner;
    float RadiusOuter;
};

如果没有指定的布局,则默认为shared。这并不能保证块的内存布局定义良好,您必须使用glGetActiveUniformBlockiv()glGetActiveUniformsiv()查询值的大小/偏移量。在您提供的数据中,总大小返回为48,这很可能意味着在末尾添加了填充,使大小为16的倍数。

更简单的选项是指定std140布局选项,它保证了特定的布局:

layout (std140, binding = 0) uniform BlobSettings {
    ...
};

这将为您提供一个总大小为40字节的压缩布局,并按指定顺序显示值。std140布局并不总是完全封装的,例如vec3将使用与vec4相同的空间。您可以阅读规格以了解详细信息。但是对于vec4和标量值,在这种情况下它是打包的。

对于用浮点值填充缓冲区,有几个不同的选项。以您的数据为例(更改顺序以匹配统一定义):

float innerColor[] = {1.0f, 1.0f, 0.75f, 1.0f};
float outerColor[] = {0.1f, 0.1f, 0.1f, 0.1f};
float innerRadius = 0.25f;
float outerRadius = 0.45f;

假设您想通过glBufferData()这样的调用将其传递给OpenGL。

放入数组,然后包装

如果将所有值放入单个浮点数组中,则可以使用FloatBuffer.wrap():直接将其转换为缓冲区

float bufferData[] = {
    1.0f, 1.0f, 0.75f, 1.0f,
    0.1f, 0.1f, 0.1f, 0.1f,
    0.25f,
    0.45f);
glBufferData(..., FloatBuffer.wrap(bufferData));

分配和使用浮动缓冲区

为此,您分配一个FloatBuffer,用数据填充它,然后使用它。请注意,put()方法会提前缓冲区位置,因此您可以简单地逐个添加值。在使用之前,您必须将缓冲区倒带到起始位置。

FloatBuffer buf = FloatBuffer.allocate(10);
buf.put(innerColor);
buf.put(outerColor);
buf.put(innerRadius);
buf.put(outerRadius);
buf.rewind();
glBufferData(..., buf);

分配字节缓冲区,并用作浮点缓冲区

我看到的所有OpenGLJava绑定都接受FloatBufferBuffer参数。因此,像上面的方法一样使用FloatBuffer是最简单的。但是,如果您使用的OpenGL绑定确实需要ByteBuffer,或者需要直接分配(至少在Android上,客户端顶点阵列是这样),您可以先分配ByteBuffer,然后将其用作FloatBuffer:

ByteBuffer byteBuf = ByteBuffer.allocateDirect(10 * 4);
FloatBuffer floatBuf = byteBuf.asFloatBuffer();
floatBuf.put(innerColor);
floatBuf.put(outerColor);
floatBuf.put(innerRadius);
floatBuf.put(outerRadius);
byteBuf.rewind();
glBufferData(..., byteBuf);

使用字节缓冲区

这看起来有点麻烦,但您可以一直使用ByteBuffer

ByteBuffer buf = ByteBuffer.allocateDirect(10 * 4);
buf.putFloat(innerColor[0]);
buf.putFloat(innerColor[1]);
buf.putFloat(innerColor[2]);
buf.putFloat(innerColor[3]);
buf.putFloat(outerColor[0]);
buf.putFloat(outerColor[1]);
buf.putFloat(outerColor[2]);
buf.putFloat(outerColor[3]);
buf.putFloat(innerRadius);
buf.putFloat(outerRadius);
buf.rewind();
glBufferData(..., buf);

最新更新