基础渲染技术介绍

作者:张辰
单位:中国移动智慧家庭运营中心
来源:移动Labs

随着硬件计算能力越来越强大,GPU的功能在近几年也得到了前所未有的提升,无论是游戏狂热爱好者还是不爱玩游戏的普通用户都在5G和AR VR的变革中受到了不同程度的影响,有的可能从技术提升中得到了更好的游戏体验,有的可能在虚拟现实中找到了另一种娱乐方式,比如迪士尼裸眼3D技术让游客可以体验到身临其境般的感觉,这些技术的基础都与渲染技术密切相关,那这次我们就来了解下基础的渲染技术。


Part 01、渲染技术基本API

目前通用的底层渲染使用的API接口主要有以下几种:

基础渲染技术介绍

微软公司在Microsoft Windows操作系统上所开发的一套3D绘图编程接口,是DirectX的一部分,目前广为各家显示卡所支援,是与OpenGL同为电脑绘图软体和电脑游戏最常使用的两套绘图编程接口之一,目前只在Windows平台上可用。

OpenGL(开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。OpenGL常用于CAD、虚拟实境、科学可视化程序和电子游戏开发。

OpenGL的高效实现(利用了图形加速硬件)存在于Windows,部分UNIX平台和Mac OS,对于不同的平台,opengl开发出了不同的版本如OpenGL,OpenGL Es,WebGL,满足了渲染接口对不同平台的兼容性。

Vulkan是一个跨平台的2D和3D绘图应用程序接口(API),最早由科纳斯组织(Khronos Group) 在2015年游戏开发者大会(GDC)上发表。科纳斯最先把VulkanAPI称为“下一代OpenGL行动”(next generation OpenGL initiative)或“glNext”,但在正式宣布Vulkan之后这些名字就没有再使用了。就像OpenGL,Vulkan针对实时3D程序(如电子游戏)设计,Vulkan并计划提供高性能和低CPU管理负担(overhead),这也是Direct3D12和AMD的Mantle的目标。Vulkan兼容Mantle的一个分支,并使用了Mantle的一些组件。Vulkan旨在提供更低的CPU开销与更直接的GPU控制,其理念大致与Direct3D 12和Mantle类似。Vulkan不再使用OpenGL的状态机设计,内部也不保存全局状态变量。显示资源全然由应用层负责管理,包括内存管理、线程管理、多线程绘制命令产生、渲染队列提交等。应用程序能够充分利用CPU的多核多线程的计算资源,降低CPU等待,降低延迟。但带来的问题是:线程间的同步问题也由应用程序负责,从而对开发人员的要求也更高。

在WWDC 2014上,Apple为游戏开发者推出了新的平台技术 Metal,该技术能够为3D图像提高10倍的渲染性能,并支持大家熟悉的游戏引擎及公司。Metal 是一项全新的技术,专为开发高临场感主机游戏的开发者打造,可让开发者全力发挥A7和A8芯片的性能。该技术经过优化,使处理器和图形处理器能够协同工作来实现最优性能。它专为多线程而设计,并提供各种出色工具将所有素材整合在Xcode中。


Part 02、用OpenGL来渲染一个简单的三角形

我们前面了解了目前常用的图形学渲染API,那我们现在就用其中的一种来实践一下吧。

我们的目标是通过提供的API接口来渲染一个三角形,所以我们要先了解一下用OpenGL渲染的一些基础知识。

2.1 渲染管线

无论是OpenGL 还是其他的渲染API,其设计的逻辑都是将渲染的流程抽象为管线的形式(Graphics Pipeline),顾名思义,渲染管线就是将3D或者2D的图像通过一系列的处理,最终显示在屏幕上的处理流水线,类似于工厂用生产猪肉罐头的产品线,无非是到哪一步做哪些事。下面我们看下基础的流水线图(visio):

首先,我们要准备好顶点数据,可以看做一个顶点的数组,后续渲染的操作都是由顶点的计算开始的,一个三维的顶点数据在顶点着色器中会经过坐标系变换、光照计算、投影计算等最终留下需要渲染的顶点,送到下一步继续处理。

基础渲染技术介绍

在上一步得到的顶点数据中,通过开发者配置的图元信息,来将得到的顶点组装成图元,如(顶点,线,三角形,多边形等),然后将装配好的图元送到几何着色器中重新细化几何图案。如原本的图元是三角形,可以通过添加顶点的方式,将其变换为多个三角形,也可以变换为多边形等,最终输出新的图元信息到光栅化阶段。

在光栅化阶段,图元信息会被采样,通过不同的算法进行的采样可以得到不同像素值,最终生成不同的像素片段,这个片段可以供片段着色器使用,以此来进行着色操作。

在片段着色器中,通过光栅化得到的片段,在shader中进行像素计算,输出像素值进行着色,着色后的片段,需要经过最后一步,即测试(深度测试,模板测试等),再经过混合着色最终显示到屏幕上。

2.2 代码部分

首先,我们创建一个顶点数组:

float vertices[] = 
{ -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f };

顶点的值归一化到(-1.0f - 1.0f)方便绘制,然后,我们创建渲染所使用的顶点shader和片段shader。

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";

const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

并且将两个shader通过动态编译的方式完成GPU部分的编译、链接,最终生成程序使用的Program。

glCompileShader(vShader);
glCompileShader(fShader);
glLinkProgram(shaderProgram);

然后,我们将要创建存储顶点信息的顶点属性buffer,

glGenVertexArrays(1, &VAO);

可以创建一个管理顶点信息顶点数组。

glGenBuffers(1, &VBO);

可以创建一个用于存储顶点数据的buffer。然后我们绑定buffer并上传数据:

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW)

使能顶点属性,并且指定数据起始位置:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
 glEnableVertexAttribArray(0);

glUseProgram(shaderProgram);
glBindVertexArray(VAO); 
glDrawArrays(GL_TRIANGLES, 0, 3);

然后在主循环中,调用创建好的shaderProgram和VAO,绑定到当前的渲染状态中,通过glDrawXXX来绘制图元,我们要绘制的是一个三角形,所以顶点是3个,索引是0。

我们在绘制之后就可以看到如下的结果了:

基础渲染技术介绍

这样,一个简单的OpenGL的例子就完成了,是不是看起来一点都不复杂。当我们熟练了整个流程,我们就可以绘制更加复杂的模型,添加更加真实的效果,感兴趣的话那就赶紧动手试试吧!


本文转自:移动Labs,作者:张辰,转载此文目的在于传递更多信息,版权归原作者所有。如不支持转载,请联系小编demi@eetrend.com删除。

最新文章