坐标系统

来源:互联网 发布:龙江网络电视投诉电话 编辑:程序博客网 时间:2024/05/29 02:40

最近在学习OpenGL,把学习的一些过程写在这里,希望与大家共同分享讨论。欢迎光临我的个人网站Orient一起讨论学习。这里是我的GitHub,如果您喜欢,不妨点个赞?☺

坐标系统分为五大类:

局部空间(Local Space)或被称为物体空间(Object Space)

指的是单个物体的坐标系统。

世界空间(World Space)

指多个物体同时放在一个世界的坐标系统。物体坐标从局部空间变换到世界空间是由模型矩阵(Model Matrix)实现的。

模型矩阵:是一种变幻矩阵,它通过对物体进行位移、缩放、旋转来将它放置在预期的位置或朝向。

观察空间(View Space)或被称为视觉空间(Eye Space)、摄像机空间(Camera Space)

将世界空间坐标转化为用户视野前方的坐标而产生的结果。也就是从摄像机视角所观察到的空间。通常由一系列的唯一和旋转的组合来完成。

这些组合被存储在一个观察矩阵(View Matrix)里,它被用来将世界坐标变幻到观察空间坐标。

裁剪空间(Clip Space)

将规定范围之外的物体裁剪掉(不可视化)。它由投影矩阵(Projection Matrix)实现。

投影分为正射投影透视投影

创建正射投影矩阵可以用GLM的内置函数glm::ortho:

/*p1、p2:指定了平截头体的左右坐标, *p3、p4:制订了平截头体的底部和顶部, *p5、p6:定义了近平面和远平面的距离 */glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);

创建透视投影矩阵可以用以下函数创建:

/*p1:定义了fov(视野:`Field of View`)的值,并且设置了观察空间的大小,一般为了真实效果,设置为45.0f, *p2:设置宽高比,由视口宽除以高所得, *p3、p4:设置了平截头体的近、远平面距离,通常按以下值设置。 */glm::nat4 proj = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);

屏幕空间(Screen Space)

屏幕空间也就是我们在屏幕上所能看见的一个窗口空间

一个物体的顶点坐标起始于局部空间(Local Space),在这里被称为局部坐标(Local Coordinate),之后会变味世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),在最后以屏幕坐标(Screen Coordinate)的形式结束

一个顶点坐标将会根据以下过程变换到裁剪坐标:

V(clip) = M(projection) · M(view) · M(model) · V(local)

最后顶点应该被赋值到顶点着色器中的gl_Position, OpenGL将会自动进行透视除法裁剪将其变化到标准化设备坐标,然后通过glViewPort内部的参数来将标准化设备坐标映射到屏幕坐标。

3D

模型矩阵

创建一个包含位移、缩放与旋转的模型矩阵,将物体变换到全局的世界空间,下面这个模型矩阵使得物体绕x轴旋转,使它看起来像放在地上一样:

glm::mat4 model;model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));

观察矩阵

创建一个观察矩阵,将物体在场景里稍微后移,以使得物体变成可见的:

glm::mat4 viewview = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

投影矩阵

最后定义一个投影矩阵,在这里使用透视投影:

glm::mat4 projectionprojection = glm::perspective(glm::radians(45.0f), screenWidth / screenHeight, 0.1f, 100.0f);

申明uniform变换矩阵

创建变换矩阵后,将它们传入着色器。首先申明一个uniform变换矩阵然后将它乘以顶点坐标:

#version 410 corelayout (location = 0) in vec3 aPos;...uniform mat4 model;uniform mat4 view;uniform mat4 projection;void main(){    gl_Position = projection * view * model * vec4(aPos, 1.0);}

然后将矩阵传入着色器(通常在每次的渲染迭代中进行,因为变换矩阵会经常变动):

int modelLoc = glGetUniformLocation(ourShader.ID, "model");glUnifromMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));...//观察矩阵和投影矩阵类似

绘制旋转的立方体

随时间旋转函数:

model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5, 1.0f, 0.0f));

使用glDrawArrays绘制立方体,总共36个顶点。

glDrawArrays(GL_TRIANGLES, 0, 36);

开始深度测试

z缓冲也叫深度缓冲(Depth Buffer),所有的深度信息都存储在其中。OpenGL会根据深度值来判断物体是否被遮挡,若是则丢弃。这个过程称为深度测试(Depth Testing),开启它需要添加以下函数:

glEnable(GL_DEPTH_TEST);

在每次迭代前需要清除深度缓冲:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

绘制更多立方体

首先在一个glm::vec3数组中定义10个立方体位置:

glm::vec3 cubePositions[] = {  glm::vec3( 0.0f,  0.0f,  0.0f),   glm::vec3( 2.0f,  5.0f, -15.0f),   glm::vec3(-1.5f, -2.2f, -2.5f),    glm::vec3(-3.8f, -2.0f, -12.3f),    glm::vec3( 2.4f, -0.4f, -3.5f),    glm::vec3(-1.7f,  3.0f, -7.5f),    glm::vec3( 1.3f, -2.0f, -2.5f),    glm::vec3( 1.5f,  2.0f, -2.5f),   glm::vec3( 1.5f,  0.2f, -1.5f),   glm::vec3(-1.3f,  1.0f, -1.5f)  };

在渲染循环当中调用glDrawArrays10次:

for (unsigned int i = 0; i < 10; i++) {    // calculate the matrix for each object and pass it to shader before drawing    glm::mat4 model;    model = glm::translate(model, cubePositions[i]);    float angle = 20.0f * (i + 1);    model = glm::rotate(model, (float)glfwGetTime() * glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));    ourShader.setMat4("model", model);    glDrawArrays(GL_TRIANGLES, 0, 36);}

最终绘制效果如下:
动图加载比较慢,请耐心等待

原创粉丝点击