带有圆柱体的 OpenGL/C++ 立方体仅呈现圆柱体圆形底的前半部分

OpenGL/C++ cube with cylinder inside only renders first half of cylinder's circular base

提问人:JS2023 提问时间:11/15/2023 最后编辑:genpfaultJS2023 更新时间:11/15/2023 访问量:35

问:

我很困惑为什么这不能呈现整个实体。

这是我的圆柱体类.cpp:

#include "cylinderClass.h"
#include <glad/glad.h>
#include <vector>
#include <glm/trigonometric.hpp>
#include <stdio.h>


// *********  CYLINDER  ************ //
// generates vertices for cylinder with radius 1.0 and height 1.0
// base is on the X/Z plane and y-axis passes through center
GLfloat* Cylinder::generateVertices()
{

    // array to hold coordinates of all 722 vertices of cylinder (6 floats per set: x, y, z, r, g, b)
    static GLfloat vertices2[4380]; // 4332 for cylinder vertices, 48 for cube

    // center of bottom circle (origin)
    vertices2[0] = 0.0f;
    vertices2[1] = 0.0f;
    vertices2[2] = 0.0f;
    // color = red
    vertices2[3] = 1.0f;
    vertices2[4] = 0.0f;
    vertices2[5] = 0.0f;

    // center of top circle
    vertices2[6] = 0.0f;
    vertices2[7] = 1.0f;
    vertices2[8] = 0.0f;
    // color = green
    vertices2[9] = 0.0f;
    vertices2[10] = 1.0f;
    vertices2[11] = 0.0f;

    // angle = degrees from positive x-axis
    // angle goes from 0 to 359 degrees in increments of 1
    // circle bases are each made up of 360 triangles
    float angle = 0.0f;
    int offset = 2160;
    float xcoord = 0.0f;
    float zcoord = 0.0f;
    // vertices2[12] is the point at 0 degrees on lower circle
    // vertices2[2166] is the point at 359 degrees on lower circle 
    // vertices2[2172] is the point at 0 degrees on upper circle
    // vertices2[4326] is the point at 359 degrees on upper circle
    // vertices2[4332] will begin cube vertices
    for (int i = 12; i < 2167; i = i + 6)
    {

        // x coordinates of lower and upper circles (they're the same)
        xcoord = cosf(glm::radians((angle)));
        if (abs(xcoord) < 0.0001f) {
            xcoord = 0.0f;
        }
        vertices2[i] = xcoord;
        vertices2[i + offset] = xcoord;

        // y coordinates of lower and upper circles
        vertices2[i + 1] = 0.0f;
        vertices2[i + offset + 1] = 1.0f;

        // z coordinates of lower and upper circles (they're the same)
        zcoord = sinf(glm::radians((angle)));
        if (abs(zcoord) < 0.0001f) {
            zcoord = 0.0f;
        }
        vertices2[i + 2] = zcoord;
        vertices2[i + offset + 2] = zcoord;

        // red color value of lower and upper circles
        vertices2[i + 3] = 0.0f;
        vertices2[i + offset + 3] = 0.0f;

        // green color value of lower and upper circles
        vertices2[i + 4] = 0.0f;
        vertices2[i + offset + 4] = 0.0f;
    
        // blue color value of lower and upper circles
        vertices2[i + 5] = 1.0f;
        vertices2[i + offset + 5] = 1.0f;

        angle = angle + 1.0f;
    }
    
    // *********  CUBE  ************ //
    // 
    // point 0, upper right corner of base (x, y, z, r, g, b)
    vertices2[4332] = 0.5f;
    vertices2[4333] = 0.0f;
    vertices2[4334] = 0.5f;

    // point 1, lower right corner of base
    vertices2[4338] = 0.5f;
    vertices2[4339] = 0.0f;
    vertices2[4340] = -0.5f;

    // point 2, lower left corner of base
    vertices2[4344] = -0.5f;
    vertices2[4345] = 0.0f;
    vertices2[4346] = -0.5f;

    // point 3, upper left corner of base
    vertices2[4350] = -0.5f;
    vertices2[4351] = 0.0f;
    vertices2[4351] = 0.5f;

    // point 4, upper right corner of top
    vertices2[4356] = 0.5f;
    vertices2[4357] = 1.0f;
    vertices2[4358] = 0.5f;

    // point 5, lower right corner of top
    vertices2[4362] = 0.5f;
    vertices2[4363] = 1.0f;
    vertices2[4364] = -0.5f;

    // point 6, lower left corner of top
    vertices2[4368] = -0.5f;
    vertices2[4369] = 1.0f;
    vertices2[4370] = -0.5f;

    // point 7, upper left corner of top
    vertices2[4374] = -0.5f;
    vertices2[4375] = 1.0f;
    vertices2[4376] = 0.5f;

    // color
    for (int i = 4335; i < 4380; i = i + 6) {
        vertices2[i] = 0.75f;
        vertices2[i + 1] = 0.55f;
        vertices2[i + 2] = 0.1f;
    }

    // multiply each x, z location coordinate of cylinder by scalar
    // to scale the cylinder down to fit inside cube
    for (int i = 0; i < 4332; i = i + 6)
    {
        vertices2[i] = vertices2[i] * 0.375f;
        // vertices2[i + 1] = vertices2[i + 1] * 0.375f;
        vertices2[i + 2] = vertices2[i + 2] * 0.375f;

    }
   
    return vertices2;
 
}

// *********  CYLINDER  ************ //
// generates indices for the above vertices array to draw a cylinder
GLuint* Cylinder::generateTriangles()
{

    GLuint p1, p2, p3, p4;

    // array to hold indices (3 vertices per triangle, 1440 triangles total for cylinder)
    static GLuint indices2[4356]; // first 4320 for cylinder, last 36 for cube

    int j = 2;
    for (int i = 0; i < 1080; i = i + 3)
    {
        // four corners of rectangle on side of cylinder
        p1 = j; // lower left corner
        p2 = j + 360; // upper left corner
        p3 = j + 361; // upper right corner
        p4 = j + 1; // lower right corner
        // when angle reaches 359 degrees, the point at 0 degrees is used
        if (i == 1077) {
            p3 = 362;
            p4 = 2;
        }

        // triangles that make up bottom circle
        indices2[i] = 0;
        indices2[i + 1] = p1;
        indices2[i + 2] = p4;
       
        // triangles that make up top circle
        indices2[i + 1080] = 1;
        indices2[i + 1081] = p2;
        indices2[i + 1082] = p3;
   

        // two triangles that make up side section (1 / 360) of cylinder
        // triangle one
        indices2[i + 2160] = p1;
        indices2[i + 2161] = p2;
        indices2[i + 2162] = p3;

        // triangle two
        indices2[i + 3240] = p1;
        indices2[i + 3241] = p3;
        indices2[i + 3242] = p4;
    
        j = j + 1;
        }

    // *********  CUBE  ************ //
    
    int offset2 = 722;
    // base triangles
    indices2[4320] = 0 + offset2;
    indices2[4321] = 1 + offset2;
    indices2[4322] = 3 + offset2;
    indices2[4323] = 1 + offset2;
    indices2[4324] = 2 + offset2;
    indices2[4325] = 3 + offset2;

    // left face triangles
    indices2[4326] = 2 + offset2;
    indices2[4327] = 3 + offset2;
    indices2[4328] = 6 + offset2;
    indices2[4329] = 3 + offset2;
    indices2[4330] = 6 + offset2;
    indices2[4331] = 7 + offset2;
    
    // top face triangles
    indices2[4332] = 4 + offset2;
    indices2[4333] = 5 + offset2;
    indices2[4334] = 7 + offset2;
    indices2[4335] = 5 + offset2;
    indices2[4336] = 6 + offset2;
    indices2[4337] = 7 + offset2;

    // right face triangles
    indices2[4338] = 0 + offset2;
    indices2[4339] = 1 + offset2;
    indices2[4340] = 5 + offset2;
    indices2[4341] = 0 + offset2;
    indices2[4342] = 4 + offset2;
    indices2[4343] = 5 + offset2;

    // front face triangles
    indices2[4344] = 1 + offset2;
    indices2[4345] = 2 + offset2;
    indices2[4346] = 6 + offset2;
    indices2[4347] = 1 + offset2;
    indices2[4348] = 5 + offset2;
    indices2[4349] = 6 + offset2;
    
    // back face triangles
    indices2[4350] = 0 + offset2;
    indices2[4351] = 3 + offset2;
    indices2[4352] = 4 + offset2;
    indices2[4353] = 3 + offset2;
    indices2[4354] = 4 + offset2;
    indices2[4355] = 7 + offset2;
    
    
    return indices2;

}

这是我的主要 cpp 文件:

#include <iostream>         // cout, cerr
#include <glad/glad.h>      // GLAD library
#include <GLFW/glfw3.h>     // GLFW library
#include <cstdlib>          // EXIT_FAILURE

// GLM Math Headers
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>


#include "shaderClass.h"    // shader class
#include "VAO.h"            // vertex array object
#include "VBO.h"            // vertex buffer object
#include "EBO.h"            // element buffer object (for indices)
#include "cylinderClass.h"  
#include "cubeClass.h"


using namespace std;

// Variables for window width, height, and title
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 800;
const char* const WINDOW_TITLE = "CS 330 Project";
// can't be calculated with sizeof(), because vertices and indices are pointers
const int SIZE_OF_VERTICES = 4380;  // (722 vertices for cylinder + 8 vertices    for cube) * 6 elements per vertex
const int SIZE_OF_INDICES = 4356;   // total number of triangles for both shapes: 
                                    // (1440 for cylinder + 12 for cube) = 1452
                                    // 1452 * 3 vertices per triangle = 4356


// cube with cylindrical cutout
// create instance of Cylinder class to generate vertices and indices
Cylinder* cylinder = new Cylinder();

// Coordinates of vertices of cylinder [number of vertices (722) x 3 = 2166,     doubled for color coordinates]
GLfloat* vertices = cylinder->generateVertices();

// Indices of coordinates used to create triangles
GLuint* indices = cylinder->generateTriangles();

// main function. Entry point to the OpenGL program
int main()
{

    // initialize GLFW
    glfwInit();

    // configure GLFW (version and type of profile)
    // tell GLFW which version is being used (3.3)
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

    // tell GLFW that CORE profile is being used (only have modern functions)
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // create GLFWwindow object
    GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL);

    // error check and message if window fails to create
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    // tell GLFW to use the window in the current context
    glfwMakeContextCurrent(window);

    // load GLAD so it configures OpenGL in the window
    gladLoadGL();

    // specify the viewport of OpenGL in the window
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    // set the background color of the window to black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

   
    // generate shader object using shaders default.vert and default.frag
    Shader shaderProgram("default.vert", "default.frag");

    // generate vertex array object and bind it
    VAO VAO1;
    VAO1.Bind();

    // generate vertex buffer object and link it to vertices
    VBO VBO1(vertices, SIZE_OF_VERTICES);

    // generate element buffer object and link it to indices
    EBO EBO1(indices, SIZE_OF_INDICES);

    // link VBO attributes (location coordinates and colors) to VAO
    VAO1.LinkAttrib(VBO1, 0, 3, GL_FLOAT, 6 * 4, (void*)0);
    VAO1.LinkAttrib(VBO1, 1, 3, GL_FLOAT, 6 * 4, (void*)(3 * 4));

    // unbind all to prevent accidentally modifying them
    VAO1.Unbind();
    VBO1.Unbind();
    EBO1.Unbind();

    // gets ID of uniform called "scale"
    GLuint uniID = glGetUniformLocation(shaderProgram.ID, "scale");

    // enable depth buffer
    glEnable(GL_DEPTH_TEST);

    // main while loop
    while (!glfwWindowShouldClose(window))
    {
        // set the background color of the window to black
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        // clean the back buffer and depth buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // tell OpenGL which shader program we want to use
        shaderProgram.Activate();

        // initialize matrices so they are not null
        glm::mat4 model = glm::mat4(1.0f);
        glm::mat4 view = glm::mat4(1.0f);
        glm::mat4 proj = glm::mat4(1.0f);

        // assign different transformations to each matrix
        // scales and rotates the cube with cylindrical hole 45 degrees about the y-axis
        //model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));
        model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        // moves the camera up 0.5 and back 5.0
        view = glm::translate(view, glm::vec3(0.0f, -0.5f, -5.0f));
        // draws the cylinder with field of view 45 degrees, aspect ration width/height, near plane at 0.1, far plane at 100
        proj = glm::perspective(glm::radians(45.0f), (float)(WINDOW_WIDTH / (float)WINDOW_HEIGHT), 0.1f, 100.0f);

        // outputs matrices into the vertex shader
        int modelLoc = glGetUniformLocation(shaderProgram.ID, "model");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        int viewLoc = glGetUniformLocation(shaderProgram.ID, "view");
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
        int projLoc = glGetUniformLocation(shaderProgram.ID, "proj");
        glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));

        // assigns a value to the uniform (must be done after activating the shader program)
        glUniform1f(uniID, 0.5f);
        // bind the VAO so OpenGL knows to use it
        VAO1.Bind();
        // draw primitives (triangles), number of indices, datatype of indices, index of indices
        glDrawElements(GL_TRIANGLES, SIZE_OF_INDICES / 3, GL_UNSIGNED_INT, 0);

        // for testing
        // glDrawElements(GL_POINTS, SIZE_OF_INDICES, GL_UNSIGNED_INT, 0);

        // swap the back buffer with the front buffer
        glfwSwapBuffers(window);
        // take care of all GLFW events
        glfwPollEvents();
    }

    // delete all the objects we've created
    VAO1.Delete();
    VBO1.Delete();
    EBO1.Delete();
    shaderProgram.Delete();

    // delete window before ending the program
    glfwDestroyWindow(window);

    // terminatee the GLFW before ending the program
    glfwTerminate();

    return 0;
}

我已经运行了调试器并检查了 vertices2 和 indices2 数组值是否正确分配,它们似乎都正确分配了。

单独类中的立方体本身使用main.cpp中的相同逻辑正确呈现,因此我认为问题不在于与OpenGL相关的代码。

当我运行程序来绘制点而不是绘制三角形时,它会绘制圆的中心和底部圆的前半部分(0 到 180 度)。(注意:圆柱体旋转,正 z 轴指向您,因此很难分辨渲染了哪些点。

C++ opengl glfw glm-math 顶点缓冲区

评论

0赞 Olivier Samson 11/15/2023
是否有可能获得您获得的结果的图像?
0赞 Gene 11/15/2023
不确定这是否是问题所在,但 C++ 适用于整数。你可能想要.abs()fabs()
0赞 BDL 11/15/2023
的 count 参数需要索引的数量,而不是三角形的数量。您可能需要省略该部分。glDrawArrays/ 3
0赞 JS2023 11/15/2023
已解决(大部分):我需要将 SIZE_OF_VERTICES SIZE_OF_INDICES相乘,并将每个乘以 4(字节大小)。可能还有一些其他的东西需要调整,但至少立方体和圆柱体现在出现了。感谢您的其他提示!我也会实现它们。

答: 暂无答案