【问题标题】:Copying float arrays and float values to a bytebuffer - Java将浮点数组和浮点值复制到字节缓冲区 - Java
【发布时间】:2014-10-11 15:23:24
【问题描述】:

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

我尝试过使用 .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 中?

【问题讨论】:

  • 这是标准的 Java ByteBuffer 吗?我在ByteBuffer 文档中找不到将float[] 作为第一个参数的put() 方法。
  • 是的,.put 来自我尝试使用浮动缓冲区的尝试 - 例如。 ByteBuffer.allocateDirect(blockB.get(0) * 4).asFloatBuffer();但是,我需要将数据放在 ByteBuffer 中。在 Bytebuffer 上,我查看了 blockBuffer.putFloat(index, value) ,我可以在其中迭代并插入数据,但我不完全了解如何正确地将浮点数据放入 Bytebuffer 中......
  • 我已经编辑了我的问题,以显示(部分)我在 FloatBuffer 或 ByteBuffer 上复制数据的尝试。

标签: java opengl glsl buffer


【解决方案1】:

根据我阅读统一块规范的方式,您需要注意着色器中的定义如何与缓冲区中的值匹配。统一块有多种布局选项。您的声明未指定布局:

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。

放入数组,然后换行

如果你把所有的值都放到一个float数组中,你可以直接用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);

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

我见过的所有 OpenGL Java 绑定都接受 FloatBufferBuffer 参数。因此,在上述方法中使用FloatBuffer 是最简单的。但是如果你使用真正需要ByteBuffer的OpenGL绑定,或者需要直接分配(至少在Android上只有客户端顶点数组的情况),你可以先分配ByteBuffer,然后将它用作@ 987654343@:

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

【讨论】:

  • 多么好的答案,非常感谢!我得到的错误很可能是由于我传递给偏移量的值将缓冲区位置推得太远而引起的?另外,我注意到您为 FloatBuffer 分配了 10,这非常有意义。我使用的值取自
  • 调用 glGetActiveUniformBlockiv(iprogram, blockindex, GL3.GL_UNIFORM_BLOCK_DATA_SIZE, blockB);它在 IntBuffer blockB 的第一个位置返回 48。将 48 除以 4 将给我 12 个浮点数 - 额外两个。如果我已经知道哪些数据将进入块,我真的需要使用 glGetActiveUniformBlockiv 吗?
  • 关于统一块的大小/布局的好问题。我在答案的开头添加了一些内容。我从未使用过统一块,但我添加的信息反映了我在阅读了一些规范后的理解。
  • 是的,我确实看到提到了布局,但我认为我是块结构的新手,我不想让事情复杂化。事实证明它会更容易!再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 2015-08-04
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 2014-12-28
相关资源
最近更新 更多