ssRender引擎中Shader学习理解小结

ssRender中的Shader

       ssRenderEdit工具中的Shader与OpenGL的Shader并无本质上的区别,是在OpenGLShader的基础上,对一些变量和方法进行了额外的封装。本篇文章对于想要学习OpenGL Shader 和ssRender工具Shader的同学都会有一定的帮助!

       下面,我将会通过一些简单的小案例来分享一下个人对Shader初学的学习理解:

(一)认识Shader(理论)

如图:

       打开SSrenderEdit工具,在资源(Resource)窗口下的材质(Material)子窗口中(New) Shader新建Shader着色器

映入眼帘的就是定点着色器(Vertex Shader)与(Fragment Shader),什么作用呢?

Vertex顶点着色器,是渲染的第一步,对每个顶点执行变换操作,计算顶点在不同模型空间的不同转换方式,还可以将后序的渲染数据传递给下一个着色器(就是Fragment片元着色器),决定着一个图元在屏幕中最终的显示位置。

Fragment片元着色器,接收顶点着色器传递过来的渲染数据,计算片元最终的颜色值和深度值。像我们常用的纹理采样、颜色汇总等就是Fragment片元着色器来计算的。它决定了一块片元的显示效果。

显而易见,Fragment着色器的执行次数远大于Vertex着色器,所以我们可以通过一定的算法优化,减少Fragment的调用次数以优化工程的渲染效率

在正式介绍Shader的使用方法前,先提前说明一下Shader的关键字和需要注意的情况

①uniform:统一值,由于GPU的线程并行,且各个线程之间无数据交互与通信,所以所有线程的某些输入值要统一,且只读。一般在定义完精度之后就进行声明。它可以在vertex和fragment共享使用。

②varying:变化值,就像 GLSL 有个默认输出值 vec4 gl_FragColor 一样,它也有一个默认输入值( vec4 gl_FragCoord )。gl_FragCoord存储了活动线程正在处理的像素屏幕碎片的坐标。有了它我们就知道了屏幕上的哪一个线程正在运转。为什么我们不声明 gl_FragCoord 为 uniform (统一值)呢?因为每个像素的坐标都不同,所以把它叫做 varying(变化值)。

