NDK OpenGL ES 3.0 开发(八):坐标系统

简介: OpenGL 坐标系统

作者:字节流动

来源:https://blog.csdn.net/Kennethdroid/article/details/100898155

OpenGL 坐标系统

我们知道 OpenGL 坐标系中每个顶点的 x,y,z 坐标都应该在 -1.0 到 1.0 之间,超出这个坐标范围的顶点都将不可见。


将一个物体(图像)渲染到屏幕上,通常经过将物体坐标转换为标准化设备坐标,然后再将标准化设备坐标转化为屏幕坐标的过程。


该过程通常涉及多个坐标系统的变换,将所有顶点转换为片段之前,顶点需要处于不同的坐标系统进行计算,对我们来说比较重要的有 5 个坐标系统:

  • 局部空间(Local Space,或者物体空间(Object Space))
  • 世界空间(World Space)
  • 观察空间(View Space,
  • 裁剪空间(Clip Space)
  • 屏幕空间(Screen Space)

image.png

局部空间

局部空间 (Local Space) 是指对象所在的坐标空间,坐标原点由你自己指定,模型的所有顶点相对于你的对象来说都是局部的。


世界空间

在世界空间(World Space)主要实现对象的平移、缩放、旋转变换,将它们放在我们指定的位置,这些变换是通过模型矩阵(Model Matrix)实现的。

在 C/C++ 中可以利用 GLM 构建模型矩阵:

glm::mat4 Model = glm::mat4(1.0f); //单位矩阵
Model = glm::scale(Model, glm::vec3(2.0f, 2.0f, 2.0f)); //缩放
Model = glm::rotate(Model, MATH_PI/2, glm::vec3(1.0f, 0.0f, 0.0f)); //沿 x 轴旋转 90 度
Model = glm::translate(Model, glm::vec3(0.0f, 1.0f, 0.0f)); //沿 y 轴正方向平移一个单位

GLM 是 OpenGL Mathematics 的缩写,它是一个只有头文件的库,也就是说我们只需包含对应的头文件就行了,不用链接和编译。GLM 可以在 Github 上下载,把头文件的根目录复制到你的includes文件夹,然后你就可以使用这个库了。


观察空间

观察空间(View Space)也被称为 OpenGL 相机空间,即从摄像机的角度观察到的空间,它将对象的世界空间的坐标转换为观察者视野前面的坐标,这通常是由一系列的平移和旋转的组合来平移和旋转场景从而使得特定的对象被转换到摄像机前面,这些组合在一起的转换通常存储在一个**观察矩阵(View Matrix)**里。

在 C/C++ 中可以利用 GLM 构建观察矩阵:

// View matrix
glm::mat4 View = glm::lookAt(
      glm::vec3(0, 0, 3), // Camera is at (0,0,1), in World Space 相机位置
      glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
      glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down) 相机 up 方向,即相机头部朝向
);

裁剪空间

裁剪空间(Clip Space)是用来裁剪观察对象的空间,在一个顶点着色器运行的最后,OpenGL 期望所有的坐标都能落在一个给定的范围内,且任何在这个范围之外的点都应该被裁剪掉。**投影矩阵(Projection Matrix)**用来将顶点坐标从观察空间转换到裁剪空间。

投影矩阵一般分为两种:正交投影(Orthographic Projection)和透视投影(Perspective Projection)。

image.png

正交投影

image.png

正交投影是一种平行投影,投影点与原顶点的连线相互平行,且物体不产生“近大远小”的视觉效果。

在 C/C++ 中可以利用 GLM 构建正交投影矩阵:

glm::mat4 Projection = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f, 100.0f); //ratio 一般表示视口的宽高比,width/height

前两个参数指定了平截头体的左右坐标,第三和第四参数指定了平截头体的底部和上部。通过这四个参数我们定义了近平面和远平面的大小,然后第五和第六个参数则定义了近平面和远平面的距离。这个指定的投影矩阵将处于这些 x,y,z 范围之间的坐标转换到标准化设备坐标系中。

透视投影image.png

透视投影的投影线相交于一点,可以用来模拟真实世界“近大远小”的视觉效果。

在 C/C++ 中可以利用 GLM 构建透视投影矩阵:

glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f); //ratio 一般表示视口的宽高比,width/height, 

它的第一个参数定义了 fov 的值,它表示的是视野(Field of View),并且设置了观察空间的大小。对于一个真实的观察效果,它的值经常设置为 45.0,但想要看到更多结果你可以设置一个更大的值。第二个参数设置了宽高比,由视口的高除以宽。第三和第四个参数设置了平截头体的近和远平面。我们经常设置近距离为 0.1 而远距离设为 100.0 。所有在近平面和远平面的顶点且处于平截头体内的顶点都会被渲染。

