2016-12-13 2 views
0

Ich versuche, einen 3D-Würfel mit VBO/VAOs texturieren. Allerdings habe ich nur 4/6 Flächen auf dem Würfel richtig texturiert. Ich habe mehrere Lösungen versucht (von der Definition der Scheitelpunkte, bis zum Versuch Cubemapping - die bei Verwendung einer Lösung von einem Dozenten führt nur zum vollständigen Verschwinden des Würfels aus)OpenGL Cube ist nicht richtig texturieren

Zunächst konnte ich die Front richtig texturieren, Rücken-, Ober- und Unterseite. Aber nach ein paar Stunden, in denen ich mit den Koordinaten rumgespielt habe, habe ich es nicht geschafft, die vorderen, hinteren, linken und rechten Flächen zu texturieren (aber nicht oben oder unten).

Wenn mir jemand helfen könnte (und freundlich zu erklären, wie Textur coords tatsächlich funktionieren - ich die Idee, auf einem 2D-Quad, aber nicht auf einem 3D-VBO - oder sogar eine gute Qualität Tutorial besser etc :))

Unten ist der Code;

VBO Einstellungen

// Per-Vertex-Positionsvektoren

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

Initialization

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

Anzeige Funktion

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

Fragment Shader

#version 330 

uniform sampler2D texture; 

in vec2 texCoord; 

layout (location=0) out vec4 fragColour; 

void main(void) { 

    vec4 texColor = texture2D(texture, texCoord); 
    fragColour = texColor; 
} 

Vertex Shader

#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; 
} 

CUBE ENTSTEHEN (ignorieren die grauen Bits, es ist nur das 3D-Modell importiert "dropship.gsf")

Antwort

3

Dies ist zu erwarten. Das Problem ist, dass jeder Vertex nur eine Texturkoordinate haben kann. Um dieses Problem zu lösen, duplizieren Sie die Scheitelpunkte, damit Sie verschiedenen Scheitelpunkten mit derselben Position eine andere Texturkoordinate zuweisen können.

Anstatt 8 Vertices zu verwenden, würde ich normalerweise 24 Vertices verwenden: 4 für jedes Gesicht. Indem Sie die Scheitelpunkte zwischen den Flächen nicht teilen, können Sie jede Fläche unabhängig voneinander strukturieren.

Sie könnten technisch noch teilen einige der Vertices, aber 24 ist sehr klein und es lässt Sie die normalen Vektoren richtig, wenn Sie diese später hinzufügen möchten. Für glatte Modelle mit UV-Mapping gibt es normalerweise eine Naht (oder mehrere Nähte), bei der die Scheitelpunkte dupliziert werden. Diese kann während des UV-Mapping-Prozesses in Ihrem 3D-Editor erstellt werden.

P.S. Es ist ein wenig verwirrend, dass die Variablen "Pyramide" statt "Würfel" heißen.

+0

Vielen Dank! Ich habe buchstäblich angefangen, daran zu arbeiten, wie du es erwähnst! Ich werde dich wissen lassen, wie es läuft. Ich entschuldige mich für die Benennung, mein endgültiges Ziel ist es, eine Pyramide nicht zu einem Würfel zu machen, sondern Probleme mit der Pyramide, so dass Gedankenwürfel einfacher wäre, also habe ich vorübergehend einen Würfel gemacht (zu dem Zeitpunkt, als es funktionierte) verwandle es in eine Pyramide - aber ich überspringe diese Stufe jetzt und gehe direkt auf die Pyramide. Nochmals vielen Dank!) – NeoKuro

+1

Etwas, das Sie auch (später) betrachten können, ist, alle Attribute in ein verschachteltes Array zu setzen - so haben Sie etwas wie 'float VertexData [] [8] = {..., {x, y, z, r, g, b, u, v}, ...};'. Das bedeutet, dass Sie nur einen Vertex-Puffer anstelle von drei benötigen und das Kopieren und Einfügen von Vertex-Daten in Ihrem Quellcode erleichtern kann. Alles, was Sie tun müssen, ist die letzten beiden Parameter von 'glVertexAttribPointer' zu ändern, damit es funktioniert. –

+0

Ein Geometrieshader würde auch funktionieren, dies wäre eine gute (einfache) Anwendung, um sie zu lernen. –

Verwandte Themen