Mikeee 的blog

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)设置光源的光分量 -- 环境光/漫色光/镜面光

默认情况下:

关于OpenGL的绘制上下文

什么是绘制上下文(Rendering Context)

初学OpenGL,打开红宝书,会告诉你OpenGL是个状态机,OpenGL采用了客户端-服务器模式,那时觉得好抽象,直到后来了解了绘制上下文才把这些联系起来。我们可以认为每一个硬件GPU是个服务器,每一个绘制上下文对应于申请的一个客户端,一个客户端维护着一套状态机,如果两个窗口分别对应两个不同的绘制上下文,则两个窗口彼此状态独立。申请绘制上下文,意味着系统资源的申请,每个绘制上下文还是需要不少资源的,记得曾经试过在chrome的TAB页不断加载WebGL页面,由于WebGL使用的是OpenGL ES,同样需要绘制上下文,当加载三十多个页面的时候,Chrome整个崩溃了。

所有的OpenGL调用,都需要指定是在哪个上下文环境下调用的。不同的上下文中,同样的资源ID,可能对应于各自上下文中不同类型的资源。

不同的操作系统,都有各自的绘制上下文创建、和设置当前绘制上下文的API。

如何创建绘制上下文

[译]OpenGL像素缓冲区对象

OpenGL ARB_pixel_buffer_object 扩展与ARB_vertex_buffer_object.很相似。为了把像素数据你储存在缓冲区对象中,而非顶点数据,它简单地扩展了 ARB_vertex_buffer_object extension。储存像素数据的缓冲区对象称为Pixel Buffer Object (PBO). ARB_pixel_buffer_object extension借用了VBO所有的架构及API,但多了两个"target" 标签。target协助PBO储存管理器(OpenGL驱动)决定缓冲区对象的最佳位置: system 内存, AGP (共享内存)或显卡内存。Target标志指定PBO的两种不同的操作:GL_PIXEL_PACK_BUFFER_ARB 传递像素数据到PBO中。或GL_PIXEL_UNPACK_BUFFER_ARB 从PBO中传回数据。

OpenGL像素缓冲区对象

OpenGL——混合的基本知识

混合是一种常用的技巧,通常可以用来实现半透明。但其实它也是十分灵活的,你可以通过不同的设置得到不同的混合结果,产生一些有趣或者奇怪的图象。

混合是什么呢?混合就是把两种颜色混在一起。具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果。

假设我们需要绘制这样一个场景:透过红色的玻璃去看绿色的物体,那么可以先绘制绿色的物体,再绘制红色玻璃。在绘制红色玻璃的时候,利用“混合”功能,把将要绘制上去的红色和原来的绿色进行混合,于是得到一种新的颜色,看上去就好像玻璃是半透明的。

要使用OpenGL的混合功能,只需要调用:glEnable(GL_BLEND);即可。
要关闭OpenGL的混合功能,只需要调用:glDisable(GL_BLEND);即可。

注意:只有在RGBA模式下,才可以使用混合功能,颜色索引模式下是无法使用混合功能的。

一、源因子和目标因子

前面我们已经提到,混合需要把原来的颜色和将要画上去的颜色找出来,经过某种方式处理后得到一种新的颜色。这里把将要画上去的颜色称为“源颜色”,把原来的颜色称为“目标颜色”。

OpenGL中的坐标系和变换

坐标系

模型坐标

模型坐标是以物体某一点为原点而建立的坐标系,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,所以可视为一个整体,与人类的思维习惯一致。

世界坐标

世界坐标系以屏幕中心为原点(0,0,0)。你面对屏幕,你的右边是x正轴,上面是y正轴,屏幕指向你的为z正轴。长度单位这样来定: 窗口范围按此单位恰好是(-1,-1)到(1,1)。

相机坐标

相机坐标以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。

投影坐标

OpenGL——光照的基本知识

从生理学的角度上讲,眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。人类对于光线强弱的变化的反应,比对于颜色变化的反应来得灵敏。因此对于人类而言,光线很大程度上表现了物体的立体感。

以下内容从《openGL入门教程》整理而来~~~~

请看下图,

OpenGL——光照的基本知识

图中绘制了两个大小相同的白色球体。其中右边的一个是没有使用任何光照效果的,它看起来就像是一个二维的圆盘,没有立体的感觉。左边的一个是使用了简单的光照效果的,我们通过光照的层次,很容易的认为它是一个三维的物体。

OpenGL对于光照效果提供了直接的支持,只需要调用某些函数,便可以实现简单的光照效果。但是在这之前,我们有必要了解一些基础知识。

一、建立光照模型

OpenGL(六)使用 VAO 打包指令 优化代码结构

通常说来当创建好vbo的数据结构,还需要设置glVertexAttribPointer等一系列属性,在OpenGL中提供了 VAO (Vertex Array Object)它相当于同时记录了数据在哪里和数据是怎样分布。从实际应用的角度,它最重要的贡献就是简化了代码。

原理

通过接口函数生成一个VertexArray,然后在其中创建和设置VBO的相关参数,在最终绘制时,直接使用。

GLuint myVao;
glGenVertexArrays(1,&myVao);
glBindVertexArray(myVao);
//... some vbo operation
glBindVertexArray(0);

实现

通过C++的匿名函数,可以将vbo操作开放出去

#include <functional>

GLuint CreateVAOWithVBOSettings(std::function<void()> settings)
{
    GLuint vaoTemp;
同步内容
--电子创新网--
粤ICP备12070055号