最后整个坐标系统的变换矩阵可以用一个矩阵表示 MVPMatrix = Projection * View * Model;

OpenGL 3D 变换实现

实现 OpenGL 3D 效果最简单的方式是在顶点着色器中将顶点坐标与 MVP 变换矩阵相乘:

#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
uniform mat4 u_MVPMatrix;
out vec2 v_texCoord;
void main()
{
    gl_Position = u_MVPMatrix * a_position; //顶点坐标与 MVP 变换矩阵相乘
    v_texCoord = a_texCoord;
}

在绘制之前构建变换矩阵:

/**
 * @param angleX 绕X轴旋转度数
 * @param angleY 绕Y轴旋转度数
 * @param ratio 宽高比
 * */
void CoordSystemSample::UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio)
{
  LOGCATE("CoordSystemSample::UpdateMVPMatrix angleX = %d, angleY = %d, ratio = %f", angleX, angleY, ratio);
  angleX = angleX % 360;
  angleY = angleY % 360;
  //转化为弧度角
  float radiansX = static_cast<float>(MATH_PI / 180.0f * angleX);
  float radiansY = static_cast<float>(MATH_PI / 180.0f * angleY);
  // Projection matrix
  //glm::mat4 Projection = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.1f, 100.0f);
  //glm::mat4 Projection = glm::frustum(-ratio, ratio, -1.0f, 1.0f, 4.0f, 100.0f);
  glm::mat4 Projection = glm::perspective(45.0f,ratio, 0.1f,100.f);
  // View matrix
  glm::mat4 View = glm::lookAt(
      glm::vec3(0, 0, 4), // Camera is at (0,0,1), in World Space
      glm::vec3(0, 0, 0), // and looks at the origin
      glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
  );
  // Model matrix
  glm::mat4 Model = glm::mat4(1.0f);
  Model = glm::scale(Model, glm::vec3(1.0f, 1.0f, 1.0f));
  Model = glm::rotate(Model, radiansX, glm::vec3(1.0f, 0.0f, 0.0f));
  Model = glm::rotate(Model, radiansY, glm::vec3(0.0f, 1.0f, 0.0f));
  Model = glm::translate(Model, glm::vec3(0.0f, 0.0f, 0.0f));
  mvpMatrix = Projection * View * Model;
}

绘制时传入变换矩阵:

void CoordSystemSample::Draw(int screenW, int screenH)
{
  LOGCATE("CoordSystemSample::Draw()");
  if(m_ProgramObj == GL_NONE || m_TextureId == GL_NONE) return;
    // 旋转角度变换,更新变换矩阵
  UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, (float)screenW / screenH);
  //upload RGBA image data
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, m_TextureId);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
  glBindTexture(GL_TEXTURE_2D, GL_NONE);
  // Use the program object
  glUseProgram (m_ProgramObj);
  glBindVertexArray(m_VaoId);
    // 将总变换矩阵传入着色器程序
  glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
  // Bind the RGBA map
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, m_TextureId);
  glUniform1i(m_SamplerLoc, 0);
  glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0);
}

效果演示


「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

阿里云社区.png

相关文章
|
6月前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
150 1
Android开发之使用OpenGL实现翻书动画
|
6月前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
75 1
Android开发之OpenGL的画笔工具GL10
|
6月前
|
前端开发 API vr&ar
Android开发之OpenGL绘制三维图形的流程
即将连载的系列文章将探索Android上的OpenGL开发,这是一种用于创建3D图形和动画的技术。OpenGL是跨平台的图形库,Android已集成其API。文章以2D绘图为例,解释了OpenGL的3个核心元素:GLSurfaceView(对应View)、GLSurfaceView.Renderer(类似Canvas)和GL10(类似Paint)。通过将这些结合,Android能实现3D图形渲染。文章介绍了Renderer接口的三个方法,分别对应2D绘图的构造、测量布局和绘制过程。示例代码展示了如何在布局中添加GLSurfaceView并注册渲染器。
197 1
Android开发之OpenGL绘制三维图形的流程
|
6月前
|
XML Java Android开发
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
79 1
|
6月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
124 0
|
存储 编解码 算法
Opengl ES之LUT滤镜(上)
Opengl ES之连载系列
458 0
|
数据安全/隐私保护 开发者
OpenGL ES 多目标渲染(MRT)
Opengl ES连载系列
319 0
|
数据安全/隐私保护 索引
Opengl ES之纹理数组
Opengl ES连载系列
257 0
|
数据安全/隐私保护
Opengl ES之水印贴图
Opengl ES之连载系列
150 0
|
Java 数据安全/隐私保护 Android开发
Opengl ES之矩阵变换(下)
Opengl ES连载系列
130 0