使用 opengl 用中点定理渲染圆我做错了什么?
What have I done wrong to render circle with mid point theoram using opengl?
我无法使用我的以下程序呈现圆圈,无法检测到我的代码中的问题。此代码编译正常并运行但未显示所需的输出
这是输出:
在此代码中,首先使用 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) 绘制的,因此您应该选择一个使中心保持在视口中心的投影:
projection = glm::ortho(-400.0f, 400.0f, -300.0f, 300.0f, -1.0f, 1.0f);
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);
当然,那么vertex shader中属性的数据类型就得是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 and a 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
到init/change缓冲区对象数据存储的内容,绘制点之前:
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
的第三个参数是顶点坐标的数量,而不是数组中元素的数量。每个坐标的元组大小组件数)在顶点属性规范中设置。
我无法使用我的以下程序呈现圆圈,无法检测到我的代码中的问题。此代码编译正常并运行但未显示所需的输出
这是输出:
在此代码中,首先使用 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) 绘制的,因此您应该选择一个使中心保持在视口中心的投影:
projection = glm::ortho(-400.0f, 400.0f, -300.0f, 300.0f, -1.0f, 1.0f);
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);
当然,那么vertex shader中属性的数据类型就得是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 and a 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
到init/change缓冲区对象数据存储的内容,绘制点之前:
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
的第三个参数是顶点坐标的数量,而不是数组中元素的数量。每个坐标的元组大小组件数)在顶点属性规范中设置。