前言

Shader,又名着色器,是控制 GPU 绘制的指令集。从某种意义来说,着色器是一个把输入转换到输出的程序,为图形渲染管线的某个特定部分而运行。图形渲染管线是渲染的核心组件。通过给定虚拟相机、3D 模型以及光源等场景要素来生成图像。整个渲染流程又可以大致分为:应用阶段、几何阶段、光栅化阶段。其中,应用阶段是在 CPU 上进行,主要负责场景渲染数据的准备,比如顶点数据,相机数据等;几何阶段是在 GPU 进行,主要负责和渲染图元打交道,处理需要绘制的几何相关工作,决定图元怎样绘制,在哪里绘制;光栅化阶段也是在 GPU 上处理,主要是将几何图元进行逐像素处理,最终渲染到屏幕上。下面,引用网络上的一个渲染流程的图片让大家基本了解一下整个过程。

在 Cocos Creator 3D 中主要采用的是 YAML 格式搭配 GLSL 语法以及基本着色器(顶点、片段着色器)来书写 Shader。编辑器中可以通过在 资源管理器 面板,右键选择 新建/Effect 来创建 Shader 资源。但是在实际的项目开发中,通常很多美术效果的表现都没法由程序来独立完成,那这时就会涉及到,如何让 Shader 变成更加简便,可操控的资源呢?那就引入了材质的概念。一个材质依赖一个 Shader 资源,可以通过属性开放的方式提供可调配界面来达到不改一行 Shader 代码就能实现不同的效果。同样通过类似创建 Shader 资源的方式来创建 Material 资源。并选择这个 Material 的 Effect 为前面创建的 Shader。

结构介绍

经过上面的操作后创建的默认 Shader 是一个不带光照,只开放贴图和颜色属性的 shader。这样的 Shader 一般可以应用于 UI 以及粒子上。

接着,把默认创建的 Shader 做一个拆分,剔除掉内容后,基本结构大致是这个样子。

CCEffect %{techniques:- name: xxxpasses:- vert: program-name:function-namefrag: program-name:function-name[properties]- name: xxx[passes]
}%CCProgram vs-name %{}%CCProgram fs-name %{}%

其中,带 [] 代表的是可以有多个数据。 CCEffect 是一个渲染流程的清单,里面包含了这个 Shader 所包含的所有 pass,顶点、片段选取,属性声明和初始设置以及测试模版配置等等。而 CCProgram 是一个 Shader(顶点/片段着色器) 片段,一个 Shader 文件里又可以包含多个顶点/片段着色器来共 pass 使用。

语法格式

1. CCEffect 格式介绍

在之前的结构介绍里可以看到 CCEffect 是由多个 technique 组成,technique 代表一个实现技术,每一个材质只能选用对应 Shader 的其中一个 technique,每个 technique 可以有多个 pass,pass 就是代表渲染一次模型,多个 pass 之间可以共同作用。例如一个卡渲的 Shader,第一个 pass 进行描边绘制,第二个 pass 进行色彩绘制。

引擎提供了一个 连字符 + 空格 的形式来区分数组,多 pass 书写如下:

passes:
- vert: 片段名:入口函数名 // (入口函数的名字必须非 main)frag: 片段名:入口函数名# ...
- vert: 片段名:入口函数名frag: 片段名:入口函数名

每个 pass 都会优先定义引用顶点/片段着色器以及它们相对应的入口函数,然后再定义属性以及测试缓冲等。

passes:
- vert: test-vs:vertfrag: test-fs:fragproperties:# ...blendState:# ...# ...CCProgram test-vs %{ vec4 vert(){ return (vec4 类型值) }}%
CCProgram test-fs %{ vec4 frag(){ return (vec4 类型值) }}%

当然,也有可能会遇到需要数据间的引用与继承来避免书写重复的内容,引用的方式引擎提供了一个 & 配合 * 使用的方式,例如:

object1: &o1 // 开放复用数据 object1key1: value1
object2:key2: value2key3: *o1 // 复用开放数据 object1// 最后形成样式
{"object1": {"key1": "value1"},"object2": {"key2": "value2","key3": {"key1": "value1"}}
}

继承的方式引擎提供了一个 & 配合 << 和 * 使用的方式,例如:

object1: &o1key1: value1key2: value2
object2:<<: *o1key3: value3// 最后形成样式
{"object1": {"key1": "value1","key2": "value2"},"object2": {"key1": "value1","key2": "value2","key3": "value3"}
}

