我使用GLSL着色器和VBO渲染网格,VBO存储4个属性; positionXYZ,normalXYZ,textureUV,colourRGBA。一切正常,除了紫外线(也可能是法线,但我还没有办法测试它们)。
发生的事情是,数组中的纹理UV位置偏移到数组中的正常x和y位置。顺便说一下,数组的结构为VVVNNNTTCCCC
(顶点位置,法线,纹理,颜色)。我很确定问题出在将VBO发送到着色器的某个地方。我确信VBO中的数据顺序正确。
这是我的渲染代码:
VBO课程
public final class Mesh
{
public static final int FLOAT_SIZE_BYTES = 4;
public static final int FLOATS_PER_POSITION = 3;
public static final int FLOATS_PER_NORMAL = 3;
public static final int FLOATS_PER_TEXTURE = 2;
public static final int FLOATS_PER_COLOUR = 4;
public static final int VERTEX_SIZE_FLOATS = FLOATS_PER_POSITION + FLOATS_PER_NORMAL + FLOATS_PER_TEXTURE + FLOATS_PER_COLOUR;
public static final int VERTEX_SIZE_BYTES = VERTEX_SIZE_FLOATS * FLOAT_SIZE_BYTES;
public static final int POSITION_OFFSET_FLOATS = 0;
public static final int NORMAL_OFFSET_FLOATS = POSITION_OFFSET_FLOATS + FLOATS_PER_POSITION;
public static final int TEXTURE_OFFSET_FLOATS = NORMAL_OFFSET_FLOATS + FLOATS_PER_NORMAL;
public static final int COLOUR_OFFSET_FLOATS = TEXTURE_OFFSET_FLOATS + FLOATS_PER_TEXTURE;
public static final int POSITION_OFFSET_BYTES = POSITION_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int NORMAL_OFFSET_BYTES = NORMAL_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int TEXTURE_OFFSET_BYTES = TEXTURE_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int COLOUR_OFFSET_BYTES = COLOUR_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int POSITION_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public static final int NORMAL_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public static final int TEXTURE_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public static final int COLOUR_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public final static int VERTICES_PER_FACE = 3;
public static final int ATTRIBUTE_LOCATION_POSITION = 0;
public static final int ATTRIBUTE_LOCATION_NORMAL = 1;
public static final int ATTRIBUTE_LOCATION_TEXTURE = 2;
public static final int ATTRIBUTE_LOCATION_COLOUR = 3;
private int vaoID;
private int iboID;
private int indexCount;
private Mesh(int vaoID, int iboID, int indexCount)
{
this.vaoID = vaoID;
this.iboID = iboID;
this.indexCount = indexCount;
}
public void draw(AbstractShaderProgram shader, Texture texture)
{
glEnable(GL_TEXTURE_2D);
if (texture != null) texture.bind(shader);
else Texture.MISSING_TEXTURE.bind(shader);
glBindVertexArray(vaoID);
glEnableVertexAttribArray(ATTRIBUTE_LOCATION_POSITION);
// glEnableVertexAttribArray(ATTRIBUTE_LOCATION_NORMAL);
// glEnableVertexAttribArray(ATTRIBUTE_LOCATION_TEXTURE);
// glEnableVertexAttribArray(ATTRIBUTE_LOCATION_COLOUR);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
glDrawElements(GL_TRIANGLES, indexCount, GL_FLOAT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(ATTRIBUTE_LOCATION_POSITION);
// glDisableVertexAttribArray(ATTRIBUTE_LOCATION_NORMAL);
// glDisableVertexAttribArray(ATTRIBUTE_LOCATION_TEXTURE);
// glDisableVertexAttribArray(ATTRIBUTE_LOCATION_COLOUR);
glBindVertexArray(0);
glDisable(GL_TEXTURE_2D);
}
public static Mesh compile(List<Face> faces)
{
if (faces.size() <= 0)
throw new RuntimeException("Failed to compile mesh. No faces were provided.");
HashMap<Vertex, Integer> indexMap = new HashMap<>();
ArrayList<Vertex> vertices = new ArrayList<>();
int vertexCount = 0;
for (Face face : faces)
{
for (Vertex vertex : face.getVertices())
{
if (!indexMap.containsKey(vertex))
{
indexMap.put(vertex, vertexCount++);
vertices.add(vertex);
}
}
}
int indicesCount = faces.size() * VERTICES_PER_FACE;
int dataSize = vertexCount * VERTEX_SIZE_FLOATS;
FloatBuffer vertexData = BufferUtils.createFloatBuffer(dataSize);
if (vertexData == null)
System.err.println("Failed to allocate FloatBuffer with size " + dataSize);
for (Vertex vertex : vertices)
{
vertexData.put(vertex.getPosition().x);
vertexData.put(vertex.getPosition().y);
vertexData.put(vertex.getPosition().z);
// vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().x);
// vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().y);
// vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().z);
// vertexData.put(vertex.getTexture() == null ? 0.0F : vertex.getTexture().x);
// vertexData.put(vertex.getTexture() == null ? 0.0F : vertex.getTexture().y);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().x);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().y);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().z);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().w);
}
vertexData.flip();
IntBuffer indices = BufferUtils.createIntBuffer(indicesCount);
for (Face face : faces)
{
for (Vertex vertex : face.getVertices())
{
int index = indexMap.get(vertex);
indices.put(index);
}
}
indices.flip();
int vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
int vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
glVertexAttribPointer(ATTRIBUTE_LOCATION_POSITION, FLOATS_PER_POSITION, GL_FLOAT, false, 0, 0);
// glVertexAttribPointer(ATTRIBUTE_LOCATION_NORMAL, FLOATS_PER_NORMAL, GL_FLOAT, false, NORMAL_STRIDE_BYTES, NORMAL_OFFSET_BYTES);
// glVertexAttribPointer(ATTRIBUTE_LOCATION_TEXTURE, FLOATS_PER_TEXTURE, GL_FLOAT, false, TEXTURE_STRIDE_BYTES, TEXTURE_OFFSET_BYTES);
// glVertexAttribPointer(ATTRIBUTE_LOCATION_COLOUR, FLOATS_PER_COLOUR, GL_FLOAT, false, COLOUR_STRIDE_BYTES, COLOUR_OFFSET_BYTES);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
int iboID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return new Mesh(vaoID, iboID, indicesCount);
}
}
顶点着色器:
#version 400 core
in vec3 vertPosition;
in vec3 vertNormal;
in vec2 vertTexture;
in vec4 vertColour;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
out vec3 pVertPosition;
out vec3 pVertNormal;
out vec2 pVertTexture;
out vec4 pVertColour;
void main()
{
pVertPosition = vertPosition;
pVertNormal = vertNormal;
pVertTexture = vertTexture;
pVertColour = vertColour;
gl_Position = vec4(vec3(vertPosition.xy + vertTexture, vertPosition.z), 1.0);
}
片段着色器:
#version 400 core
in vec3 ppVertPosition;
in vec3 ppVertNormal;
in vec2 ppVertTexture;
in vec4 ppVertColour;
uniform sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture, ppVertTexture);
}
它们之间有一个几何着色器,但它目前是多余的,只是将信息直接填充到片段着色器(这就是out和in变量不匹配的原因。)另外,添加了textureUV的原因片段着色器中的顶点位置是调试实际传递的纹理UV值。这就是我知道UV偏移到正常xy的方式。如果我将纹理UV放入正常的xy中,它们的效果非常好。
如果你想看到任何额外的代码,我没有包含,我会添加它。我没有添加所有内容,例如整个VBO类,因为代码太多了。我只包括了我认为相关的内容以及我认为问题出在哪里。
编辑#1:
着色器中的变量位置(例如vertPosition
和vertNormal
)是绑定的。这是我绑定它们的代码
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_POSITION, "vertPosition");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_NORMAL, "vertNormal");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_TEXTURE, "vertTexture");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_COLOUR, "vertColour");
更改顶点着色器以使用布局(如此)会产生ex \ ct相同的结果;
layout(location = 0) in vec3 vertPosition;
layout(location = 1) in vec3 vertNormal;
layout(location = 2) in vec2 vertTexture;
layout(location = 3) in vec4 vertColour;
编辑#2 我决定发布整个Mesh类,而不仅仅是它的一部分。我也试图实现VAO而不是VBO,但它无法正常工作。
答案 0 :(得分:0)
您正在将标准管道功能与自定义着色器变量混合使用。
调用glEnableClientState(GL_VERTEX_ARRAY);
告诉OpenGL使用某个数据绑定点,一切都很好。
调用glVertexPointer(
告诉OpenGL在哪里找到它的顶点。由于您之前启用了正确的数组,所有数据仍然很好。
然后我们到达顶点着色器并使用in vec3 vertPosition;
但GLSL并不知道你想要你的顶点数据。当然,我们可以看到名称是&#34; vertPosition&#34;,但GLSL不应该根据变量名称猜测您想要的数据!相反,GLSL的默认管道行为是使用gl_Vertex
,这是一个绑定到GL_VERTEX_ARRAY
的预构建GLSL变量。
那为什么它适用于职位呢?我猜你真的很幸运,你定义的变量是偶然分配预先构建的常量。
您应该做的是将glEnableClientState
切换为glEnableVertexAttribArray
,使用Layouts为每个变量分配一个数字,然后拨打glVertexAttribPointer
而不是glVertexPointer
进行链接那个数字到正确的数据。
现在,您声明的变量(如vertPosition
)指向缓冲区中的正确数据,不是偶然的,而是因为您告诉他们!
这是在现代OpenGL中执行操作的正确方法,使用预先构建的变量(如gl_Vertex
)和glEnableClientState
之类的函数被认为是旧的和坏的,因为它不灵活。
您也可以省略布局(因为它需要OGL 4+,并非每个人都有),但在链接着色器之前需要更多工作。
祝你好运!More info on converting your code
(我希望我对此,我不能评论实际验证这是问题)
答案 1 :(得分:0)
好的,我终于开始了......我不知道VBO最初的问题是什么,但是一旦我切换到使用VAO,而不是使用glClientState
进行渲染,它就可以正常工作。此外,我遇到的问题是VAO没有呈现任何有关的内容:
glDrawElements(GL_TRIANGLES, indexCount, GL_FLOAT, 0);
应该是
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);