③attribute:只能在vertex 中使用的变量(不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。

④void mainmain 函数,无需多言,应该都知道是什么含义以及作用吧

precision mediump float:精密度为中间浮点。这个比较重要,它影响了渲染效率,更低的精度会有更快的渲染速度,但是会以牺牲渲染质量为代价。你可以选择每一个浮点值的精度。(precision mediump float;)就是设定了所有的浮点值都是中等精度。但我们也可以选择把这个值设为“低”(precision lowp float;)或者“高”(precision highp float;)。

⑥vec2vec3vec4:有n个分量的floatvectors(n 纬向量,数字值代表纬度),最高纬度就是4纬,是Shader中常用的变量,它们的初始化方法将会在文章后半部分的Shader应用实例中详细介绍。

⑦ivec*bvec*:(*代表维度值,只能是2/3/4)代表int型的vector与bool型的vector,类比vec即可理解。

⑧mat*:(*代表维度值,只能是2/3/4)n乘n大小的浮点型矩阵。

注意①:GLSL 语言规范并不保证变量会被自动转换类别。就是数字1代表着int型的数字,并不支持自动转换为float型的1.0,千万要注意使用上的规范,要养成在float型数据中加一个 . 的好习惯!

接下来就是介绍ssRenderEdit中的Shader使用详解啦:

1.Vertex Shader内容详解

attribute vec3 ssVertexPosition

定义了一个三维float型的向量,代表了顶点的位置。

attribute vec2 ssVertexUV

定义了一个二维float型向量,代表顶点的纹理坐标(UV坐标),等价于Shader中的(gl_FragCoord.xy / u_resolution,对坐标进行了规范化

uniform mat4 ssMVP

定义了一个4x4的矩阵的统一值,表示模型-视图-投影矩阵。

这个矩阵通常用于将顶点从模型空间转换到裁剪空间。

varying vec2 ssUV:

定义了一个变化值,上方介绍过,attribute定义的值只能在VertexShader中使用,而varying可用于Vertex Shader和Fragment Shader之间的传值。在这里,它用于向Fragment中传递纹理坐标。

gl_Position = ssMVP * vec4(ssVertexPosition, 1.0)

计算变换后的顶点位置,将模型-视图-投影矩阵(ssMVP)乘以顶点位置向量ssVertexPosition。gl_Position,表示顶点的裁剪空间坐标。

ssRenderEdit工具里Vertx中自带的代码基本无需改动,理解其大意即可,接下来介绍Fragment Shader中封装好的代码

2.Fragment Shader内容详解

precision mediump float:上面有过详细介绍,不再赘述

varying vec2 ssUV:接收从Vertex Shader中传递的同名(变化值)纹理坐标(UV坐标)。

uniform vec4 ssColor:统一值四纬变量,代表颜色。包含红(R)、绿(G)、蓝(B)和透明度(A)四个分量。

uniform float ssOpacity:统一值Float型变量,代表透明度。

uniform float ssTime:统一值Float型变量,代表运行时间,与Shader中的u_time用法一致。

gl_FragColor = vec4(color.rgb, ssOpacity * color.a): color.rgb 代表上方ssColor的红绿蓝变量,ssOpacity * color.a 代表透明度成绩。gl_FragColor 决定了最终显示效果。

ssRenderEdit工具中封装好的Vertex Shader和Fragment Shader就介绍到这了,下面将会通过几个实例来加深对Shader的理解:

(二)使用Shader(实践)

本篇文章举一些2D的实例:

第一步:

首先在SSRenderEdit工具中创建一个Item节点用来展示我们的最终效果:

第二步:在材质(Material)窗口下创建新材质,选择编写好的Shader,填写材质名称

第三步:

将新建的材质拖拽到Item节点下的Material的Source属性上,就能在页面中显示我们编写的Shader效果了!

1.最最最基础的Shader

此案例可以称为Shader里的"Hello World",看完上面的理论部分,并且Shader有着类似C语言的特征,这个实例应该很通俗易懂!

这里讲一下vec*(*代表纬度值,只能是2,3,4)的初始化方法,ivec*和bvec*的初始化方法与之类似:

(1)为各个分量提供标量值以供初始化:

例如vec2 avec2 = vec2(1.0 , 0.0);  

vec4 avec4  = vec4(1.0 , 0.8 , 0.6 , 0.4);

(2)提供一个标量值,应用于各个分量的初始化:

例如vec2 bvec2 = vec2(1.0);  等价于  vec2 bvec2 = vec2(1.0 , 1.0);  vec3、vec4同理

(3)提供其他向量与标量值的组合进行初始化(要注意分量个数上的对应)

例如 ①vec3 avec3 = vec3(1.0 , 0.5, 0.0);

        vec2 bvec2 = vec2(avec3);            

        等价于vec2 bvec2 = vec2(avec3.x , avec3.y);

        等价于vec2 bvec2 = vec2(1.0 , 0.5);

        (更高维度的向量将会顺序的分配给低维度的向量)

       ②vec3 cvec3 = vec3(bvec2.yyx);

        等价于vec3(bvec2.y , bvec2.y , bvec2.x);

(有没有很神奇的赶脚?赋值方式跟传统的set函数很像,但是又有些许不一样)

效果展示:

上述的Shader让我们得到了一个红色的小方块

我们也可以在此基础上加一些小小的,有关于ssTime(与u_time类似,记录系统运行时间)的三角函数,接下来请看

2.加了三角函数的Shader

对Red和Green分量上加上了sin函数和cos函数,他们的参数是ssTime(同u_time,代表着程序运行的时间),Blue设置为固定值0.5,透明度设为1.0。

这样,我们就得到了一个随时间规律变化的粉绿色块(如下图)

怎么样,是不是感觉越来越好玩,越来越感兴趣了呢?接下来上点难度,跟紧了!

3.变化的红色圆环

uv纹理坐标取值范围[0,1],所以将它*2 -1可以将纹理坐标范围调整到[-1,1],正中心的坐标就是[0,0];

vec3 col  = vec3(1.00,0.00,0.00);应该是很熟悉的语法吧,就是将col染成红色;

就是将直角坐标转换为极坐标,length()函数计算极坐标的半径

atan()函数就是arctan(uv.y/uv.x)计算极坐标角度

col *= step(d,0.8);将半径从0到0.8范围的圆染色,得到了一个红色的圆:

col *= 1.0 - step(d,0.7);将半径小于0.7的圆除去染色,得到了一个宽度为0.1的圆环:

col *= step(sin(ssTime)*3.14,angle);这句话应该不会陌生了吧,极坐标的角度范围是[-π,π],sin()函数的取值为[-1,1],这样我们就能得到最终的效果,一个随时间变换的红色圆环啦:

4.转动十字

得到的效果如下:

解析:我虽然只是一个可能连入门都算不上的Shader菜鸟,这一段shader也是我从网上找的资料,但我还是想要发表一下我的一些观点:在我仔细看过这段shader代码,经过长时间的思考后:知道勾股定理吗?知道万有引力吗?其实跟这段Shader代码并没有什么关系!我其实也不知道这段代码是如何构思并实现的,正如我一开始说的:我只是一个可能连入门都算不上的Shader菜鸟。

小结:本篇文章是本人在使用ssRenderEdit工具中的Shader内容时的学习理解,并且编写了几个简短的Shader代码对一些小效果进行了实现,接下来本人会继续分享对Shader的理解,并且会继续深度探索ssRenderEdit工具其他实用功能!

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值