love2d--glsl02变量和语句
Shader分为顶点着色器和片段着色器,GPU先处理顶点再处理片段,大概可以这么理解,
顶点着色器处理模型里的点,输出处理后的数据,这些数据经过GPU其它模块处理后传入
片段着色器,经片段着色器综合后渲染。片段处理器的名字也很恰当,表明了它处理的数
据是一些顶点集合的数据片段。(以上理解仅供参考,如有错误,欢迎指正)
在love2d里片段着色器被称作像素着色器pixelcode,下文也使用像素着色器。
以上过程如下图,来自此文。
另外在泡泡网上找到了这两幅图,仅供参考。
使用shader时需要先检测显卡是否支持,可以用love.graphics.isSupported("shader")来检测,love.graphics.isSupported可以检测某个特性是否被支持,更多功能检测请参照wiki。
下面介绍一下love2d shader里的变量和函数。
变量
基本类型
名称 |
注释 |
number |
glsl里的float |
bool |
true false |
int |
整型 |
复合类型
名称 |
注释 |
Image |
glsl里的sample2d |
Texel(tex纹理,uv二维向量) |
glsl里的texture2d |
mat2、mat3、mat4 矩阵 |
投影矩阵、变换矩阵等 |
vec2、vec3、vec4 向量 |
位置、颜色 |
变量修饰符
名称 |
注释 |
extern |
glsl里的uniform,用来和外部程序通信,在shader里只读 |
const |
常量,只读 |
varying |
顶点和像素着色器通信用,必须在两个着色器里都用varying修饰,且在像素着色器里只读 |
更多解释请参照wiki。
还可以使用宏#define,即文本替换
#define A 2,即遇到A就用2替换,关于宏以后遇到再细说。
可以像lua那样使用变量,在shader里变量都有类型,变量名前要加上类型名,即:
number a=2;
Image b;
矩阵(二维的)和向量(一维的)的初始化如下:
vec2 a = vec2(1.0,2.0);//直接赋值
vec2 b = vec2(3.0,4.0);
vec4 c = vec4(a,b)
mat4 m = mat4(1.0) // 用1.0初始化矩阵对角线
mat2 n = mat2(a,b); //用向量赋值,行主序
mat2 k = mat2(1.0,0.0,1.0,0.0); // 直接赋值
还可以使用结构体(类似lua里的table)
struct myobject //定义一个结构体
{
vec2 pos;
vec4 color;
};
myobject mo=myobject(vec2(0.1,0.2),vec4(0.1,0.2,0.3,0));
向量成员可以使用x,y,z,w来访问位置类型的,或者r,g,b,a访问颜色类型的,或者s,t,p,q访问纹理坐标类型的,或者使用数组下标[i]。
矩阵成员可以用数组下标,如m是一个矩阵,m[0]取第一列,m[2][3]取具体值。
注意shader里的数组下标是从0开始的。
结构体可以直接用”.”访问,如上文的mo.pos。
语句
shader里的控制语句和C语言类似,
if(exp)
...;
else
...;
for (initialization; bool expression; loop expression)
...;
while(exp)
...;
do
...;
while(exp);
跳转语句有continue,break,discard,其中discard只在像素shader中使用,它将在不写入帧缓存或者深度缓存的情况下,终止当前的shader。
函数
像素着色器至少包含名为effect的函数,该函数用来处理所绘制对象的颜色变换。
顶点着色器至少包含名为position的函数,该函数用来处理所绘制对象的顶点位置变换。
这两个函数可以理解为shader的入口函数即main。
像素着色器的定义如下:
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
参数详解
vec4 color 和love.graphics.setColor类似,不过它的取值范围是0--1.0,
或者是逐像素的Mesh color(以后再介绍)
Image texture 正在绘制的Image或canvas
vec2 texture_coords 像素相对于纹理的坐标,取值范围是0--1.0,y轴朝上,(1,1)是右上角
vec2 screen_coords 像素相对于屏幕的坐标,没有归一化,和love2d里的类似
返回值
vec4 返回一个rgba类型的颜色向量
注意
如果同时绘制多个canvas(如用love.graphics.setCanvas),可以使用effects替代effect,
单独处理每个canva,effects的原型如下:
void effects( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
{
// love_Canvases是一个可写的vec4 colors数组, 每个索引匹配一个canvas。
//如果你没有对所有激活的canvas赋值,将会出错。
love_Canvases[0] = color;
}
顶点着色器定义如下:
vec4 position( mat4 transform_projection, vec4 vertex_position )
参数
mat4 transform_projection 变换矩阵受love.graphics.translate以及投影矩阵影响
vec4 vertex_position 当前向量的原始坐标
返回值
vec4 返回一个vec4向量类型的转换后的坐标
注意
像素着色器在每次绘制像素到屏幕事都会调用,顶点着色器在每次顶点绘制到屏幕都会调用。
可以在一段着色器代码里使用两者,使用宏区分,即
#ifdef VERTEX
...顶点代码
#endif
#ifdef PIXEL
...像素代码
#endif
下面是一段简单的示例:(注意shader是类C的语言,if else和lua不同)
function love.load() if not love.graphics.isSupported("shader") then print("your gpu not support shader") return end local shadercode=[[ extern number time; //time变量用来和外部交换,外部程序可以给这个time传值 vec4 test(number x) { vec4 color; if( x>-1 && x<-0.5 ) color = vec4(0.8,0.8,0.8,1.0); else if(x>-0.5 && x<0 ) color = vec4(0.4,0.4,0.8,1.0); else if(x>0 && x<0.5) color = vec4(0.2,0.2,0.4,1.0); else color = vec4(0.1,0.1,0.1,1.0); return color; } vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) { //(r,g,b,a)颜色,取值0-1,这里对time变量进行操作保证结果在0-1范围内 return test(cos(time)); } ]] --1 创建shader myeffect = love.graphics.newShader(shadercode) end function love.draw() -- 2 关闭shader,矩形为默认效果 love.graphics.setShader() love.graphics.rectangle('fill', 10,10,790,285) -- 2 加载effect shader,矩形效果绚丽 love.graphics.setShader(myeffect) love.graphics.rectangle('fill', 10,305,790,285) end local t = 0 function love.update(dt) t = t + dt myeffect:send("time", t) --3 更新 end
附:
作者:半山
出处:http://www.cnblogs.com/xdao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。