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. Mac OS使用brew安装memcached

    1.查看安装信息 brew info memcached 显示如下: memcached: stable 1.5.9 (bottled) High performance, distributed m ...

  2. Leetcode 532.数组中的K-diff数对

    数组中的K-diff数对 给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对.这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字 ...

  3. Leetcode 523.连续的子数组和

    连续的子数组和 给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数. 示例 1: ...

  4. sqlserver 表值函数

    一.单语句表值函数 ALTER function [dbo].[uf_get_jxc_da_sum](@dt char(8),@dt2 char(8)) RETURNS table as return ...

  5. php显示错误

    error_reporting(E_ALL); ini_set('display_errors', '1');    //将出错信息输出到一个文本文件 ini_set('error_log', dir ...

  6. Linux系统基础优化总结

    请称呼我搬运工,哈哈 优化综合 https://www.cnblogs.com/yinshoucheng-golden/p/6149556.html (1)不用root管理,以普通用户的名义通过sud ...

  7. AngularJs 特性 之 双向数据绑定

    <!DOCTYPE html> <html lang="en" ng-app> <head> <meta charset="UT ...

  8. HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  9. inner join和left join 、right join 的区别?

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...

  10. swarm 发布服务

    1.发布服务 2.发布服务 服务发现:Swarm模式内置DNS组件,自动为每个服务分配DNS记录,然后服务的DNS名称在集群内的服务直接分发请求.负载均衡:在Swarm集群中创建服务时,Ingress ...