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 } } # 改变贴图的大小
TriplanarBlendSharpness: { value: 1, editor: {type: float}}
tilingOffset: { value: [1.0, 1.0, 0.0, 0.0] }
}%
CCProgram unlit-fs %{
precision highp float;
#include <output>
#include <cc-fog-fs>
in vec2 v_uv;
uniform sampler2D mainTexture;
uniform Constant {
vec4 mainColor;
};
vec4 frag () {
vec4 col = mainColor * texture(mainTexture, v_uv);
CC_APPLY_FOG(col);
return CCFragOutput(col);
}
}%
CCProgram triPlanar-vs %{
precision highp float;
#include <input-standard>
#include <cc-global>
#include <cc-local>
#include <cc-local-batch>
#include <cc-fog-vs>
#include <cc-shadow-map-vs>
out vec4 v_position;
out vec4 wVertex;
out vec3 v_normal;
out vec2 v_uv;
uniform TexCoords{
vec4 tilingOffset;
};
vec4 vert(){
mat4 matWorld, matWorldIT;
CCGetWorldMatrixFull(matWorld, matWorldIT);
StandardVertInput In;
CCVertInput(In);
v_position = cc_matProj * (cc_matView * matWorld) * In.position;
v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);
wVertex = cc_matWorld * In.position;
v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;
CC_TRANSFER_FOG(matWorld * In.position);
return v_position;
}
}%
CCProgram triPlanar-fs %{
precision highp float;
#include <output>
#include <cc-fog-fs>
uniform sampler2D mainTexture;
uniform fsConstants{
vec4 mainColor;
float TextureScale;
float TriplanarBlendSharpness;
};
in vec2 v_uv;
in vec4 v_position;
in vec4 wVertex;
in vec3 v_normal;
vec4 frag () {
float bWeightX = pow(abs(v_normal.x),TriplanarBlendSharpness);
float bWeightY = pow(abs(v_normal.y),TriplanarBlendSharpness);
float bWeightZ = pow(abs(v_normal.z),TriplanarBlendSharpness);
vec3 bWeight= vec3(bWeightX,bWeightY,bWeightZ);
bWeight = bWeight / (bWeightX + bWeightY + bWeightZ);
vec4 xaxis_tex = texture(mainTexture, wVertex.zy / TextureScale);
vec4 yaxis_tex = texture(mainTexture, wVertex.xz / TextureScale);
vec4 zaxis_tex= texture(mainTexture, wVertex.xy / TextureScale);
vec4 tex = xaxis_tex * bWeight.x+ yaxis_tex * bWeight.y + zaxis_tex * bWeight.z;
CC_APPLY_FOG(tex);
return CCFragOutput(tex);
}
}%
对齐本地坐标
如果我们想既能在缩放物体的时候,物体的贴图不被拉伸,还想要在物体移动的时候,贴图不会流动
效果
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: tilling
passes:
- vert: tilling-vs:vert
frag: tilling-fs:frag
properties: &props
mainTexture: { editor: { type : sampler2D } }
textureSize: { value: [128,128,128,1], editor: { type: vec4}}
}%
CCProgram unlit-fs %{
precision highp float;
#include <output>
#include <cc-fog-fs>
in vec2 v_uv;
in vec3 v_position;
uniform sampler2D mainTexture;
uniform Constant {
vec4 mainColor;
};
vec4 frag () {
vec4 col = mainColor * texture(mainTexture, v_uv);
CC_APPLY_FOG(col, v_position);
return CCFragOutput(col);
}
}%
CCProgram tilling-vs %{
precision highp float;
#include <input-standard>
#include <cc-global>
#include <cc-local>
#include <cc-local-batch>
#include <cc-fog-vs>
#include <cc-shadow-map-vs>
out vec4 v_position;
out vec3 v_normal;
out vec2 v_uv;
out vec3 v_res;
out vec3 scaleXYZ;
out float scaleX;
out float scaleY;
out float scaleZ;
uniform constant{
vec4 textureSize;
};
vec3 getObjectScale( mat4 matWorld){
vec4 r = vec4(1,0,0,0);
vec4 g = vec4(0,1,0,0);
vec4 b = vec4(0,0,1,0);
vec4 rWorld = matWorld * r;
vec4 gWorld = matWorld * g;
vec4 bWorld = matWorld * b;
float rlen = length(rWorld.xyz);
float glen = length(gWorld.xyz);
float blen = length(bWorld.xyz);
scaleXYZ = vec3(rlen,glen,blen);
scaleX = rlen;
scaleY = glen;
scaleZ = blen;
return scaleXYZ;
}
vec4 vert(){
StandardVertInput In;
CCVertInput(In);
mat4 matWorld, matWorldIT;
CCGetWorldMatrixFull(matWorld, matWorldIT);
v_uv = a_texCoord;
v_position = cc_matProj * (cc_matView * matWorld) * In.position;
v_normal = In.normal;
getObjectScale(matWorld);
vec3 scaleVPos = scaleXYZ* In.position.xyz;
vec3 tempTextureSize = abs(textureSize.xyz)*-1.0;
v_res = scaleVPos/tempTextureSize;
CC_TRANSFER_FOG(v_position);
return v_position;
}
}%
CCProgram tilling-fs %{
precision highp float;
#include <output>
#include <cc-fog-fs>
uniform sampler2D mainTexture;
in vec4 v_position;
in vec3 v_normal;
in vec3 v_res;
in vec2 v_uv;
in vec3 scaleXYZ;
in float scaleX;
in float scaleY;
in float scaleZ;
float cheapContrast(float In, float Contrast){
float mixA = 0.0-Contrast;
float mixB = 1.0+Contrast;
float temp = mix(mixA, mixB, In);
return clamp(temp, 0.0, 1.0);
}
vec4 frag () {
vec4 gbTex = texture(mainTexture, v_res.bg);
vec4 rbTex = texture(mainTexture, v_res.rb);
vec4 rgTex = texture(mainTexture, v_res.rg);
float tempA = abs(v_normal.r * scaleX);
float tempB = abs(v_normal.b * scaleZ);
float tempC = abs(v_normal.g * scaleY);
float alphaA = cheapContrast(tempA,1.0);
float alphaB = cheapContrast(tempB,1.0);
float alphaC = cheapContrast(tempC,1.0);
vec3 xytex = mix(gbTex.rgb,rgTex.rgb,alphaB);
vec3 ztex = rbTex.rgb;
vec3 xyztex = mix(xytex.rgb,rbTex.rgb,alphaC);
vec4 tex1 = rgTex*alphaB;
vec4 tex2 = gbTex*alphaA;
vec4 tex3 = rbTex*alphaC;
vec4 tex = tex1+tex2+tex3;
CC_APPLY_FOG(tex);
return CCFragOutput(tex);
}
}%
参考链接
Unity Shader:三向贴图(Tri-planar mapping)—解决地形拉伸贴图变形以及贴图边缘的缝隙问题
Unity 贴图随着模型变换而缩放 UE4材质学习:LocalAlignedTexture UE4中实现物体缩放贴图大小保持不变的思路
|