http://blog.csdn.net/racehorse/article/details/6638455

GLSL的Hello World

这一节中包含一个最基本的shader,它提供如下功能:顶点变换然后使用单一的颜色渲染图元。

顶点shader

前面已经说过,顶点shader负责完成顶点变换。这里将按照固定功能的方程完成顶点变换。

固定功能流水线中一个顶点通过模型视图矩阵以及投影矩阵进行变换,使用如下公式:

  1. vTrans = projection * modelview *incomingVertex

首先GLSL需要访问OpenGL状态,获得公式中的前两个矩阵。前面讲过,GLSL可以获取某些OpenGL状态信息的,这两个矩阵当然包括在内。可以通过预先定义的一致变量来获取它们:

  1. uniform mat4 gl_ModelViewMatrix;
  2. uniform mat4 gl_ProjectionMatrix;

接下来需要得到输入的顶点。通过预先定义的属性变量,所有的顶点将可以一个个传入顶点shader中。

  1. attribute vec4 gl_Vertex;

为了输出变换后的顶点,shader必须写入预先定义的vec4型变量gl_Position中,注意这个变量没有修饰符。

现在我们可以写一个仅仅进行顶点变换的顶点shader了。注意所有其他功能都将丧失,比如没有光照计算。顶点shader必须有一个main函数,如下面的代码所示:

  1. void main()
  2. {
  3. gl_Position =gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
  4. }

上面代码中变换每个顶点时,投影矩阵都将乘上模型视图矩阵,这显然非常浪费时间,因为这些矩阵不是随每个顶点变化的。注意这些矩阵是一致变量

GLSL提供一些派生的矩阵,也就是说gl_ModelViewProjectionMatrix是上面两个矩阵的乘积,所以顶点shader也可以写成下面这样:

  1. void main()
  2. {
  3. gl_Position =gl_ModelViewProjectionMatrix * gl_Vertex;
  4. }

上面的操作能够获得和固定功能流水线相同的结果吗?理论上是如此,但实际上对顶点变换操作的顺序可能会不同。顶点变换通常在显卡中是高度优化的任务,所以有一个利用了这种优化的特定函数用来处理这个任务。这个神奇的函数如下:

  1. vec4 ftransform(void);

使用这个函数的另一个原因是float数据类型的精度限制。由于数据精度的限制,当使用不同的顺序计算时,可能得到不同的结果,因此GLSL提供这个函数保证获得最佳性能的同时,还能得到与固定功能流水线相同的结果。

这个函数按照与固定功能相同的步骤对输入顶点进行变换,然后返回变换后的顶点。所以shader可以重新写成如下形式:

  1. void main()
  2. {
  3. gl_Position =ftransform();
  4. }

片断shader

片断shader也有预先定义的变量gl_FragColor,可以向其中写入片断的颜色值。下面的代码就是一个片断shader,将所有片断绘制成淡蓝色:

  1. void main()
  2. {
  3. gl_FragColor =vec4(0.4,0.4,0.8,1.0);
  4. }

可以在此获得本节例子的源码:

http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl5_2.0.zip


颜色shader

GLSL可以读取一些OpenGL状态,在本节我们将学习如何访问在OpenGL中设置的glColor变量。

GLSL有一个属性变量记录当前颜色,也提供易变变量从顶点shader向片断shader传递颜色值。

  1. attribute vec4 gl_Color;
  2. varying vec4 gl_FrontColor; // writable onthe vertex shader
  3. varying vec4 gl_BackColor; // writable onthe vertex shader
  4. varying vec4 gl_Color; // readable on thefragment shader

变量使用思想如下:

1、OpenGL程序通过glColor传送颜色信息。

2、顶点shader通过属性gl_Color接收颜色值。

3、顶点shader计算正面和反面的颜色,然后分别保存在gl_FrontColor和gl_BackColor中。

4、片断shader接收易变变量gl_Color中存储的插值产生的颜色,由当前图元的方向决定颜色是gl_FrontColor还是gl_BackColor插值产生的。