pass 的更多参数参考这里。

2. CCEffect 属性 properties

属性 properties 是与编辑器交互的核心部分,它的通用格式是:prop-name: { value: init-value, [target], [editor] }。其中,[] 代表可选部分。

prop-name 代表属性的名字。

value 属性初始值。

值类型 默认值 说明
ivec2/3/4,vec2/3/4, color, array [0],[0, 0],[0, 0, 0],[0, 0, 0, 0] 根据声明选择数组长度。例如:ivec3
int, float 0 任意数字。例如:value: 0.5
sampler2D default black, grey, white, normal, default。例如:value: grey
samplerCube default-cube black-cube, white-cube,default-cube。例如:value: white-cube

可选属性 target ,指向作用的 Uniform 属性。例如:声明 replaceR:{ value: { 0.5 }, target: mainColor.r } uniform vec4 mainColor; 那么,该属性则会修改 mainColor 的 r 通道。

可选编辑器呈现效果属性 editor,是一个可以在编辑器上定制数据的属性。可以通过在 properties 下写入 metadata: { visible: false } 的方式定义基础通用编辑器呈现方式,然后差异组件自身再定义不一样的数据。在下面我会介绍基础配置的说明,更多配置请查看这里。

配置名 说明
displayName any string 默认的是属性的名字,如果这里填入新的值,则在编辑器的属性名上显示该值。例如:editor: { displayName: Albedo }
parent 指定宏启用后才显示该属性。关于宏的介绍,会在接下来 4. CCProgram 继续介绍。例如:editor: { parent: USE_NORMAL_MAP }
type vector, color 当前属性的类型,通常 vec2/3/4,array,number,贴图类型不需要填写,像颜色这样数值是 vec4 显示是色值编辑的,就需要定义类型。例如:editor: { type: color }
visible true, false 是否在编辑器上可视。例如: editor: { visible: false }
tooltip any string 鼠标移到属性名上提示的内容。例如:editor: { tooltip: 显示看这里 }
range [min, max, [step]] 数值可填写范围,step 是数值在编辑器里调整的步长。例如:editor: { range: [0, 1, 0.1] }

3. CCProgram

主要包含的是 Shader 片段,如果是在 CCEffect 的 pass 里声明需要使用的顶点/片段着色器,入口函数必须返回相对应的数据,比如顶点着色器返回需要绘制的屏幕坐标,片段着色器返回绘制的像素颜色。结构大致如下:

CCProgram unlit-vs %{precision highp float;vec4 vert () {vec4 position = vec4(1, 1, 1, 1);return position;}
}%CCProgram unlit-fs %{precision highp float;vec4 frag () {vec4 color = vec4(1, 1, 1, 1);return color;}
}%

整个内容的书写会在下一篇里做一个详细说明,这里就不过多描述。

结合上述属性定义,做一个小的展示如下:

properties:mainColor: { value: [1, 1, 1, 1], editor: { type: color, displayName: bgColor } }showRange: { value: 0.5, editor: { range:[0, 1, 0.1] } }mainTexture: { value: grey, editor: { tooltip: 主贴图, parent: USE_TEXTURE } }reOrderColor: { value: [1, 1, 1, 1], editor: { type: color, visible: false } }uniform Constants {vec4 mainColor;vec4 reOrderColor;float showRange;
};
uniform sampler2D mainTexture;

小目标

接下来应用上面的属性内容以及基础框架,尝试开始定义一下自定义 Shader 的基础属性。先定义一个可调节颜色属性,代码如下。

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
CCEffect %{techniques:- name: testpasses:- vert: test-vs:vertfrag: test-fs:fragproperties:mainColor: { value: [1, 1, 1, 1], editor: { type: color } }
}%CCProgram test-vs %{precision mediump float; // 精度定义,不能去highp vec4 vert () {highp vec4 position = vec4(0, 0, 0, 1);return position;}
}%CCProgram test-fs %{precision mediump float;vec4 frag () {vec4 o = mainColor;return o;}
}%

这个时候会发现在编辑器的控制台输出如下报错。这个报错的主要原因在于声明了 mainColor 属性,但是却没有实际的 uniform 来与它对应,接下来在 test-fs 里加入这个声明 uniform vec4 mainColor;

