OpenGL绘制旋转立方体。

首先要用到glm库。在进行PVM变换时可以帮助我们方便地运算。
下载:https://github.com/g-truc/glm/tags

首先是处理顶点数据,由于是一个正方体,有六个面,每个面两个三角形,一共36个点。输入顶点有顶点坐标和顶点的颜色值。这里的坐标是处在模型空间的坐标。

const float vertices[] = {                  //立方体数组
	-0.5f, -0.5f, -0.5f, 1.0f,0.0f,0.0f,    //六个面,每个面两个三角形。
	0.5f, -0.5f, -0.5f,  1.0f,0.0f,0.0f,    //每一行前三个为顶点的坐标,
	0.5f,  0.5f, -0.5f,  1.0f,0.0f,0.0f,    //后三个值为顶点颜色值
	0.5f,  0.5f, -0.5f,  1.0f,0.0f,0.0f,
	-0.5f,  0.5f, -0.5f,  1.0f,0.0f,0.0f,
	-0.5f, -0.5f, -0.5f,  1.0f,0.0f,0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f,1.0f,0.0f,
	0.5f, -0.5f,  0.5f,  0.0f,1.0f,0.0f,
	0.5f,  0.5f,  0.5f,  0.0f,1.0f,0.0f,
	0.5f,  0.5f,  0.5f,  0.0f,1.0f,0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f,1.0f,0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f,1.0f,0.0f,

	-0.5f,  0.5f,  0.5f,  0.0f,0.0f,1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f,0.0f,1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f,0.0f,1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f,0.0f,1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f,0.0f,1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f,0.0f,1.0f,

	0.5f,  0.5f,  0.5f,  0.5f,0.0f,0.0f,
	0.5f,  0.5f, -0.5f,  0.5f,0.0f,0.0f,
	0.5f, -0.5f, -0.5f,  0.5f,0.0f,0.0f,
	0.5f, -0.5f, -0.5f,  0.5f,0.0f,0.0f,
	0.5f, -0.5f,  0.5f,  0.5f,0.0f,0.0f,
	0.5f,  0.5f,  0.5f,  0.5f,0.0f,0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f,0.5f,0.0f,
	0.5f, -0.5f, -0.5f,  0.0f,0.5f,0.0f,
	0.5f, -0.5f,  0.5f,  0.0f,0.5f,0.0f,
	0.5f, -0.5f,  0.5f,  0.0f,0.5f,0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f,0.5f,0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f,0.5f,0.0f,

	-0.5f,  0.5f, -0.5f,  0.0f,0.0f,0.5f,
	0.5f,  0.5f, -0.5f,  0.0f,0.0f,0.5f,
	0.5f,  0.5f,  0.5f,  0.0f,0.0f,0.5f,
	0.5f,  0.5f,  0.5f,  0.0f,0.0f,0.5f,
	-0.5f,  0.5f,  0.5f,  0.0f,0.0f,0.5f,
	-0.5f,  0.5f, -0.5f,  0.0f,0.0f,0.5f
};

很繁杂,但是一般模型都是导入的,不用自己去一个个顶点的写。

接下来根据坐标转换流程来写:
在这里插入图片描述
PVM变换矩阵就对应于这个过程。

  • model矩阵对应模型变换过程,将局部坐标转换到世界坐标。
  • view矩阵对应

接下来是PVM变换矩阵。实际的变换顺序是“MVP”。Model矩阵用于将模型坐标转化为世界坐标。view矩阵用于从世界坐标转移到观察坐标,要设置观察摄像机的位置,观察方向和头顶方向。projection对应从观察空间到剪裁空间的变换,指定了坐标的范围。
在进入主循环后,得到pvm三个矩阵:

	// Transform坐标变换矩阵
		glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标
		model = glm::translate(model, glm::vec3(0.0, 0.0, 0.0));
		model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f));
		model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));
		glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系
		view = glm::lookAt(camera_position, camera_position + camera_front, camera_up);
		glm::mat4 projection(1);//projection矩阵,投影矩阵
		projection = glm::perspective(glm::radians(fov), (float)screen_width / screen_height, 0.1f, 100.0f);

这里之前要设置view矩阵中摄像机的各参数:

glm::vec3 camera_position = glm::vec3(0.0f, 0.0f, 3.0f);   // 摄像机位置
 
glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f);     // 摄像机方向
 
glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f);         // 摄像机上向量
 