5、片断shader根据易变变量gl_Color设置gl_FragColor。


面说过顶点shader和片断shader中传递的易变变量要有相同的名字,但这里是个例外,顶点shader中的gl_FrontColor和
gl_BackColor会根据图元的方向,自动转变为片断shader中的gl_Color。还要注意属性变量gl_Color和易变变量
gl_Color没有冲突,因为前者只存在于顶点shader,后者只存在于片断shader。

下面是顶点shader的例子,只计算了正面颜色:

  1. void main()
  2. {
  3. gl_FrontColor =gl_Color;
  4. gl_Position =ftransform();
  5. }

片断shader更加简单:

  1. void main()
  2. {
  3. gl_FragColor = gl_Color;
  4. }

基于GLEW的源代码:

http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/colorglut_2.0.zip

扁平shader(Flatten Shader)

着色器编程让我们可以探索一些新效果,本节的例子展示了用奇怪的方法操作顶点得到的效果。

首先我们要得到一个扁平的3D模型,只需要在应用模型视图变换时将模型顶点的z坐标设为0就行了。下面是顶点shader的代码:

  1. void main(void)
  2. {
  3. vec4 v = vec4(gl_Vertex);
  4. v.z = 0.0;
  5. gl_Position =gl_ModelViewProjectionMatrix * v;
  6. }

我们先将gl_Vertex变量复制到一个局部变量v中。gl_Vertex是一个GLSL提供的属性变量,所以在顶点shader中它是只读的。

片断shader与“GLSL中的Hello World”一节相同,就只用设置一种颜色。

一个扁平的茶壶效果如下:

更进一步,我们需要在z坐标上使用一个正弦函数。将z坐标作为x坐标的函数,这样茶杯将呈现波浪的效果:

  1. void main(void)
  2. {
  3. vec4 v =vec4(gl_Vertex);
  4. v.z = sin(5.0*v.x)*0.25;
  5. gl_Position =gl_ModelViewProjectionMatrix * v;
  6. }


后我们需要加入一些顶点动画效果。为了达到这个目的我们需要增加一个变量记录变化的时间,或者帧数。一个顶点shader是无法记录不同顶点值的,更不用

说记录不同的帧了。所以我们需要在OpenGL程序中定义这个变量,然后作为一致变量传递给shader。假设在OpenGL程序中有一个名为time的
帧计数器,在shader中有个同名的一致变量。

顶点shader的代码如下:

  1. uniform float time;
  2. void main(void)
  3. {
  4. vec4 v =vec4(gl_Vertex);
  5. v.z = sin(5.0*v.x +time*0.01)*0.25;
  6. gl_Position =gl_ModelViewProjectionMatrix * v;
  7. }

在有关一致变量的小节讲过,在OpenGL程序中需要两个步骤:

·setup: 获取一致变量的存储位置

·render: 更新一致变量

设置(setup)步骤只有一条语句:

  1. loc =glGetUniformLocation(p,"time");

这里p是程序的句柄,time与顶点shader中定义的一致变量名称相同。变量loc是Glint类型的,必须定义在下面的渲染(render)函数也可以访问到的地方。渲染函数如下所示:

  1. void renderScene(void)
  2. {
  3. glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
  4. glLoadIdentity();
  5. gluLookAt(0.0,0.0,5.0,
  6. 0.0,0.0,0.0,
  7. 0.0f,1.0f,0.0f);
  8. glUniform1f(loc, time);
  9. glutSolidTeapot(1);
  10. time+=0.01;
  11. glutSwapBuffers();
  12. }

函数中的变量time在程序一开始初始化,然后每帧都会进行自增运算。

本节的GLEW源代码:

http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/flatten_2.0.zip

