OpenGL 纹理正在渲染时出现奇怪的中断
OpenGL textures are being rendered with weird interruptions
我正在使用 OpenGL 引擎,我的纹理呈现得很奇怪。纹理大多是完整的并且可以正常工作,但它们几乎没有奇怪的中断。这是它的样子。
右下角是纹理应该看起来的样子,那里还有随机着色的蓝色方块。这些实心方块(无纹理)没有这些中断。
我可以提供代码,但我不确定要显示什么,因为我到处都检查过,但我不知道问题出在哪里。
我正在开发 Java 和 C++ 版本。这是 Java 中的渲染器(如果您想查看其他内容,请询问):
public class BatchRenderer2D extends Renderer2D {
private static final int MAX_SPRITES = 60000;
private static final int VERTEX_SIZE = Float.BYTES * 3 + + Float.BYTES * 2 + Float.BYTES * 1 + Float.BYTES * 1;
private static final int SPRITE_SIZE = VERTEX_SIZE * 4;
private static final int BUFFER_SIZE = SPRITE_SIZE * MAX_SPRITES;
private static final int INDICES_SIZE = MAX_SPRITES * 6;
private static final int SHADER_VERTEX_INDEX = 0;
private static final int SHADER_UV_INDEX = 1;
private static final int SHADER_TID_INDEX = 2;
private static final int SHADER_COLOR_INDEX = 3;
private int VAO;
private int VBO;
private IndexBuffer IBO;
private int indexCount;
private FloatBuffer buffer;
private List<Integer> textureSlots = new ArrayList<Integer>();
public BatchRenderer2D() {
init();
}
public void destroy() {
IBO.delete();
glDeleteBuffers(VBO);
glDeleteVertexArrays(VAO);
glDeleteBuffers(VBO);
}
public void init() {
VAO = glGenVertexArrays();
VBO = glGenBuffers();
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, BUFFER_SIZE, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glEnableVertexAttribArray(SHADER_UV_INDEX);
glEnableVertexAttribArray(SHADER_TID_INDEX);
glEnableVertexAttribArray(SHADER_COLOR_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, VERTEX_SIZE, 0);
glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, false, VERTEX_SIZE, 3 * 4);
glVertexAttribPointer(SHADER_TID_INDEX, 1, GL_FLOAT, false, VERTEX_SIZE, 3 * 4 + 2 * 4);
glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_UNSIGNED_BYTE, true, VERTEX_SIZE, 3 * 4 + 2 * 4 + 1 * 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int[] indices = new int[INDICES_SIZE];
int offset = 0;
for (int i = 0; i < INDICES_SIZE; i += 6) {
indices[ i ] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += 4;
}
IBO = new IndexBuffer(indices, INDICES_SIZE);
glBindVertexArray(0);
}
@Override
public void begin() {
glBindBuffer(GL_ARRAY_BUFFER, VBO);
buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY).asFloatBuffer();
}
@Override
public void submit(Renderable2D renderable) {
Vector3f position = renderable.getPosition();
Vector2f size = renderable.getSize();
Vector4f color = renderable.getColor();
List<Vector2f> uv = renderable.getUV();
float tid = renderable.getTID();
float c = 0;
float ts = 0.0f;
if (tid > 0) {
boolean found = false;
for(int i = 0; i < textureSlots.size(); i++) {
if(textureSlots.get(i) == tid) {
ts = (float)(i + 1);
found = true;
break;
}
}
if(!found) {
if(textureSlots.size() >= 32) {
end();
flush();
begin();
}
textureSlots.add((int)tid);
ts = (float)textureSlots.size();
}
} else {
int r = (int) (color.x * 255);
int g = (int) (color.y * 255);
int b = (int) (color.z * 255);
int a = (int) (color.w * 255);
c = Float.intBitsToFloat((r << 0) | (g << 8) | (b << 16) | (a << 24));
}
transformationBack.multiply(position).store(buffer);
uv.get(0).store(buffer);
buffer.put(ts);
buffer.put(c);
transformationBack.multiply(new Vector3f(position.x, position.y + size.y, position.z)).store(buffer);
uv.get(1).store(buffer);
buffer.put(ts);
buffer.put(c);
transformationBack.multiply(new Vector3f(position.x + size.x, position.y + size.y, position.z)).store(buffer);
uv.get(2).store(buffer);
buffer.put(ts);
buffer.put(c);
transformationBack.multiply(new Vector3f(position.x + size.x, position.y, position.z)).store(buffer);
uv.get(3).store(buffer);
buffer.put(ts);
buffer.put(c);
indexCount += 6;
}
@Override
public void end() {
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@Override
public void flush() {
for(int i = 0; i < textureSlots.size(); i++) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, textureSlots.get(i));
}
glBindVertexArray(VAO);
IBO.bind();
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, NULL);
IBO.unbind();
glBindVertexArray(0);
indexCount = 0;
}
}
你没有提供,但我很确定我知道原因(有同样的问题,遵循 The Cherno 教程?;))。就像信息一样,你的gpu是什么? (看来AMD的问题更多)。将我的 链接到源
重要部分:
片段着色器:
#version 330 core
if(fs_in.tid > 0.0){
int tid = int(fs_in.tid - 0.5);
texColor = texture(textures[tid], fs_in.uv);
}
根据 GLSL 3.30 规范
,不允许您在此处尝试执行的操作
在着色器中聚合成数组的采样器(使用方括号 [ ])只能使用整数常量表达式进行索引(参见第 4.3.3 节“常量表达式”)。
你的 tid 不是一个常量,所以这行不通。
在 GL 4 中,此约束有所放宽(引用自 GLSL 4.50 规范):
当在着色器中聚合到数组中时,采样器只能使用动态统一的积分表达式进行索引,否则结果是不确定的。
现在你的输入也不是动态统一的,所以你也会得到未定义的结果。
(感谢derhass)
一个 "simple" 解决方案(但不是很好,我相信对性能影响很小):
switch(tid){
case 0: textureColor = texture(textures[0], fs_in.uv); break;
...
case 31: textureColor = texture(textures[31], fs_in.uv); break;
}
另外,作为一个小提示,你在那里为正方形做了很多矩阵乘法,你可以简单地乘以第一个然后去添加值,它提高了我的表现200 fps(在您的示例中,相乘,然后加 y,然后加 x,然后再次减去 y)
编辑:
显然我的代数不是应该的,我说你可以做的(现在是罢工)是完全错误的,抱歉
我正在使用 OpenGL 引擎,我的纹理呈现得很奇怪。纹理大多是完整的并且可以正常工作,但它们几乎没有奇怪的中断。这是它的样子。
右下角是纹理应该看起来的样子,那里还有随机着色的蓝色方块。这些实心方块(无纹理)没有这些中断。
我可以提供代码,但我不确定要显示什么,因为我到处都检查过,但我不知道问题出在哪里。
我正在开发 Java 和 C++ 版本。这是 Java 中的渲染器(如果您想查看其他内容,请询问):
public class BatchRenderer2D extends Renderer2D {
private static final int MAX_SPRITES = 60000;
private static final int VERTEX_SIZE = Float.BYTES * 3 + + Float.BYTES * 2 + Float.BYTES * 1 + Float.BYTES * 1;
private static final int SPRITE_SIZE = VERTEX_SIZE * 4;
private static final int BUFFER_SIZE = SPRITE_SIZE * MAX_SPRITES;
private static final int INDICES_SIZE = MAX_SPRITES * 6;
private static final int SHADER_VERTEX_INDEX = 0;
private static final int SHADER_UV_INDEX = 1;
private static final int SHADER_TID_INDEX = 2;
private static final int SHADER_COLOR_INDEX = 3;
private int VAO;
private int VBO;
private IndexBuffer IBO;
private int indexCount;
private FloatBuffer buffer;
private List<Integer> textureSlots = new ArrayList<Integer>();
public BatchRenderer2D() {
init();
}
public void destroy() {
IBO.delete();
glDeleteBuffers(VBO);
glDeleteVertexArrays(VAO);
glDeleteBuffers(VBO);
}
public void init() {
VAO = glGenVertexArrays();
VBO = glGenBuffers();
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, BUFFER_SIZE, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glEnableVertexAttribArray(SHADER_UV_INDEX);
glEnableVertexAttribArray(SHADER_TID_INDEX);
glEnableVertexAttribArray(SHADER_COLOR_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, VERTEX_SIZE, 0);
glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, false, VERTEX_SIZE, 3 * 4);
glVertexAttribPointer(SHADER_TID_INDEX, 1, GL_FLOAT, false, VERTEX_SIZE, 3 * 4 + 2 * 4);
glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_UNSIGNED_BYTE, true, VERTEX_SIZE, 3 * 4 + 2 * 4 + 1 * 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int[] indices = new int[INDICES_SIZE];
int offset = 0;
for (int i = 0; i < INDICES_SIZE; i += 6) {
indices[ i ] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += 4;
}
IBO = new IndexBuffer(indices, INDICES_SIZE);
glBindVertexArray(0);
}
@Override
public void begin() {
glBindBuffer(GL_ARRAY_BUFFER, VBO);
buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY).asFloatBuffer();
}
@Override
public void submit(Renderable2D renderable) {
Vector3f position = renderable.getPosition();
Vector2f size = renderable.getSize();
Vector4f color = renderable.getColor();
List<Vector2f> uv = renderable.getUV();
float tid = renderable.getTID();
float c = 0;
float ts = 0.0f;
if (tid > 0) {
boolean found = false;
for(int i = 0; i < textureSlots.size(); i++) {
if(textureSlots.get(i) == tid) {
ts = (float)(i + 1);
found = true;
break;
}
}
if(!found) {
if(textureSlots.size() >= 32) {
end();
flush();
begin();
}
textureSlots.add((int)tid);
ts = (float)textureSlots.size();
}
} else {
int r = (int) (color.x * 255);
int g = (int) (color.y * 255);
int b = (int) (color.z * 255);
int a = (int) (color.w * 255);
c = Float.intBitsToFloat((r << 0) | (g << 8) | (b << 16) | (a << 24));
}
transformationBack.multiply(position).store(buffer);
uv.get(0).store(buffer);
buffer.put(ts);
buffer.put(c);
transformationBack.multiply(new Vector3f(position.x, position.y + size.y, position.z)).store(buffer);
uv.get(1).store(buffer);
buffer.put(ts);
buffer.put(c);
transformationBack.multiply(new Vector3f(position.x + size.x, position.y + size.y, position.z)).store(buffer);
uv.get(2).store(buffer);
buffer.put(ts);
buffer.put(c);
transformationBack.multiply(new Vector3f(position.x + size.x, position.y, position.z)).store(buffer);
uv.get(3).store(buffer);
buffer.put(ts);
buffer.put(c);
indexCount += 6;
}
@Override
public void end() {
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@Override
public void flush() {
for(int i = 0; i < textureSlots.size(); i++) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, textureSlots.get(i));
}
glBindVertexArray(VAO);
IBO.bind();
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, NULL);
IBO.unbind();
glBindVertexArray(0);
indexCount = 0;
}
}
你没有提供,但我很确定我知道原因(有同样的问题,遵循 The Cherno 教程?;))。就像信息一样,你的gpu是什么? (看来AMD的问题更多)。将我的
重要部分:
片段着色器:
#version 330 core
if(fs_in.tid > 0.0){
int tid = int(fs_in.tid - 0.5);
texColor = texture(textures[tid], fs_in.uv);
}
根据 GLSL 3.30 规范
,不允许您在此处尝试执行的操作在着色器中聚合成数组的采样器(使用方括号 [ ])只能使用整数常量表达式进行索引(参见第 4.3.3 节“常量表达式”)。 你的 tid 不是一个常量,所以这行不通。
在 GL 4 中,此约束有所放宽(引用自 GLSL 4.50 规范):
当在着色器中聚合到数组中时,采样器只能使用动态统一的积分表达式进行索引,否则结果是不确定的。 现在你的输入也不是动态统一的,所以你也会得到未定义的结果。
(感谢derhass)
一个 "simple" 解决方案(但不是很好,我相信对性能影响很小):
switch(tid){
case 0: textureColor = texture(textures[0], fs_in.uv); break;
...
case 31: textureColor = texture(textures[31], fs_in.uv); break;
}
另外,作为一个小提示,你在那里为正方形做了很多矩阵乘法,你可以简单地乘以第一个然后去添加值,它提高了我的表现200 fps(在您的示例中,相乘,然后加 y,然后加 x,然后再次减去 y)
编辑:
显然我的代数不是应该的,我说你可以做的(现在是罢工)是完全错误的,抱歉