这时发现,报错的方式换了,因为除了 sampler 类型,其余的 uniform 声明都必须放在声明块里(这个在下一篇文章里会做一个说明)。因此,还是在 test-fs 里加入 uniform Constants { vec4 mainColor; };

然后,在编辑器中查看,报错没有了,此时,点击 show 材质资源,出现定义的属性 mainColor。各位同学也可以尝试一下用上面提到的方式修改显示的名字,来观察定义的属性的名字是否是你定制的,如果是,那么恭喜你,完成了自定义材质属性的第一步!

接下来,开始应用这个材质。在 层级管理器 上右键 创建/3D 对象/Quad,选中 Quad 节点,在 属性检查器 里的 materials 下方替换成当前创建的材质,观察模型会发现什么内容都没有出现,这个时候就要回到我们在开篇提及到那部分内容了,图形渲染管线接受一组 3D 坐标,然后把它们转变为你屏幕上的有色 2D 像素输出,图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。从上面我们书写的内容就可以看出问题出现在顶点着色器中,顶点着色器顾名思义就是要负责处理顶点数据的,在这里始终输出的都是一个点的信息,这样最终在屏幕上肯定是什么也没有。因此,在这里必须要将模型 Quad 的顶点数据传输上来最终绘制上去。那么,要如何上传顶点数据呢?那就要先告诉大家这个顶点数据怎么来的。顶点数据可以是整个游戏世界里的绘制模型的世界坐标点,也可以是隐藏在其他地方的模型坐标点。最后都会通过一系列的坐标转换(模型坐标 -> (模型矩阵 )-> 世界坐标 -> (视图矩阵)-> 观察坐标 -> (投影矩阵)-> 裁剪坐标 -> (视口变换) -> 屏幕坐标),返回出换算好的屏幕点给下一个阶段使用。在顶点着色器中可以通过一个 in 关键字来接收相对应输入的顶点数据 a_position。

CCProgram test-vs %{precision mediump float; // 精度定义,不能去#include <cc-global>#include <cc-local>in vec3 a_position;highp vec4 vert () {highp vec4 position = vec4(a_position, 1);// 投影矩阵 <- 视图矩阵  <- 世界矩阵 <- 本地坐标return  cc_matProj * (cc_matView * cc_matWorld) * position;;}
}%

上面,可以看出 include 出了几个头文件,多了几个 cc_matProj 等都没有被声明量,这几个变量从名字上看,就知道是空间变换的矩阵。cc-local 里包含了本地空间转实际空间的矩阵(cc_matWorld)等,cc-global 里包含了世界空间到屏幕空间的一系列矩阵(cc_matView,cc_matProj)和其他全局数据。最终计算的是本地空间坐标转屏幕坐标的变换。有兴趣的可以看下官方说明,至于 include 的用法,会在下一篇详细说明。

在这里还需要给大家补充的一点是,可能会有一部分人会有疑问,关于如何定义着色器的输入数据,我就拿 Quad 打比方,在 Quad 的模型导入的时候,就定义了自身会传入的数据,可以通过对 Quad 资源右击,在 Library 中显示查看相对应的 json 文件里的 attributes 来知悉,如果定义了 a_position 则会传入 顶点数据,如果定义了 a_normal 则会传入法线数据,以此类推。

最后,经过上述步骤在编辑器下就能看到一个白色的正方形。通过双击材质修改颜色属性,就可以控制屏幕上的正方形方块变色。

结语

看到这里的同学应该大概能知道引擎的 Shader 开发流程是怎样的了,本人也是才这条道路上磕磕绊绊的学习,第一次写教程如果有哪里写错的或者说的不够清晰的地方希望大家能够不吝赐教。接下来会写更多的教程让大家更深入的了解引擎的 Shader 使用,以更好的制作出更加精美的效果,共勉。

