当前位置: 首页 > 知识库问答 >
问题:

如何在OpenGL Core 3.3中使用正交投影绘制圆形?

赫连骏
2023-03-14

我是OpenGL编程的完全初学者,正在努力学习learnopengl的突破教程。但是他想把球画成一个实际的圆,而不是像乔伊建议的那样使用纹理四维。然而,谷歌为“画圈opengl 3.3”或类似短语向我抛出的每一个结果似乎都至少有几年历史了,并且使用的API版本甚至比那个版本还要旧:-(

我发现的最接近的事情是这个SO问题,但是当然OP只需要使用一个自定义的VertexFormat对象来抽象一些细节,而没有分享他/她的实现!只是我的运气!: P

还有一个YouTube教程,它使用了一个看似旧版本的API,但逐字复制代码(除了最后几行代码看起来很旧的地方)仍然让我一事无成。

我的版本的Sprite渲染器::initRenderData()从教程:

void SpriteRenderer::initRenderData() {
    GLuint vbo;

    auto attribSize = 0;
    GLfloat* vertices = nullptr;

    // Determine whether this sprite is a circle or
    // quad and setup the vertices array accordingly
    if (!this->isCircle) {
        attribSize = 4;
        vertices = new GLfloat[24] {...}   // works for rendering quads
    } else {
        // This code is adapted from the YouTube tutorial that I linked
        // above and is where things go pear-shaped for me...or at least
        // **not** circle-shaped :P
        attribSize = 3;

        GLfloat x = 0.0f;
        GLfloat y = 0.0f;
        GLfloat z = 0.0f;
        GLfloat r = 100.0f;

        GLint numSides = 6;
        GLint numVertices = numSides + 2;

        GLfloat* xCoords = new GLfloat[numVertices];
        GLfloat* yCoords = new GLfloat[numVertices];
        GLfloat* zCoords = new GLfloat[numVertices];

        xCoords[0] = x;
        yCoords[0] = y;
        zCoords[0] = z;

        for (auto i = 1; i < numVertices; i++) {
            xCoords[i] = x + (r * cos(i * (M_PI * 2.0f) / numSides));
            yCoords[i] = y + (r * sin(i * (M_PI * 2.0f) / numSides));
            zCoords[i] = z;
        }

        vertices = new GLfloat[numVertices * 3];
        for (auto i = 0; i < numVertices; i++) {
            vertices[i * 3] = xCoords[i];
            vertices[i * 3 + 1] = yCoords[i];
            vertices[i * 3 + 2] = zCoords[i];
        }
    }

    // This is where I go back to the learnopengl.com code. Once
    // again, the following works for quads but not circles!
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(
        GLfloat), vertices, GL_STATIC_DRAW);

    glBindVertexArray(vao);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(0, attribSize, GL_FLOAT, GL_FALSE,
        attribSize * sizeof(GLfloat), (GLvoid*)0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

下面是spritenderer::DrawSprite()方法(与原始方法的唯一区别是第24-28行):

void SpriteRenderer::Draw(vec2 position, vec2 size, GLfloat rotation, vec3 colour) {
    // Prepare transformations
    shader.Use();

    auto model = mat4(1.0f);
    model = translate(model, vec3(position, 0.0f));

    model = translate(model, vec3(0.5f * size.x, 0.5f * size.y, 0.0f));   // Move origin of rotation to center
    model = rotate(model, rotation, vec3(0.0f, 0.0f, 1.0f));              // Rotate quad
    model = translate(model, vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); // Move origin back

    model = scale(model, vec3(size, 1.0f)); // Lastly, scale

    shader.SetMatrix4("model", model);

    // Render textured quad
    shader.SetVector3f("spriteColour", colour);

    glActiveTexture(GL_TEXTURE0);
    texture.Bind();

    glBindVertexArray(vao);

    if (!isCircular) {
        glDrawArrays(GL_TRIANGLES, 0, 6);
    } else {
        glDrawArrays(GL_TRIANGLE_FAN, 0, 24);  // also tried "12" and "8" for the last param, to no avail
    }

    glBindVertexArray(0);
}

最后,着色器(不同于用于四边形的着色器):

// Vertex shader
#version 330 core

layout (location = 0) in vec3 position;

uniform mat4 model;
uniform mat4 projection;

void main() {
    gl_Position = projection * model *
        vec4(position.xyz, 1.0f);
}

// Fragment shader
#version 330 core

out vec4 colour;

uniform vec3 spriteColour;

void main() {    
    colour = vec4(spriteColour, 1.0);
}

P、 我知道我可以只用一个四边形,但我正在努力学习如何在OpenGL中绘制所有的基本体,而不仅仅是四边形和三角形(谢谢乔伊)!

P、 另外,我刚刚意识到learnopengl。com站点有一整节专门用于调试OpenGL应用程序,所以我设置了它,但没有用:-(我认为我的驱动程序(Intel UHD Graphics 620最新驱动程序)不支持错误处理,因为在遵循说明后没有设置GL\u CONTEXT\u FLAG\u DEBUG\u位:

在GLFW中请求调试上下文出乎意料地简单,因为我们所要做的就是向GLFW传递一个提示,即我们想要一个调试输出上下文。在调用glfwCreateWindow之前,我们必须这样做:

glfwWindowHint(GLFW\u OPENGL\u DEBUG\u CONTEXT,GL\u TRUE);

一旦我们初始化GLFW,如果我们使用的是OpenGL 4.3或更高版本,我们应该有一个调试上下文,否则我们必须抓住机会,希望系统仍然能够请求调试上下文。否则,我们必须使用其OpenGL扩展请求调试输出。

为了检查我们是否成功初始化了调试上下文,我们可以查询OpenGL:

闪烁标志;glGetIntgerv(GL_CONTEXT_FLAGS,

if(标志

如果从未输入语句,则为!

共有1个答案

宋俊民
2023-03-14

多亏了@Mykola对这个问题的回答,我已经走到了一半:

numVertices = 43;
vertices = new GLfloat[numVertices];

auto i = 2;
auto x = 0.0f,
     y = x,
     z = x,
     r = 0.3f;

auto numSides = 21;
auto TWO_PI = 2.0f * M_PI;
auto increment = TWO_PI / numSides;

for (auto angle = 0.0f; angle <= TWO_PI; angle += increment) {
    vertices[i++] = r * cos(angle) + x;
    vertices[i++] = r * sin(angle) + y;
}

我还有两个问题:

  1. 为什么有一条额外的线从中心到右侧,我如何修复它
 类似资料:
  • 举个简单的例子来说明正交投影与透视投影照相机的区别。使用透视投影照相机获得的结果是类似人眼在真实世界中看到的有“近大远小”的效果(如下图中的(a));而使用正交投影照相机获得的结果就像我们在数学几何学课上老师教我们画的效果,对于在三维空间内平行的线,投影到二维空间中也一定是平行的(如下图中的(b))。 (a)透视投影,(b)正交投影 那么,你的程序需要正交投影还是透视投影的照相机呢? 一般说来,对

  • 我只是试图用DrawOval()方法画圆,当我运行程序时,它只显示小正方形。我试图将构造函数添加到Surface类,但它不起作用。这是我制作的代码:

  • 正交投影照相机(Orthographic Camera)设置起来较为直观,它的构造函数是: THREE.OrthographicCamera(left, right, top, bottom, near, far) 这六个参数分别代表正交投影照相机拍摄到的空间的六个面的位置,这六个面围成一个长方体,我们称其为视景体(Frustum)。只有在视景体内部(下图中的灰色部分)的物体才可能显示在屏幕上,

  • 问题内容: 似乎没有绘制椭圆形形状的本机功能。我也不是在寻找蛋形。 是否可以绘制具有2个贝塞尔曲线的椭圆形?有人遇到过吗? 我的目的是画一些眼睛,实际上我只是使用弧线。提前致谢。 解 因此,scale()更改所有下一个形状的缩放比例。Save()之前保存设置,还原用于还原设置以绘制新形状而无需缩放。 感谢Jani 问题答案: 更新: 缩放方法可能会影响笔触宽度的外观 正确的缩放方法可以保持笔画宽度

  • 问题内容: 如何使用HTML5和CSS3画圆? 也可以在其中放入文字吗? 问题答案: 本身不能画一个圆。但是您可以制作与圆相同的东西。 您必须创建一个带有圆角(通过border-radius)的矩形,该圆角是要制作的圆的宽度/高度的一半。

  • 问题内容: 我目前正在尝试在mongodb内部的文档数组中提取单个对象。这是一个样本数据集: 我可以在mongo中使用以下命令成功查询: 我无法使用mgo进行相同操作,并尝试了以下操作: 使用嵌套(抛出:合成文字中缺少类型,地图文字中缺少键) 我正在使用httprouter,p.ByName(“ …”)调用是传递给处理程序的参数。 提前致谢。 问题答案: 将与该 方法一起使用,因为doc指出,这使