我正在尝试将数据从两个数组和两个变量复制到字节缓冲区。字节缓冲区将为片段着色器中的统一块结构保存这些数据。我可以很好地复制第一个,但第二个总是产生索引超出范围的错误。
我尝试过使用.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绑定都接受FloatBuffer
或Buffer
参数。因此,像上面的方法一样使用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);