快速入门 Cocos Creator 3D Shader 上篇相关推荐

  1. 借Blake老师的投篮小游戏公开课入门Cocos Creator 3D开发!

    点击上方蓝字关注我 效果预览 获取代码 关注公众号,发送[3D篮球]获取代码. 游戏介绍 ● 点击屏幕,根据按住屏幕的时间,进行蓄力,时间越短,发出去的力越小,时间越长,发出去的力越大,超过了最大力, ...

  2. 从投篮小游戏入门 Cocos Creator 3D 开发

    一枚小工,多年 Cocos2d-x 和 Cocos Creator 游戏开发工程师.现阶段,主要在 Cocos Creator 环境下用 JS  和 TS 进行项目开发.19 年 7 月份开始,想和其 ...

  3. 麒麟子Cocos Creator 3D研究笔记零:从零开始入门并发布微信小游戏

    编辑器状态截图 不要在意名字,我临时借用的小游戏APPID 一.前言 Cocos Creator,我回来了. 2016年6月,大家都觉得Cocos Creator 2D不够成熟的时候,我就开始商用了. ...

  4. Cocos Creator 3D 麒麟子回来了!(入门心法)

    1 前言 Cocos Creator,我回来了. 2016年6月,大家都觉得Cocos Creator 2D不够成熟的时候,我就开始商用了.因为我感受到了市场对Cocos Creator商业游戏源码框 ...

  5. 用 shader effect 实现雨滴落水效果!Cocos Creator 3D !

    最近逛论坛时,看到一位大佬在分享各种 shader 特效.基于其中的水波 shader ,白玉无冰写了一个玩水效果!文章底部获取完整代码!还可以试试水哦! 先一起看看效果- 点击任意位置,会在该位置生 ...

  6. 麒麟子Cocos Creator 3D研究笔记十一:实用Shader之单张纹理实现武器动态发光

    零.别看广告,看疗效 虽然标题叫武器发光,其实它还能实现魔法护盾.动态光柱等效果.别说话,看图! 阿子最近沉迷于学英语和写代码,可HIGH了. 一看时间,竟然已经十天没发稿了. 但这不能怪阿子,要怪就 ...

  7. Cocos Creator 3D后期效果解决方案源码剖析--从入门到融汇贯通

    注:本文既有经验上的总结,又有实现方式上的讲解.既有流程上的描述,又有代码细节上的剖析. 全文字数5000+,看的时候最好带上笔和纸. 零.你的序 感谢大家的厚爱,KylinsPostEffects上 ...

  8. 麒麟子Cocos Creator 3D研究笔记九:初尝Shader并实现边缘光(RimLight)

    零.先看一些图 图1:边缘光因子检查 图2:黄色,一般用于霸体效果 图3:红色,一般用于特殊技能特效 图4:白色,一般用于受击效果 图5:绿色,一般用于人物,NPC选中时高亮 看着群里的小伙伴们都很热 ...

  9. 蚂蚁庄园运动会登山赛!3d项目入门实战!Cocos Creator 3D!

    好像没写过3d项目分享,那么就跟着蚂蚁庄园的小鸡一起跳跳跳吧! 效果预览 配置环境: cocos creator 3D 1.0.0 首先是寻找3d资源花费了大半天时间,开发3d游戏不易呀!最终还是向K ...

最新文章

  1. 计算高效,时序一致,超清还原!清华NYU 提出 RRN:视频超分新型递归网络
  2. JDBC连接数据库格式
  3. C#后台,执行前台js 脚本
  4. Response.Write具体介绍
  5. 大型网站架构设计系列总结
  6. 斯坦福 CS183f YC 创业课 2017 资料整理
  7. 如何做一个国产数据库系统(一)
  8. java导出sas_[转载]SAS Proc Export导出文件
  9. 电脑Win10系统如何进入安全模式
  10. 滤波器m矩阵 awr 不一样_云南tte滤波器_灿勤科技
  11. Centos中重置MySQL密码
  12. 安卓kali安装mysql_安卓手机安装kali教程(root篇)
  13. JAVA 类和对象的实例
  14. 【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割
  15. java web,添加删除文本框
  16. Springboot集成Screw生成数据库表结构文档
  17. gets和puts基本用法。
  18. MACBOOK 连接不上wifi的解决办法
  19. 做了一个淘宝内部优惠券分享平台支持微信公众号以及网站
  20. Android添加UserAgent

热门文章

  1. mysql 中文全文搜索总结
  2. JVM笔记(四)对象是否存活判断算法
  3. SDUT 2021 Winter Individual Contest - G
  4. 外网/内网端口映射-实现外网远程访问PC/服务器
  5. 关于中科网讯信息服务平台的有关介绍
  6. 快速排序(代码+详细分析)
  7. 数据库事务的 ACID 特性
  8. bugku:love
  9. 国外问卷调查该怎么做?
  10. 【ffmpeg】-fflags nobuffer 会导致 av_find_stream_info失败