简体   繁体   中英

OpenGL shape only draws when initial position is (0, 0, 0)

I have a cube that I am loading from an OBJ file. When I make its position (0, 0, 0) everything works fine. The cube renders, and my function that gives it a velocity moves the cube across the screen. However if I change the position of the cube to something other than (0, 0, 0) before entering my while loop where I render and calculate velocity changes, the cube never renders. This is the first time I have tried to reload my vertices every time I render a frame, and I am assuming I messed up something there - but I've looked over other code and can't figure out what.

Here is my main function:

int main()
{
#ifdef TESTING
    testing();
    exit(0);
#endif

    setupAndInitializeWindow(768, 480, "Final Project");

    TriangleTriangleCollision collisionDetector;

    Asset cube1("cube.obj", "vertexShader.txt", "fragmentShader.txt");

    cube1.position = glm::vec3(0.0, 2.0, 0.0);
    cube1.velocity = glm::vec3(0.0, -0.004, 0.0);

    MVP = projection * view * model;

    do{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        moveAsset(cube1);

        renderAsset(cube1);

        glfwSwapBuffers(window);
        glfwPollEvents();

    } while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
        glfwWindowShouldClose(window) == 0);

    glfwTerminate();

    return 0;
}

my moveAsset function:

void moveAsset(Asset &asset)
{
    double currentTime = glfwGetTime();

    asset.position.x += (asset.velocity.x * (currentTime - asset.lastTime));
    asset.position.y += (asset.velocity.y * (currentTime - asset.lastTime));
    asset.position.z += (asset.velocity.z * (currentTime - asset.lastTime));

    for (glm::vec3 &vertex : asset.vertices)
    {
        glm::vec4 transformedVector = glm::translate(glm::mat4(1.0f), asset.position) * glm::vec4(vertex.x, vertex.y, vertex.z, 1);
        vertex = glm::vec3(transformedVector.x, transformedVector.y, transformedVector.z);
    }

    asset.lastTime = glfwGetTime();
}

void renderAsset(Asset asset)
{   
    glUseProgram(asset.programID);

    GLuint MatrixID = glGetUniformLocation(asset.programID, "MVP");
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, asset.vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, asset.vertices.size() * sizeof(glm::vec3), &asset.vertices[0], GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glDrawArrays(GL_TRIANGLES, 0, asset.vertices.size());

    glDisableVertexAttribArray(0);
}

my model, view and projection matrices are defined as:

glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::lookAt(glm::vec3(5, 5, 10),
                            glm::vec3(0, 0, 0),
                            glm::vec3(0, 1, 0));
glm::mat4 projection = glm::perspective(45.0f, (float) _windowWidth / _windowHeight, 0.1f, 100.0f);

and finally, my Asset struct:

struct Asset
{
    Asset() { }
    Asset(std::string assetOBJFile, std::string vertexShader, std::string fragmentShader)
    {
        glGenVertexArrays(1, &vertexArrayID);
        glBindVertexArray(vertexArrayID);

        programID = LoadShaders(vertexShader.c_str(), fragmentShader.c_str());

        // Read our .obj file
        std::vector<glm::vec2> uvs;
        std::vector<glm::vec3> normals;
        loadOBJ(assetOBJFile.c_str(), vertices, uvs, normals);

        // Load it into a VBO
        glGenBuffers(1, &vertexbuffer);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

        //velocity = glm::vec3(0.0, 1.0, 1.0);
        velocity = glm::vec3(0.0, 0.0, 0.0);
        position = glm::vec3(0.0, 0.0, 0.0);

        lastTime = glfwGetTime();
    }

    GLuint vertexArrayID;
    GLuint programID;

    GLuint vertexbuffer;

    std::vector<glm::vec3> faces;
    std::vector<glm::vec3> vertices;

    glm::vec3 velocity;

    double lastTime;
    glm::vec3 position;
};

It looks like you're adding the current asset.position to your vertex positions on every iteration , replacing the previous positions. From the moveAsset() function:

for (glm::vec3 &vertex : asset.vertices)
{
    glm::vec4 transformedVector = glm::translate(glm::mat4(1.0f), asset.position) *
                                  glm::vec4(vertex.x, vertex.y, vertex.z, 1);
    vertex = glm::vec3(transformedVector.x, transformedVector.y, transformedVector.z);
}

Neglecting the velocity for a moment, and assuming that you have an original vertex at (0, 0, 0), you would move it to asset.position on the first iteration. Then add asset.position again on the second iteration, which places it at 2 * asset.position . Then on the third iteration, add asset.position to this current position again, resulting in 3 * asset.position . So after n steps, the vertices will be around n * asset.position . Even if your object might be visible initially, it would move out of the visible range before you can blink.

To get your original strategy working, the most straightforward approach is to have two lists of vertices. One list contains your original object coordinates, which you never change. Then before you draw, you build a second list of vertices, calculated as the sum of the original vertices plus the current asset.position , and use that second list for rendering.

The whole thing is... not very OpenGL. There's really no need to modify the vertex coordinates on the CPU. You can make the translation part of the transformation applied in your vertex shader. You already have a model matrix in place. You can simply put the translation by asset.position into the model matrix, and recalculate the MVP matrix. You already have the glUniformMatix4fv() call to pass the new matrix to the shader program in your renderAsset() function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM