c++ - 使用 opengl 用中点定理渲染圆我做错了什么?

标签 c++ opengl glfw glm-math glad

我无法使用我的以下程序呈现圆圈,无法检测到我的代码中的问题。此代码可以正常编译并运行但未显示所需的输出

这是输出:

在这段代码中,首先使用 glfw 进行初始化 然后定义着色器并相应地设置均匀投影矩阵 然后渲染循环开始,其中调用了 midPointCircleAlgo 函数 渲染,进一步的绘图功能在屏幕上显示输出。 我哪里错了。

这是顶点着色器:-

#version 330 core
layout (location = 0) in vec2 apos;
uniform mat4 projection;
void main()
{
    gl_Position = projection*vec4(apos,0.0,1.0);
}
#include <glad/glad.h> 
#include <GLFW/glfw3.h>
#include <iostream>
#include "Header.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>


void framebuffer_size_callback(GLFWwindow *window, int width, int height); 
void plot(int x, int y);
void midPointCircleAlgo(int r);

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3 );
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *window = glfwCreateWindow(800,600,"Circle",NULL,NULL);
    if(!window){
        std::cout << "Failed to open window";
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    glViewport(0,0,800,600);
    glfwSetFramebufferSizeCallback(window,framebuffer_size_callback);

    Shader shader("shader.vs","shader.fs");//I use a header file containing shader abstraction
    glm::mat4 projection;
    projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);

    int pmatrix = glGetUniformLocation(shader.ID, "projection");
    shader.use();
    glUniformMatrix4fv(pmatrix,1,GL_FALSE,glm::value_ptr(projection));

    int r = 10;

    while(!glfwWindowShouldClose(window))
    {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //render Circle
        shader.use();
        midPointCircleAlgo(10);

    glfwSwapBuffers(window);
        glfwPollEvents();    
    }

    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow *window,int width,int height){
    glViewport(0,0,width,height);   
}



void midPointCircleAlgo(int r)
{
    int x = 0;
    int y = r;
    float decision = 5 / 4 - r;
    plot(x, y);

    while (y > x)
    {
        if (decision < 0)
        {
            x++;
            decision += 2 * x + 1;
        }
        else
        {
            y--;
            x++;
            decision += 2 * (x - y) + 1;
        }
        plot(x, y);
        plot(x, -y);
        plot(-x, y);
        plot(-x, -y);
        plot(y, x);
        plot(-y, x);
        plot(y, -x);
        plot(-y, -x);
    }

}

void plot(int x,int y) 
{
    int vertices[] = { x,y};
    unsigned int VBO,VAO;
    glGenBuffers(1,&VBO);
    glGenVertexArrays(1,&VAO);
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 2, GL_INT, GL_TRUE, 0, (void *)0);
    glEnableVertexAttribArray(0);   
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glDrawArrays(GL_POINTS, 0, 2);

    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &VAO);

}

最佳答案

第一个问题是正交投影。

projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);

由于您的几何图形是在 0.0 的 z 坐标处绘制的,因此它会被投影的近平面 (0.1) 裁剪。圆是围绕 (0, 0) 绘制的,因此您应该选择一个使中心保持在视口(viewport)中心的投影:

projection = glm::ortho(-400.0f, 400.0f, -300.0f, 300.0f, -1.0f, 1.0f);

当您使用 glVertexAttribPointer

glVertexAttribPointer(0, 2, GL_INT, GL_TRUE, 0, (void *)0);

然后,第 4 个参数指定定点数据值是应该归一化 (GL_TRUE) 还是直接转换为定点值 (GL_FALSE)。这意味着,如果参数是 GL_TRUE,则数据类型 int 范围内的值将映射到 [-1.0, 1.0] 范围内的浮点值。您想将积分值 1:1 转换为膨胀点值,因此参数必须为 GL_FALSE:

 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, (void *)0);

请注意,您也可以使用 glVertexAttribIPointer (关注I),这是针对积分顶点着色器输入属性:

glVertexAttribIPointer(0, 2, GL_INT, 0, (void *)0);

当然,那么顶点着色器中属性的数据类型必须是ivec2而不是vec2:

#version 330 core

layout (location = 0) in ivec2 apos;

uniform mat4 projection;

void main()
{ 
    gl_Position = projection * vec4(vec2(apos), 0.0, 1.0);
}

缓冲区的思想是在缓冲区中存储尽可能多的数据,然后一次渲染所有顶点。
但是即使你想画一个点,创建一个 Vertex Array Object 也不是一个好主意。和一个 Vertex Buffer Object对于每个点,并在绘图后立即将其销毁。

在主循环之前的初始化时创建一个空缓冲区和一个顶点数组对象:

unsigned int VBO, VAO;

int main() {

    // [...]

    glGenVertexArrays(1,&VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1,&VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, 2*sizeof(int), 0, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, (void *)0);
    //glVertexAttribIPointer(0, 2, GL_INT, 0, (void *)0);
    glEnableVertexAttribArray(0);

    while(!glfwWindowShouldClose(window))
    {
        // [...]
    }

    // [...]
}

使用glBufferSubData在绘制点之前初始化/更改缓冲区对象数据存储的内容:

void plot(int x, int y) 
{
    int vertices[] = {x, y};

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    glDrawArrays(GL_POINTS, 0, 1);
}

旁注,glDrawArrays 的第三个参数是顶点坐标的数量,但不是数组中元素的数量。每个坐标的元组大小组件数)在顶点属性规范中设置。

关于c++ - 使用 opengl 用中点定理渲染圆我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55196306/

相关文章:

c++ - c++中基于点的重力示例

c++ - glClearBufferData - 使用示例?

c++ - 如何防止调整自定义 QWidget 的大小?

performance - 2d 绘图基元和图像 : OpenGL, Cairo 或 Agg

C++ STL 算法 upper_bound() 不是严格大于

c++ - 如何在 C++ 中创建 glfw 线程?

c++ - glfwOpenWindowHint 未在此范围内声明 GLFW3 和 GLEW

c++ - 如何在 Linux 中使用 GLFW 函数正确链接 C++ 对象?

c++ - CreateGraphicsPipelineState 失败并显示 E_INVALIDARG

c# - 在C#中调整图像大小并将其发送到OpenCV会导致图像失真