rgba 数组到 OpenGL 纹理
rgba arrays to OpenGL texture
对于我的游戏的图形用户界面,我有一个自定义纹理对象,用于存储纹理的 rgba 数据。我的游戏注册的每个 GUI 元素都添加到最终的 GUI 纹理中,然后该纹理在 post 处理后叠加到帧缓冲区上。
我在将我的纹理对象转换为 openGL 纹理时遇到问题。
首先,我创建了一个 rgbargbargba... etc.
的一维整数数组
public int[] toIntArray(){
int[] colors = new int[(width*height)*4];
int i = 0;
for(int y = 0; y < height; ++y){
for(int x = 0; x < width; ++x){
colors[i] = r[x][y];
colors[i+1] = g[x][y];
colors[i+2] = b[x][y];
colors[i+3] = a[x][y];
i += 4;
}
}
return colors;
}
其中 r
、g
、b
和 a
是从 0 到 255 的锯齿状 int 数组。接下来我创建 int 缓冲区和纹理。
id = glGenTextures();
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
IntBuffer iBuffer = BufferUtils.createIntBuffer(((width * height)*4));
int[] data = toIntArray();
iBuffer.put(data);
iBuffer.rewind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT, iBuffer);
glBindTexture(GL_TEXTURE_2D, 0);
之后我在纹理的左上角添加了一个 50x50 的红色方块,并将纹理绑定到帧缓冲区着色器并渲染显示我的帧缓冲区的全屏矩形。
frameBuffer.unbind(window.getWidth(), window.getHeight());
postShaderProgram.bind();
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, guiManager.texture()); // this gets the texture id that was created
postShaderProgram.setUniform("gui_texture", 1);
mesh.render();
postShaderProgram.unbind();
然后在我的片段着色器中,我尝试显示 GUI:
#version 330
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texFramebuffer;
uniform sampler2D gui_texture;
void main()
{
outColor = texture(gui_texture, Texcoord);
}
但它输出的只是黑色window!
我在左上角添加了一个红色的 50x50 矩形并验证它存在,但由于某种原因它没有显示在最终输出中。
这让我有理由相信我没有正确地将我的纹理转换为 glTexImage2D
的 opengl 纹理。
你能看出我做错了什么吗?
更新 1:
Here 我看到他们使用浮点数组做类似的事情,所以我尝试将我的 0-255 转换为 0-1 浮点数组并将其作为图像数据传递,如下所示:
public float[] toFloatArray(){
float[] colors = new float[(width*height)*4];
int i = 0;
for(int y = 0; y < height; ++y){
for(int x = 0; x < width; ++x){
colors[i] = (( r[x][y] * 1.0f) / 255);
colors[i+1] = (( g[x][y] * 1.0f) / 255);
colors[i+2] = (( b[x][y] * 1.0f) / 255);
colors[i+3] = (( a[x][y] * 1.0f) / 255);
i += 4;
}
}
return colors;
}
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, toFloatArray());
而且有效!
我打算让这个问题悬而未决,因为我想了解为什么 int 缓冲区不起作用:)
当您将 GL_UNSIGNED_INT
指定为 "Host" 数据的类型时,OpenGL 期望为每种颜色分配 32 位。由于 OpenGL 仅将默认帧缓冲区中的输出颜色映射到 [0.0f, 1.0f]
范围内,因此它将采用您的输入颜色值(映射在 [0, 255]
范围内)并将所有这些值除以最大尺寸int(约 42 亿)以获得屏幕上显示的最终颜色。作为练习,使用您的原始代码,将屏幕的 "clear" 颜色设置为白色,并看到一个黑色矩形正在屏幕上绘制。
你有两个选择。第一种是将颜色值转换到 GL_UNSIGNED_INT
指定的范围内,这意味着对于每个颜色值,将它们乘以 Math.pow((long)2, 24)
,并相信乘以该值的整数溢出会正确运行(因为 Java 没有无符号整数类型)。
另一个更安全的选择是将每个 0-255 值存储在一个 byte[]
对象中(不要 使用 char
。char
在 C/C++/OpenGL 中是 1 个字节,但在 Java 中是 2 个字节)并将元素的类型指定为 GL_UNSIGNED_BYTE
.
对于我的游戏的图形用户界面,我有一个自定义纹理对象,用于存储纹理的 rgba 数据。我的游戏注册的每个 GUI 元素都添加到最终的 GUI 纹理中,然后该纹理在 post 处理后叠加到帧缓冲区上。
我在将我的纹理对象转换为 openGL 纹理时遇到问题。
首先,我创建了一个 rgbargbargba... etc.
public int[] toIntArray(){
int[] colors = new int[(width*height)*4];
int i = 0;
for(int y = 0; y < height; ++y){
for(int x = 0; x < width; ++x){
colors[i] = r[x][y];
colors[i+1] = g[x][y];
colors[i+2] = b[x][y];
colors[i+3] = a[x][y];
i += 4;
}
}
return colors;
}
其中 r
、g
、b
和 a
是从 0 到 255 的锯齿状 int 数组。接下来我创建 int 缓冲区和纹理。
id = glGenTextures();
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
IntBuffer iBuffer = BufferUtils.createIntBuffer(((width * height)*4));
int[] data = toIntArray();
iBuffer.put(data);
iBuffer.rewind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT, iBuffer);
glBindTexture(GL_TEXTURE_2D, 0);
之后我在纹理的左上角添加了一个 50x50 的红色方块,并将纹理绑定到帧缓冲区着色器并渲染显示我的帧缓冲区的全屏矩形。
frameBuffer.unbind(window.getWidth(), window.getHeight());
postShaderProgram.bind();
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, guiManager.texture()); // this gets the texture id that was created
postShaderProgram.setUniform("gui_texture", 1);
mesh.render();
postShaderProgram.unbind();
然后在我的片段着色器中,我尝试显示 GUI:
#version 330
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texFramebuffer;
uniform sampler2D gui_texture;
void main()
{
outColor = texture(gui_texture, Texcoord);
}
但它输出的只是黑色window!
我在左上角添加了一个红色的 50x50 矩形并验证它存在,但由于某种原因它没有显示在最终输出中。
这让我有理由相信我没有正确地将我的纹理转换为 glTexImage2D
的 opengl 纹理。
你能看出我做错了什么吗?
更新 1:
Here 我看到他们使用浮点数组做类似的事情,所以我尝试将我的 0-255 转换为 0-1 浮点数组并将其作为图像数据传递,如下所示:
public float[] toFloatArray(){
float[] colors = new float[(width*height)*4];
int i = 0;
for(int y = 0; y < height; ++y){
for(int x = 0; x < width; ++x){
colors[i] = (( r[x][y] * 1.0f) / 255);
colors[i+1] = (( g[x][y] * 1.0f) / 255);
colors[i+2] = (( b[x][y] * 1.0f) / 255);
colors[i+3] = (( a[x][y] * 1.0f) / 255);
i += 4;
}
}
return colors;
}
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, toFloatArray());
而且有效!
我打算让这个问题悬而未决,因为我想了解为什么 int 缓冲区不起作用:)
当您将 GL_UNSIGNED_INT
指定为 "Host" 数据的类型时,OpenGL 期望为每种颜色分配 32 位。由于 OpenGL 仅将默认帧缓冲区中的输出颜色映射到 [0.0f, 1.0f]
范围内,因此它将采用您的输入颜色值(映射在 [0, 255]
范围内)并将所有这些值除以最大尺寸int(约 42 亿)以获得屏幕上显示的最终颜色。作为练习,使用您的原始代码,将屏幕的 "clear" 颜色设置为白色,并看到一个黑色矩形正在屏幕上绘制。
你有两个选择。第一种是将颜色值转换到 GL_UNSIGNED_INT
指定的范围内,这意味着对于每个颜色值,将它们乘以 Math.pow((long)2, 24)
,并相信乘以该值的整数溢出会正确运行(因为 Java 没有无符号整数类型)。
另一个更安全的选择是将每个 0-255 值存储在一个 byte[]
对象中(不要 使用 char
。char
在 C/C++/OpenGL 中是 1 个字节,但在 Java 中是 2 个字节)并将元素的类型指定为 GL_UNSIGNED_BYTE
.