【GLSL教程】(四)shder的简单示例 【转】的更多相关文章

  1. java基础之JDBC四:事务简单示例

    /** * 事务 */ public class Test { public static void main(String[] args) { Connection conn = null; Pre ...

  2. ActiveMQ学习教程/2.简单示例

    ActiveMQ学习教程(二)——简单示例 一.应用IDEA构建Maven项目 File->New->Module...->Maven->勾选->选择->Next ...

  3. pureMVC简单示例及其原理讲解四(Controller层)

    本节将讲述pureMVC示例中的Controller层. Controller层有以下文件组成: AddUserCommand.as DeleteUserCommand.as ModelPrepCom ...

  4. Fastify 系列教程四 (求对象、响应对象和插件)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...

  5. 关于Ajax实现的简单示例

    一.代码示例 关于Ajax的基本概念(包括XMLHttpRequest对象及其相关方法属性)移步这里(w3school中文版)学习了解. <!doctype html> <html ...

  6. 【Redis】三、Redis安装及简单示例

    (四)Redis安装及使用   Redis的安装比较简单,仍然和大多数的Apache开源软件一样,只需要下载,解压,配置环境变量即可.具体安装过程参考:菜鸟教程Redis安装.   安装完成后,通过r ...

  7. 【Canvas】(1)---概述+简单示例

    Canvas---概述+简单示例 如果通俗的去理解Canvas,我们可以去理解成它类似于我们电脑自带的画图工具一样,canvas首先是选择一块画布,然后在这个画布上描绘我们想画的东西,画好后展示给用户 ...

  8. DotNetty关键概念及简单示例(基于NET5)

    DotNetty关键概念及简单示例(基于NET5) 目录 DotNetty关键概念及简单示例(基于NET5) 1.DotNetty 设计的关键 1.1 核心组件 1.1.1 Channel 1.1.2 ...

  9. WPF入门教程系列二十三——DataGrid示例(三)

    DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...

随机推荐

  1. C# 序列化和反序列化 详解

    什么是序列化以及如何实现序列化? 如何将对象数据写入 XML 文件? 如何从 XML 文件读取对象数据? 什么是序列化以及如何实现序列化? 序列化是通过将对象转换为字节流,从而存储对象或将对象传输到内 ...

  2. Mac: mac git 的安装 及实现自动补全

    1.检查是否装了brew $ brew list 如果没有,拷贝以下命令到终端 回车.可以安装好brewruby -e "$(curl -fsSL https://raw.githubuse ...

  3. 在windows64位上安装Python3.0

    1.下载安装包 下载地址:https://www.python.org/downloads/ 如果要下载帮助文件:Download Windows help file 如果要下载基于网页的安装程序: ...

  4. sqlserver导入dbf文件

    select top 10000 * from OPENROWSET('MICROSOFT.JET.OLEDB.4.0','dBase IV;HDR=NO;IMEX=2;DATABASE=E:/日常/ ...

  5. csapp 深入理解计算机系统 csapp.h csapp.c文件配置

    转载自   http://condor.depaul.edu/glancast/374class/docs/csapp_compile_guide.html Compiling with the CS ...

  6. grep_awk_sed文本处理

    小技巧 1.删除0字节文件find -type f -size 0 -exec rm -rf {} \; 2.查看进程按内存从大到小排列ps -e -o “%C : %p : %z : %a”|sor ...

  7. codevs 1081 线段树练习 2 区间更新 单点查询 无lazy

    题目描述 Description 给你N个数,有两种操作 1:给区间[a,b]的所有数都增加X 2:询问第i个数是什么? 输入描述 Input Description 第一行一个正整数n,接下来n行n ...

  8. 【一个比较bug free的二分写法】

    lower_bound: [l, r)区间内大于等于val的第一个位置 int lower_bound(int l, int r, int val){ while(l < r){ ); if(a ...

  9. linux命令 显示文件内容

    通过命令+文件名查看内容.如下命令可以查看.1, cat :由第一行开始显示文件内容:2,tac:从最后一行开始显示,可以看出tac与cat字母顺序相反:3,nl:显示的时候输出行号:4,more:一 ...

  10. [Codeforces Round #351 Div. 2] 673A Bear and Game

    A. Bear and Game time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...