C++ OpenGL多维数据集的纹理设置不正确
我正在尝试对使用VBO/VAOs制作的3D立方体进行纹理处理。然而,我只成功地在立方体上对4/6个面进行了适当的纹理处理。我尝试过多种解决方案(从多次定义顶点,到尝试立方体映射——当使用讲师的解决方案时,由于某种原因,只会导致立方体完全消失) 最初,我可以适当的纹理正面,背面,顶部和底部的脸。但是,在与coords玩了几个小时之后,我没有办法对正面、背面、左脸和右脸(但不是顶部或底部)进行纹理处理 如果有人能帮我的话(请解释一下纹理坐标实际上是如何工作的——我是在2D四边形上得到这个想法的,但不是在3D VBO上——或者更好的是一个高质量的教程等等:) 下面是代码 VBO设置 //逐顶点位置向量C++ OpenGL多维数据集的纹理设置不正确,c++,opengl,textures,vbo,vao,C++,Opengl,Textures,Vbo,Vao,我正在尝试对使用VBO/VAOs制作的3D立方体进行纹理处理。然而,我只成功地在立方体上对4/6个面进行了适当的纹理处理。我尝试过多种解决方案(从多次定义顶点,到尝试立方体映射——当使用讲师的解决方案时,由于某种原因,只会导致立方体完全消失) 最初,我可以适当的纹理正面,背面,顶部和底部的脸。但是,在与coords玩了几个小时之后,我没有办法对正面、背面、左脸和右脸(但不是顶部或底部)进行纹理处理 如果有人能帮我的话(请解释一下纹理坐标实际上是如何工作的——我是在2D四边形上得到这个想法的,但不
static float pyramidVertices[] =
{
//Front
0.0f, 0.0f, 0.0f, 1.0f, //BtmLeft
1.0f, 0.0f, 0.0f, 1.0f, //BtmRight
1.0f, 1.0f, 0.0f, 1.0f, //TopRight
0.0f, 1.0f, 0.0f, 1.0f, //TopLeft
//Back
0.0f, 1.0f, -1.0f, 1.0f, //TopLeft
1.0f, 1.0f, -1.0f, 1.0f, //TopRight
1.0f, 0.0f, -1.0f, 1.0f, //BottomRight
0.0f, 0.0f, -1.0f, 1.0f //BottomLeft
};
#pragma region Pyramid Data
// Per-vertex colours (RGBA) floating point values
static float pyramidColours[32] =
{
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f
};
// 5 faces each with 3 vertices (each face forms a triangle)
static unsigned short pyramidVertexIndices[] =
{
//Front
0, 1, 2,
2, 3, 0,
//Left
0, 3, 7,
7, 3, 4,
//Back
4, 5, 6,
6, 7, 4,
//Top
4, 3, 5,
5, 3, 2,
//Right
2, 1, 5,
5, 1, 6,
//Bottom
6, 1, 7,
7, 1, 0
};
#pragma endregion
static float pyramidTexCoordArray[] =
{
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
初始化
显示功能
片段着色器
顶点着色器
结果立方体
(忽略灰色部分,它只是导入的3D模型“dropship.gsf”)
这是意料之中的。问题是每个顶点只能有一个纹理坐标。为了解决此问题,请复制顶点,以便可以为共享同一位置的不同顶点指定不同的纹理坐标 我通常不使用8个顶点,而是使用24个顶点:每个面4个。通过不在面之间共享顶点,可以独立地对每个面进行纹理处理 从技术上讲,您仍然可以共享一些顶点,但24非常小,如果以后要添加这些顶点,它可以让您获得正确的法向量。对于具有UV贴图的平滑模型,通常会有一个接缝(或多个接缝)在其中复制顶点,这可以在UV贴图过程中在3D编辑器中创建
p.S.将变量命名为“金字塔”而不是“立方体”有点令人困惑。这是意料之中的。问题是每个顶点只能有一个纹理坐标。为了解决此问题,请复制顶点,以便可以为共享同一位置的不同顶点指定不同的纹理坐标 我通常不使用8个顶点,而是使用24个顶点:每个面4个。通过不在面之间共享顶点,可以独立地对每个面进行纹理处理 从技术上讲,您仍然可以共享一些顶点,但24非常小,如果以后要添加这些顶点,它可以让您获得正确的法向量。对于具有UV贴图的平滑模型,通常会有一个接缝(或多个接缝)在其中复制顶点,这可以在UV贴图过程中在3D编辑器中创建
p.S.将变量命名为“金字塔”而不是“立方体”有点令人困惑。非常感谢!正如你提到的,我真的开始做这个了!我会告诉你事情的进展。对命名表示歉意,我的最终目标是制作一个金字塔,而不是一个立方体,但是在制作金字塔时遇到了问题,所以我认为立方体会更简单,所以我暂时改为制作一个立方体(在这个时候,当立方体工作时,我打算将其转换为金字塔-但我现在跳过这个阶段,直接去做金字塔。再次感谢!)你还可以考虑(稍后)将所有的属性放在交错的数组中,这样你就有了一些类似于<代码>浮点VisteDATABO[](8)={…,{x,y,z,r,g,b,u,v},…};<代码>。这意味着您只需要一个顶点缓冲区,而不是三个,这样可以更容易地在源代码中复制和粘贴顶点数据。您所要做的就是更改
glvertexattributepointer
的最后两个参数,使其工作。几何体着色器也可以工作,这将是一个很好的(简单的)应用程序来学习它们。@AndonM.Coleman:几何体着色器在一般情况下不起作用,它只是允许您在这里这样做的几何体的一个真正的怪癖,同样可以在片段着色器中轻松使用三平面纹理贴图。我不推荐使用几何体着色器。@DietrichEpp我接受了你关于交错数组的建议。现在一切都正常了。我的绝大多数金字塔现在都能正常显示。然而(令人困惑和烦恼的是)在我的金字塔底部有一个三角形没有渲染。最初我认为我没有分配足够的内存,但现在我分配了足够多的内存(以及我认为的确切数量),它仍然没有渲染最后一个三角形…我无法判断它是没有渲染最后一个顶点,还是没有渲染最后3个顶点。这不是一个大问题(我可以隐藏它),但它只是很烦人谢谢你!正如你提到的,我真的开始做这个了!我会告诉你事情的进展。对命名表示歉意,我的最终目标是制作一个金字塔,而不是一个立方体,但是在制作金字塔时遇到了问题,所以我认为立方体会更简单,所以我暂时改为制作一个立方体(在这个时候,当立方体工作时,我打算将其转换为金字塔-但我现在跳过这个阶段,直接去做金字塔。再次感谢!)你还可以考虑(稍后)将所有的属性放在交错的数组中,这样你就有了一些类似于<代码>浮点VisteDATABO[](8)={…,{x,y,z,r,g,b,u,v},…};<代码>。这意味着您只需要一个顶点缓冲区,而不是三个,这样可以更容易地在源代码中复制和粘贴顶点数据。您所要做的就是更改glVertexAttribPointer
的最后两个参数以使其工作。几何体着色器也可以工作,这将是一个学习它们的好(简单)应用程序。@AndonM.Coleman:几何体着色器在一般情况下不起作用,它只是允许您这样做的几何体的一个真正的怪癖
void init(void) {
// Request an OpenGL 4.3 context with the Compatibility profile
glutInitContextVersion(4, 3);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE);
// Setup OpenGL Display mode - include MSAA x4
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_MULTISAMPLE);
[...]
[...]
[...]
texturedQuad = new CGTexturedQuad(wstring(L"Common\\Resources\\Textures\\bumblebee.png"));
pyramidTexture = TextureLoader::fiLoadTexture(wstring(L"Common\\Resources\\Textures\\VBO\\sandstone.png"));
exampleModel = new CGModel();
importGSF(L"Common\\Resources\\Models\\dropship.gsf", exampleModel);
// Setup VAO for pyramid object
glGenVertexArrays(1, &pyramidVAO);
glBindVertexArray(pyramidVAO);
// Setup VBO for vertex position data
glGenBuffers(1, &pyramidVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, pyramidVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidVertices), pyramidVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0); // attribute 0 gets data from bound VBO (so assign vertex position buffer to attribute 0)
// Setup VBO for vertex colour data
glGenBuffers(1, &pyramidColourBuffer);
glBindBuffer(GL_ARRAY_BUFFER, pyramidColourBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidColours), pyramidColours, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_TRUE, 0, (const GLvoid*)0); // attribute 1 gets colour data
glGenBuffers(1, &pyramidTexCoordBuffer);
glBindBuffer(GL_ARRAY_BUFFER, pyramidTexCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidTexCoordArray), pyramidTexCoordArray, GL_STATIC_DRAW);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
// Enable vertex position and colour attribute arrays
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(3);
// Setup VBO for face index array
glGenBuffers(1, &pyramidIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pyramidIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pyramidVertexIndices), pyramidVertexIndices, GL_STATIC_DRAW);
// Unbind pyramid VAO (or bind another VAO for another object / effect)
// If we didn't do this, we may alter the bindings created above.
glBindVertexArray(0);
glEnable(GL_NORMALIZE); // If we scale objects, ensure normal vectors are re-normalised to length 1.0 to keep lighting calculations correct (see lecture notes)
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Best colour interpolation results
// Setup GL_LIGHT0
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient); // Setup ambient light
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse); // Setup diffuse light
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular); // Setup specular light
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, ca);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, la);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, qa);
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 15.0f);
glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 0.0);
// OpenGL provides a global ambient light component - we don't want this so set to zero
GLfloat global_ambient[] = { 0.15f, 0.15f, 0.15f, 1.0f };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
//
// Load the shader we'll use for the pyramid object
//
err = ShaderLoader::createShaderProgram(string("Common\\Resources\\Shaders\\basic_texture.vs"), string("Common\\Resources\\Shaders\\basic_texture.fs"), &basicShader);
}
void display(void) {
// Clear the screen
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set viewport to the client area of the current window
glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));
// Get view-projection transform as a GUMatrix4
GUMatrix4 T = mainCamera->projectionTransform() * mainCamera->viewTransform();
if (principleAxes)
principleAxes->render(T);
if (texturedQuad)
texturedQuad->render(T * GUMatrix4::translationMatrix(0.5f, 0.5f, 0.0f));
// Fixed function rendering (Compatability profile only) - use this since CGImport is written against OpenGL 2.1
glUseProgram(0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf((const float*)mainCamera->projectionTransform().M);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf((const float*)mainCamera->viewTransform().M);
glMultMatrixf((const float*)GUMatrix4::translationMatrix(0.0f, -0.15f, 0.0f).M);
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT, GL_FILL);
if (exampleModel)
exampleModel->renderTexturedModel();
glDisable(GL_TEXTURE_2D);
//Define position and direction (so appear at fixed point in scene)
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightDirection);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
// enable texturing
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//
// Pyramid VBO rendering
//
// Use basic shader for rendering pyramid (we'll look at this in more detail next week)
glUseProgram(basicShader);
static GLint mvpLocationPyramid = glGetUniformLocation(basicShader, "mvpMatrix");
glUniformMatrix4fv(mvpLocationPyramid, 1, GL_FALSE, (const GLfloat*)&(T.M));
GUMatrix4 pyramidModelTransform = GUMatrix4::translationMatrix(-0.0f, 0.0f, 0.0f) * GUMatrix4::scaleMatrix(2.0f, 2.0f, 2.0f);
GUMatrix4 mvpPyramid = T * pyramidModelTransform;
glUniformMatrix4fv(mvpLocationPyramid, 1, GL_FALSE, (const GLfloat*)&(mvpPyramid.M));
// Bind VAO that contains all relevant pyramid VBO buffer and attribute pointer bindings
glBindVertexArray(pyramidVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, pyramidTexture);
// Draw pyramid
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, (const GLvoid*)0);
// Unbind pyramid VAO (or bind another VAO)
glBindVertexArray(0);
glutSwapBuffers();
}
#version 330
uniform sampler2D texture;
in vec2 texCoord;
layout (location=0) out vec4 fragColour;
void main(void) {
vec4 texColor = texture2D(texture, texCoord);
fragColour = texColor;
}
#version 330
uniform mat4 mvpMatrix;
layout (location=0) in vec4 vertexPos;
layout (location=3) in vec2 vertexTexCoord;
out vec2 texCoord;
void main(void) {
mat4 M;
M[0] = vec4(1.0);
ivec2 a = ivec2(1, 2);
//vec3 b = vec3(2.0, 4.0, 1.0) + a;
texCoord = vertexTexCoord;
gl_Position = mvpMatrix * vertexPos;
}