OpenGL4:旋转看起来完全错误
OpenGL4: Rotation looks all wrong
这是我正在绘制的四边形的顶点缓冲区信息:
static const GLfloat pv_quad[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
这个四边形用于在屏幕上绘制二维框架作为图形用户界面的一部分。我用来执行此操作的 class 是 Mage::Interface::Frame
。我将为您省去 header 定义,而是为您提供 class 的实现,因为它很小。这里有一些测试代码,所以忽略着色器是 class 的一部分这一事实。我知道它不应该在那里。
#include <Mage/Root.h>
#include <Mage/Interface/Frame.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
using Mage::Interface::Frame;
Frame::Frame()
: width(300), height(200), position(0, 0), color(1.0, 1.0, 1.0), model(1.0), rotation(0) {
prog.compileFile("Data/Shaders/FrameVertex.glsl", Mage::ShaderType::VERTEX);
prog.compileFile("Data/Shaders/FrameFragment.glsl", Mage::ShaderType::FRAGMENT);
prog.link();
this->calcTransform();
}
void Frame::setSize(int w, int h) {
this->width = w;
this->height = h;
this->calcTransform();
}
void Frame::setColor(int r, int g, int b) {
this->color = glm::vec3(float(r) / 256, float(g) / 256, float(b) / 256);
}
void Frame::setRotation(float degrees) {
this->rotation = glm::radians(degrees);
this->calcTransform();
}
void Frame::calcTransform() {
this->model = glm::mat4(1.0f); // reset model to origin.
// 1280 and 720 are the viewport's size. This is only hard coded for tests.
this->model = glm::scale(this->model, glm::vec3(float(width) / 1280, float(height) / 720, 1.0f));
this->model = glm::rotate(this->model, this->rotation, glm::vec3(0.0f, 0.0f, 1.0f));
this->model = glm::translate(this->model, glm::vec3(position.x, position.y, 0.0f));
}
void Frame::draw() {
Mage::VertexObject obj = ROOT.getRenderWindow()->getVertexBufferObject()->getObject("PrimitiveQuad");
prog.use();
prog.setUniform("mvp", this->model);
prog.setUniform("fColor", this->color);
glEnableVertexAttribArray(0);
ROOT.getRenderWindow()->getVertexBufferObject()->bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)obj.begin);
glDrawArrays(GL_TRIANGLE_STRIP, 0, obj.size);
glDisableVertexAttribArray(0);
}
这是每帧调用的绘图函数:
void RenderWindow::render() {
Mage::Interface::Frame F;
F.setSize(400, 200);
F.setRotation(0);
while (glfwWindowShouldClose(this->win) == 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
F.draw();
glfwSwapBuffers(this->win);
glfwPollEvents();
}
}
当我有 setRotation(0)
时,生成的四边形确实是 400 像素宽和 200 像素高,正如您所期望的那样,就在我的屏幕中央。
但是,如果我将旋转设置为 (90),那么,会发生这种情况:
如您所见,这根本不是接近 90 度的转弯。它应该是 400px 高和 200px 宽。
有人愿意解释一下这是怎么回事吗?
编辑: 一些尝试告诉我问题出在比例上,而不是旋转。当我注释掉比例时,旋转似乎是正确的。
glm::rotate()
的 angle
参数以弧度为单位,而不是度数:
m
: Input matrix multiplied by this rotation matrix.
angle
: Rotation angle expressed in radians.
axis
: Rotation axis, recommanded [sic] to be normalized.
使用这个:
void Frame::setRotation(float degrees) {
this->rotation = glm::radians( degrees );
this->calcTransform();
}
我假设这个游戏应该是一个带有 2D GUI 的 3D 游戏,虽然这在问题中没有指定,但不是完全必要的,因为我的答案是一样的。
当使用 3D 矩阵渲染时,使用透视图(考虑视野),而不是使用正交视图,形状将根据 fov 弯曲到它们的位置。
因此,我建议您使用一个简单的解决方案,并为您的 2D 界面初始化一个 2D 观察矩阵(或正交矩阵)。如果您只是在寻找一种将 2D 四边形渲染到屏幕上的简单方法,freeGLUT(免费图形库实用工具包)正适合您。有很多文档可以帮助安装 freeglut,所以一旦完成,初始化一个 2D 渲染矩阵,然后使用 glVertex2i/f 或 glVertex3i/f 渲染四边形,如下所示:
void setView2d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, *SCREEN_WIDTH, *SCREEN_HEIGHT, 0);
glMatrixMode( GL_MODELVIEW );
glDisable(GL_DEPTH_TEST);
glLoadIdentity();
}
void setView3d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, (GL_FLOAT)*SCREEN_WIDTH / *SCREEN_HEIGHT, 0.1, 100);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_TEST);
setView2d(); //Render 2D objects
glPushMatrix();
{
//glTranslatef() and glRotatef() still work for 2D
//if using rotate, rotate on z axis, like so:
glRotatef(90, 0, 0, 1);
glBegin(GL_TRIANGLES);
{
glVertex2i(0, 0);
glVertex2i(100, 0);
glVertex2i(0, 100);
/*
glVertex2i is replacable with glVertex2f, glVertex3i, and glVertex3f
if using a glVertex3, set the z value to 0
*/
}
glEnd();
}
glPopMatrix();
setView3d(); //Render 3D objects
glPushMatrix();
{
//render 3D stuff
}
glPopMatrix();
glutSwapBuffers();
}
我还应该提到,在使用 gluOrtho2D 时,顶点 x、y 中使用的坐标基于像素,而不是 3D 块。
希望对您有所帮助,
-尼克
这是我正在绘制的四边形的顶点缓冲区信息:
static const GLfloat pv_quad[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
这个四边形用于在屏幕上绘制二维框架作为图形用户界面的一部分。我用来执行此操作的 class 是 Mage::Interface::Frame
。我将为您省去 header 定义,而是为您提供 class 的实现,因为它很小。这里有一些测试代码,所以忽略着色器是 class 的一部分这一事实。我知道它不应该在那里。
#include <Mage/Root.h>
#include <Mage/Interface/Frame.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
using Mage::Interface::Frame;
Frame::Frame()
: width(300), height(200), position(0, 0), color(1.0, 1.0, 1.0), model(1.0), rotation(0) {
prog.compileFile("Data/Shaders/FrameVertex.glsl", Mage::ShaderType::VERTEX);
prog.compileFile("Data/Shaders/FrameFragment.glsl", Mage::ShaderType::FRAGMENT);
prog.link();
this->calcTransform();
}
void Frame::setSize(int w, int h) {
this->width = w;
this->height = h;
this->calcTransform();
}
void Frame::setColor(int r, int g, int b) {
this->color = glm::vec3(float(r) / 256, float(g) / 256, float(b) / 256);
}
void Frame::setRotation(float degrees) {
this->rotation = glm::radians(degrees);
this->calcTransform();
}
void Frame::calcTransform() {
this->model = glm::mat4(1.0f); // reset model to origin.
// 1280 and 720 are the viewport's size. This is only hard coded for tests.
this->model = glm::scale(this->model, glm::vec3(float(width) / 1280, float(height) / 720, 1.0f));
this->model = glm::rotate(this->model, this->rotation, glm::vec3(0.0f, 0.0f, 1.0f));
this->model = glm::translate(this->model, glm::vec3(position.x, position.y, 0.0f));
}
void Frame::draw() {
Mage::VertexObject obj = ROOT.getRenderWindow()->getVertexBufferObject()->getObject("PrimitiveQuad");
prog.use();
prog.setUniform("mvp", this->model);
prog.setUniform("fColor", this->color);
glEnableVertexAttribArray(0);
ROOT.getRenderWindow()->getVertexBufferObject()->bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)obj.begin);
glDrawArrays(GL_TRIANGLE_STRIP, 0, obj.size);
glDisableVertexAttribArray(0);
}
这是每帧调用的绘图函数:
void RenderWindow::render() {
Mage::Interface::Frame F;
F.setSize(400, 200);
F.setRotation(0);
while (glfwWindowShouldClose(this->win) == 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
F.draw();
glfwSwapBuffers(this->win);
glfwPollEvents();
}
}
当我有 setRotation(0)
时,生成的四边形确实是 400 像素宽和 200 像素高,正如您所期望的那样,就在我的屏幕中央。
但是,如果我将旋转设置为 (90),那么,会发生这种情况:
如您所见,这根本不是接近 90 度的转弯。它应该是 400px 高和 200px 宽。
有人愿意解释一下这是怎么回事吗?
编辑: 一些尝试告诉我问题出在比例上,而不是旋转。当我注释掉比例时,旋转似乎是正确的。
glm::rotate()
的 angle
参数以弧度为单位,而不是度数:
m
: Input matrix multiplied by this rotation matrix.
angle
: Rotation angle expressed in radians.
axis
: Rotation axis, recommanded [sic] to be normalized.
使用这个:
void Frame::setRotation(float degrees) {
this->rotation = glm::radians( degrees );
this->calcTransform();
}
我假设这个游戏应该是一个带有 2D GUI 的 3D 游戏,虽然这在问题中没有指定,但不是完全必要的,因为我的答案是一样的。
当使用 3D 矩阵渲染时,使用透视图(考虑视野),而不是使用正交视图,形状将根据 fov 弯曲到它们的位置。
因此,我建议您使用一个简单的解决方案,并为您的 2D 界面初始化一个 2D 观察矩阵(或正交矩阵)。如果您只是在寻找一种将 2D 四边形渲染到屏幕上的简单方法,freeGLUT(免费图形库实用工具包)正适合您。有很多文档可以帮助安装 freeglut,所以一旦完成,初始化一个 2D 渲染矩阵,然后使用 glVertex2i/f 或 glVertex3i/f 渲染四边形,如下所示:
void setView2d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, *SCREEN_WIDTH, *SCREEN_HEIGHT, 0);
glMatrixMode( GL_MODELVIEW );
glDisable(GL_DEPTH_TEST);
glLoadIdentity();
}
void setView3d()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, (GL_FLOAT)*SCREEN_WIDTH / *SCREEN_HEIGHT, 0.1, 100);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_TEST);
setView2d(); //Render 2D objects
glPushMatrix();
{
//glTranslatef() and glRotatef() still work for 2D
//if using rotate, rotate on z axis, like so:
glRotatef(90, 0, 0, 1);
glBegin(GL_TRIANGLES);
{
glVertex2i(0, 0);
glVertex2i(100, 0);
glVertex2i(0, 100);
/*
glVertex2i is replacable with glVertex2f, glVertex3i, and glVertex3f
if using a glVertex3, set the z value to 0
*/
}
glEnd();
}
glPopMatrix();
setView3d(); //Render 3D objects
glPushMatrix();
{
//render 3D stuff
}
glPopMatrix();
glutSwapBuffers();
}
我还应该提到,在使用 gluOrtho2D 时,顶点 x、y 中使用的坐标基于像素,而不是 3D 块。
希望对您有所帮助,
-尼克