以及projection矩阵中的视角:

float fov=45.0f;

首先计算的是model矩阵

  • 首先要创建一个model矩阵,glm::mat4 model(1)创建一个4*4的单位矩阵。
  • glm::translate()函数用于进行平移变换,将物体平移(0,0,0),也就是不变。
  • glm::rotate()函数用于旋转。第二个参数为旋转角度,第三个参数为旋转轴。这里的glfwGetTime是获取glfw初始化到当前状态所经过的秒数。如果是一个常数的话,就不会旋转了。那是因为每次进入循环之后矩阵在初始状态,都旋转同一个角度,那么肯定就看不到旋转。每次循环旋转不同角度,且这个角度的大小随时间变换,才能看得到旋转效果。
  • glm::scale()函数用于缩放,vec3指定x,y,z三个方向上的缩放比例。
glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标
model = glm::translate(model, glm::vec3(0.0,0.0,0.0));  
model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 
0.0f));  
model = glm::scale(model, glm::vec3(1.0f,1.0f,1.0f));  

接着是view矩阵

  • 首先还是要创建一个4*4的单位矩阵
  • 通过lookAt函数计算。第一个参数是相机位置,第二个参数是相机所正对的目标的坐标,这里用camera_position+camera_front(相机的方向)进行向量加法后可以得到相机正对的坐标。第三个参数是相机的上向量。
glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系
view = glm::lookAt(camera_position, camera_position + camera_front,  
camera_up);

最后是projection矩阵

  • 这是一个投影透视矩阵
  • 第一个参数fov是角度值,定义了视野。对一个真实的观察效果,通常设置为45,如果要看到更多东西需要设置一个更大的值.
  • 第二个参数设置宽高比,也就是屏幕宽度比上屏幕高度。
  • 第三个和第四个参数设置了平截头体(也就是一个四棱台)的近和远平面。通常设置最近距离为0.1,最远距离为100.0。所有在近平面和远平面的顶点且处于平截头体内的顶点都会被渲染。
glm::mat4 projection(1);//projection矩阵,投影矩阵
projection = glm::perspective(glm::radians(fov), (float)screen_width / 
screen_height, 0.1f, 100.0f); 

以上对model,view,projection矩阵进行初始化后,还要将这三个矩阵传入着色器内。

glGetUniformLocation函数可以获得某个着色器中参数的位置,第一个参数为着色器id,第二个参数为该参数的名字

int model_location = glGetUniformLocation(shader.ID, "model");  

glUniformMatrix4fv函数用于向指定位置传入一个4*4矩阵值。

glUniformMatrx4fv(model_location,1,GL_FALSE,glm::value_ptr(model));

接下来看顶点着色器的内容:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 PosColor;
out vec3 positionColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
	gl_Position = projection * view * model * vec4(aPos, 1.0);
	positionColor=PosColor;
}

可以看到这里的参数和我们在程序内设置的是对应的。
注意顺序。由于opengl的向量是列向量,与行向量算的方式相反。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用 OpenGL 绘制立方体旋转的示例代码: ```c++ #include <GL/glut.h> GLfloat angle = 0.0f; // 旋转角度 // 绘制立方体 void drawCube() { glBegin(GL_QUADS); // 前面 glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 后面 glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glVertex3f(1.0f, -1.0f, -1.0f); // 左面 glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 右面 glColor3f(1.0f, 1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 上面 glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 下面 glColor3f(1.0f, 0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glVertex3f(1.0f, -1.0f, -1.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); } // 显示回调函数 void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); // 平移 glRotatef(angle, 1.0f, 1.0f, 0.0f); // 绕 x 和 y 轴旋转 drawCube(); glutSwapBuffers(); } // 定时器回调函数,每隔一段时间更新角度并重绘 void timer(int value) { angle += 1.0f; if (angle >= 360.0f) { angle -= 360.0f; } glutPostRedisplay(); glutTimerFunc(16, timer, 0); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(640, 480); glutCreateWindow("OpenGL Cube"); glEnable(GL_DEPTH_TEST); glutDisplayFunc(display); glutTimerFunc(0, timer, 0); glutMainLoop(); return 0; } ``` 在 `drawCube()` 函数中绘制了一个立方体,使用 `glTranslatef()` 和 `glRotatef()` 进行平移和旋转,然后在 `display()` 函数中进行绘制,最后在 `timer()` 函数中更新角度并重绘。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值