我这里用的是Cocos Creator 3.7.2版本,不同版本可能存在差异
因为使用的第三方图床,导致文中图片丢失,看来以后还是得靠谱的图床了
顶点着色器
开始实现这个功能,对定点着色器应该有了基本的了解,这里不过多说明。
这里我们先看下Cocos Creator默认使用的着色器代码:builtin-sprite.effect
,可以直接在资源管理器中搜索
想要达到效果,其实修改就是扑克牌上边缘两个顶点的x轴坐标
但是想要修改,最起码得知道现在的值,做个小测试看一下。让顶点坐标的x值+=y值,观察x坐标的变化规律.
复制粘贴builtin-sprite.effect
文件(必须要复制粘贴,系统最开始的不能被修改),在复制出来的文件中搜索vec4 pos = vec4(a_position, 1)
并在该代码后面添加代码pos.x += pos.y;
,如下:
1 2
| vec4 pos = vec4(a_position, 1); pos.x += pos.y;
|
这里可以看到,蓝色框区域是牌原本显示的边框,底边的x轴没有变化,所以底边的+=pos.y这里的y值为0。
调整下牌的位置,让牌的左上角顶点和画布左上角顶点重合
从图上可以看出,当牌的左上角顶点和画布左上角顶点重合时,上边两个顶点的值往右偏了屏幕高度那么多的值。看下蓝框,很直观,一个正方形,偏移宽度=屏幕高度。
这说明顶点在画布上边缘位置时,顶点坐标y值是画布高。
这里测试x,y也是一样的(自己可以动手试下)其实片段着色器中我们拿到的a_position
就是一个屏幕左下角(0,0)
到 屏幕右上角(画布宽,画布高)
这样的vec2变量,有了定点的具体值,后面就好操作了。来看下顶点的屏幕坐标:
顶部偏移
我来定一个顶点point
,我要让所有的扑克都往这个点变形。设定point坐标vec2(屏幕宽/2,屏幕高*0.85).
对每个点来说,点的x轴偏移值 = (顶点x和pointx差值)* (顶点y和point.y的比例) 把前面的
pos.x += pos.y;`代码改为下面2行:
1 2
| vec2 point = vec2(1920. * .5,1080. * 0.85); pos.x += (point.x - pos.x) * (pos.y / point.y);
|
图片会往箭头所指的方向偏移。
修改起点y值
有个问题,就是这里的计算 都是用屏幕底边y值0计算的,我牌桌变如果不在屏幕底边咋办呢,我要指定一个起点的y值可以计算这个三角形。
比如我牌摆在离底边100px的位置,将参与计算的y坐标 减100就行了。
1
| pos.x += (point.x - pos.x) * ((pos.y - 100.) / point.y);
|
shader代码
放一下最终代码,让起点y值和终点坐标都用可变变量,从材质传值进来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. CCEffect %{ techniques: - passes: - vert: sprite-vs:vert frag: sprite-fs:frag depthStencilState: depthTest: false depthWrite: false blendState: targets: - blend: true blendSrc: src_alpha blendDst: one_minus_src_alpha blendDstAlpha: one_minus_src_alpha rasterizerState: cullMode: none properties: alphaThreshold: { value: 0.5 } u_point: { value: [1,1] } u_starty: {value: 0 } }%
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| CCProgram sprite-vs %{ precision highp float; #include <builtin/uniforms/cc-global> #include <builtin/internal/embedded-alpha> #if USE_LOCAL #include <builtin/uniforms/cc-local> #endif #if SAMPLE_FROM_RT #include <common/common-define> #endif in vec3 a_position; in vec2 a_texCoord; in vec4 a_color;
out vec4 color; out vec2 uv0; uniform Constant{ vec2 u_point; // 自己定义的顶点 float u_starty; // 扑克牌底边离屏幕下边的距离 }; vec4 vert () { vec4 pos = vec4(a_position, 1); pos.x += (u_point.x - pos.x) * ((pos.y - u_starty) / u_point.y); #if USE_LOCAL pos = cc_matWorld * pos; #endif
#if USE_PIXEL_ALIGNMENT pos = cc_matView * pos; pos.xyz = floor(pos.xyz); pos = cc_matProj * pos; #else pos = cc_matViewProj * pos; #endif
uv0 = a_texCoord; #if SAMPLE_FROM_RT CC_HANDLE_RT_SAMPLE_FLIP(uv0); #endif color = a_color;
return pos; } }%
CCProgram sprite-fs %{ precision highp float; #include <builtin/internal/embedded-alpha> #include <builtin/internal/alpha-test>
in vec4 color;
#if USE_TEXTURE in vec2 uv0; #pragma builtin(local) layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture; #endif
vec4 frag () { vec4 o = vec4(1, 1, 1, 1);
#if USE_TEXTURE o *= CCSampleWithAlphaSeparated(cc_spriteTexture, uv0); #if IS_GRAY float gray = 0.2126 * o.r + 0.7152 * o.g + 0.0722 * o.b; o.r = o.g = o.b = gray; #endif #endif
o *= color; ALPHA_TEST(o); return o; } }%
|
使用方法
在Cocos Creator 中找到精灵默认使用的材质ui-sprite-material.mtl
,将材质拷贝出来放在自己的资源文件夹下(必须拷贝出来,不然无法修改)。将上面代码保存为gradient.effect
,名字按照自己的想法来。最后修改下面4个地方即可
- 将精灵的”CustomMaterial”属性设置为你刚刚拷贝出来的材质
- 将材质的
Effect
属性设置为刚刚保存的gradient.effect
shader文件
- 这里
USE TEXTURE
一定要勾选上,不然没有纹理,只会显示一张空白图
- 调整这三个参数,获得自己想要的透视效果