OpenGL

GPU 实现 RGB -- YUV 转换 (OpenGL)

RGB --> YUV 转换的公式是现成的,直接在 CPU 端转换的话,只需要遍历每个像素,得到新的 YUV 值,根据其内存分布规律,合理安排分布即可。然而在 CPU 端进行转换,存在的问题运行效率太低,无法满足高效转换的需求。我们将目光投向拥有流水线体系的支持高速浮点数计算的硬件——GPU.

转换公式如下:

GPU 上面的实现

考虑在 GPU 上执行 RGB --> YUV 转换。GPU 的流水线操作:

vertices 
        ----> Pipeline ----> Out color
texture

所以将 RGB 图像作为纹理输入,流水线输出我们需要的 YUV 数据。前面一部分很好理解,图像作为唯一的纹理输入,没有别的选项。后面一部分的话,需要在输出的时候输出我们需要的 YUV 数据即可,在 fragment shader 中的输出按常理就是每一个 fragment 的颜色,为实现读取像素是 YUV 的目标,要调整输出的数据。

OpenGL——可编程管线基础光照的实现

在OpenGL中创建 基础光照 ,主要的工作将模型中的法线信息和法线空间运算矩阵传入到shader中。另一方面,LightDir,ViewDir通常是在shader中从引擎参数获取的,为了简化光照模型的实现,这里我们可以在shader中写死。至于经典的 ambient+diffuse+specular 光照原理,不是本文的重点,就在shader中一笔带过了。

原理

通过函数

glm::mat4 normalMatrix = glm::inverseTranspose(s_shaderData.model);

可以获取当前模型的法线矩阵。用来将法线信息从模型坐标转换为世界坐标。这个矩阵是随着模型的Transform改变而改变的,因此需要在Render时动态计算。

实现

在 基础光照 中,数据传递没什么特殊的,将Normal信息作为attribute传递到shader,将NormalMatrix作为uniform传递到shader。

//normalmatrix

OpenGL学习——颜色的选择

OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式。

无论哪种颜色模式,计算机都必须为每一个像素保存一些数据。不同的是,RGBA模式中,数据直接就代表了颜色;而颜色索引模式中,数据代表的是一个索引,要得到真正的颜色,还必须去查索引表。

1. RGBA颜色

RGBA模式中,每一个像素会保存以下数据:R值(红色分量)、G值(绿色分量)、B值(蓝色分量)和A值(alpha分量)。其中红、绿、蓝三种颜色相组合,就可以得到我们所需要的各种颜色,而alpha不直接影响颜色,它将留待以后介绍。

在RGBA模式下选择颜色是十分简单的事情,只需要一个函数就可以搞定。

glColor*系列函数可以用于设置颜色,其中三个参数的版本可以指定R、G、B的值,而A值采用默认;四个参数的版本可以分别指定R、G、B、A的值。例如:

void glColor3f(GLfloat red, GLfloat green, GLfloat blue);
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);

(还记得吗?3f表示有三个浮点参数~请看第二课中关于glVertex*函数的叙述。)

OpenGL光源位置

一、OpenGL光源简介

OpenGL提供了多种形式的光源,如点光源、平行光源和聚光灯光源等。所有光源都使用 glLight*接口来设置光源属性,其中包括 glLight{if} 和 glLight{if}v 两类。

1、示例光源

GLfloat ambient[] = {0.3f, 0.3f, 0.3f, 1.0f};  // 环境强度
GLfloat diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};  // 散射强度
GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; // 镜面强度

// 点光源, GL_POSITION属性的最后一个参数为1
GLfloat position[] = {-3.0f, -3.4f, -8.8f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);

OpenGL基础之Stencil Testing

stencil testing发生在fragment shader之后,depth testing之前,它利用stencil-buffer来舍弃一些片元,余下的会进入depth testing进行进一步的比较。

stencil buffer中每一个片元通常对应一个8bit的stencil value,也就是每一个像素或者片元可以设置256个不同的值,我们可以根据这些值来决定哪些片元可以保留,哪些可以舍弃。

OpenGL基础之Stencil Testing

我们可以在片元渲染的过程中,指定stencil-buffer中的值;在同一个渲染循环中,就可以读stencil buffer中的值,来保留或者舍弃一些片段,通常的流程如下:

1、开启写stencil-buffer

2、渲染物体,更新stencil-buffer

3、关闭写stencil-buffer

4、渲染物体,并根据stencil-testing结果舍弃一些片元

OpenGL基础之Depth Testing

就像color-buffer存储了所有片元的颜色一样,depth-buffer存储了每一个片元的深度信息。它是由窗口系统自动创建并存储深度值的,深度值的精度一般有16位、24位和32位float,比较常用的深度精度为24位。

当深度测试打开后,OpenGL会测试每个片元的深度值与depth-buffer中数值,如果测试通过,则会更新depth-buffer中的值,如果测试通不过,则会舍弃这个片元。

