Cocos creater 3.x 模型拉伸贴图平铺 Shader
Unity shader 和cocos shader API的对比
空间转换
顶点着色器要对模型空间下的顶点变换到世界空间,在变换到摄像机的空间,在进行一个裁剪变换,(也叫裁剪空间)然后在做一个投影变换,(将3维转换成2维),实际上这不是真正的投影变换,还是在为后面的投影变化做准备,
模型空间
模型空间,就是在3Dmax中,美术人员建模的时候,以一个3维坐标系的原点开始建模。就以下面鲨鱼模型做例子。鲨鱼的所有三角面片的顶点都是以模型空间的坐标原点而建立的
模型空间 也被称为对象空间 object space 和局部空间 local space
模型空间到世界空间
但是我们想要把这个模型渲染到屏幕上。这个模型要放在一个虚拟的3D场景,这个3D场景也有一个三维坐标系,我们要知道模型的每个点(顶点)在这个虚拟场景的位置。我们想要从模型空空间变换到世界空间。我们需要一个矩阵。
对于矩阵,一看到这个词不要害怕。在学了线性代数的本质 后,我们知道矩阵可以将一个点从一个3维空间,变换到另一个三维空间中。这个变换矩阵,在各个引擎都为我们提供了这些矩阵
Cocos
Name | Type | Info |
---|---|---|
cc_matWorld | mat4 | 模型空间转世界空间矩阵 |
cc_matWorldIT | mat4 | 模型空间转世界空间逆转置矩阵 |
要用这个矩阵要引入 cc-local.chunk
Unity
世界空间到摄像机空间
世界空间的英文是world space,摄像机空间叫Camera space,
摄像机空间也有多个别称 ,观察空间(Eye space),视图空间(View space),意思都是一样的
观察空间,摄像机就是那个观察者,
我们都知道通过专业的照相机,还是我们手机拍照,都可以把任何物体,显示到一张照片上。
我们的虚拟场景也有一个摄像机。摄像机有一个视锥体,在这个视锥体范围内,摄像机能看见的范围就绘制,看不见的就裁剪。
但是当我们把摄像机移动了,我们看到的画面中的物体位置也就发生了变化。在这一步转换的时候,我们把物体(模型)顶点坐标由世界空间下,转换到摄像机的坐标系下,计算的是一个相对的位置。这样才能摄像机动了,看到的物体的位置也就变了。
在世界空间=》摄像机空间,用的就是视图矩阵来变换的
Cocos creater 用到的视图矩阵
这个变量要导入 cc-global.chunk
#include <cc-global>
Name | Type | info |
---|---|---|
cc_matView | mat4 | 视图矩阵 |
cc_matViewInv | mat4 | 视图逆矩阵 |
摄像机空间(Camera Space)到投影空间(Projection space)
当物体被转换到摄像机空间下,然后就需要对 摄像机看不见的范围做裁剪,裁剪完之后,也叫裁剪变换。整个的过程就是把一个点从摄像机空间(Camera Space)转换到裁剪空间(clip space),我在Cocos 没有看到关于裁剪矩阵,有可能是在世界空间到摄像机空间,已经完成了裁剪。也有可能是在投影之前完成了裁剪变换
摄像机空间到屏幕空间(Screen space),就需要一次投影变换,用到的矩阵叫投影矩阵
Name | Type | info |
---|---|---|
cc_matProj | mat4 | 投影矩阵 |
cc_matProjInv | mat4 | 投影逆矩阵 |
所以我们看到Cocos shader中下面这句代码就是啥意思了。In.position是模型空间下的顶点坐标,我们给这个坐标左乘了一个模型空间转世界空间的矩阵,没有用cc_matWorld, 如果要对接引擎动态 Mesh 合批和几何体实例化(GPU Instancing)通过 CCGetWorldMatrix 工具函数获取世界矩阵
然后又左乘了一个视图矩阵,就是将模型上的顶点从世界空间变换到摄像机空间。最后左乘了一个投影矩阵cc_matProj,将顶点从摄像机空间变换到了屏幕空间。
shader 要实现的效果
对齐世界坐标
对齐世界坐标??
当我们缩放物体的时候,物体的缩放了,但是其贴图不会被拉伸变形
对齐世界坐标,就是当我们移动 旋转 物体的时候,发现这个物体表面的纹理会流动
效果
shader 代码
这个shader是我参考unity的三向贴图shader改写的,经过我通过对比unity shader和cocos shader
的一些api的差异,和glsl和hlsl的语法差异改写。
其实shader的语法不难,难的是背后蕴含得原理,很难理解。我会在后面贴出相关链接。
大致原理是用顶点的世界坐标,和世界法线去对纹理进行采样,然后混合
CCEffect %{
techniques:
- name: opaque
passes:
- vert: general-vs:vert # builtin header
frag: unlit-fs:frag
properties: &props
mainTexture: {
value: white }
mainColor: {
value: [1, 1, 1, 1], editor: {
type: color } }
- name: transparent
passes:
- vert: general-vs:vert # builtin header
frag: unlit-fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendSrcAlpha: src_alpha
blendDstAlpha: one_minus_src_alpha
properties: *props
- name: triPlanar
passes:
- vert: triPlanar-vs:vert # builtin header
frag: triPlanar-fs:frag
properties: &props
mainColor: {
value: [1, 1, 1, 1], editor: {
type: color } }
mainTexture: {
editor: {
type : sampler2D } } # 用到的贴图
TextureScale: {
value: 1 , editor: {
type: float } } # 改变贴图的大小
TriplanarBlendSharp