深度测试发生在片元着色器执行之后的屏幕空间,屏幕空间坐标与glViewport函数定义的视口大小直接相关,并且可以通过GLSL的内建变量gl_FragCoord来访问。gl_FragCoord代表了屏幕空间的坐标值(左下角为(0,0)),gl_FragCoord的z值就是片元的深度值,最后的深度测试就是对比这个值跟depth-buffer中的值。

现在大部分的GPU都支持一项称为early depth testing的特性,early depth testing允许在片元着色器执行之前进行深度测试,这样就可以避免那些根本看不到的片元进行片元着色,这样可以提高程序性能。但是,一旦使用了early depth testing,就不能再在片元着色器中写深度值。

OpenGL基础之Shadow Mapping

现有的实时渲染的阴影计算都是tricky的,还没有完美的阴影计算算法。但是有几种很不错的方法来计算阴影,这些方法或多或少都有一些问题,需要我们在实现的时候注意。

在现有的视频游戏领域,有一种称为shadow mapping的方法。该方法简单易懂,开销也低,可以提供一个不错的阴影效果,并且可以很方便地扩展到高级的阴影算法(OSM,CSM)。

shadow mapping的原理是:

我们从光源位置处渲染一遍场景(即将视点放在光源位置,渲染一次场景),所有在该视锥体中看到的物体,都是被光照照到的;所有没被看到的物体都是位于阴影中的。如图

OpenGL基础之Shadow Mapping

图中所有蓝色的片元都是被光照点亮的,而黑色的则处于阴影当中。

通过这种对比,我们可以利用深度图,来比较像素是否处于阴影当中,实现的方法是:

pass1:我们从光源位置渲染一遍场景,取得场景的深度buffer,输出为一张depth map或者叫shadow map的纹理;

OpenGL状态机理解

状态机是理论上的一种机器,呃这个说法非常非常的抽象。通俗一点理解,状态机描述了一个对象在其生命周期内所经历的各种状态,状态间的转变,发生转变的动因,条件及转变中所执行的活动。或者说,状态机是一种行为,说明对象在其生命周期中响应事件所经历的状态序列以及对那些状态事件的响应。因此具有以下特点:

1.有记忆功能,能记住其当前的状态;

2.可以接收输入,根据输入的内容和自己的原先状态,修改自己当前状态,并且可以有对应输出;

3.当进入特殊状态(停机状态)的时候,变不再接收输入,停止工作;

虽然还是很抽象,但结合实例理解就容易明白了,如身边的电脑,就是一典型的状态机,对照理解如下:

1. 电脑的存储器(内存、硬盘等),可以记住电脑自己当前的状态(如保存在电脑中的数据,即二进制的值,都属于当前的状态);

2. 电脑的输入设备接收输入(键盘和鼠标输入等),根据输入的内容和自己的状态,修改自己的状态(修改内存中的值),并且可以得到输出(将结果显示到屏幕)。

3. 当进入关机状态的时候,它不再接收输入,停止工作。

同理,OpenGL也可以类似这样的理解:

1. OpenGL可以记录自己的状态(如当前所使用的颜色、是否开启了混合功能等);

OpenGL绘制基本图形单元的方法

1.点绘制

OpenGL提供了一系列函数。它们都以glVertex开头,后面跟一个数字和1~2个字母。例如:
glVertex2d(x,y)
glVertex2f(x,y)
glVertex3f(x,y,z)

glVertex3fv(GLfloat *p)

数字表示参数的个数:

2表示有两个参数,3表示三个;

字母表示参数的类型:

i表示32位整数(OpenGL中将这个类型定义为GLint和GLsizei),
f表示32位浮点数(OpenGL中将这个类型定义为GLfloat和GLclampf),

d表示64位浮点数(OpenGL中将这个类型定义为GLdouble和GLclampd)。

glVertex2i(3, 3);
glVertex2f(3.0f, 3.0f);
glVertex3f(3.0f, 3.0f, 0.0f);

GLfloat p[] = { 3.0f,3.0f, 0.0f };

glVertex3fv(p)

注:OpenGL中定义的点可以有不同的尺寸,其函数形式为:

void glPointSize( GLfloat size );
  参数size设置点的宽度(以象素为单位),必须大于0.0,缺省时为1.0。

OpenGL学习——光照

OpenGL场景中模型颜色的产生,大致为如下的流程图所描述:

OpenGL学习——光照

(1)当不开启光照时,使用顶点颜色来产生整个表面的颜色。

用glShadeModel可以设置表面内部像素颜色产生的方式。GL_FLAT/GL_SMOOTH.

(2)一般而言,开启光照后,在场景中至少需要有一个光源(GL_LIGHT0...GL_LIGHT7)

通过glEnable(GL_LIGHT0) glDisable(GL_LIGHT0) 来开启和关闭指定的光源。

--- 全局环境光 ---

GLfloat gAmbient[] = {0.6, 0,6, 0,6, 1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gAmbient);

(3)设置光源的光分量 -- 环境光/漫色光/镜面光

默认情况下:

同步内容
--电子创新网--
粤ICP备12070055号