最终效果如下,不知道过程有没有错误但是效果算是出来了
起因是看到ps有一个叫球面扭曲的功能,就有了个无端联想看看能不能再creator 2.x内做一些简单的3D视觉效果,试着能不能做成地球仪
首先要在creator上复刻ps的球面化,可以通过扭曲uv的方法实现
//球面化扭曲uv
vec2 centered_uv = v_uv0 * 2.0 - 1.0;
float z = sqrt(1.0 - clamp(dot(centered_uv, centered_uv),0.0,1.0));
vec2 spherified_uv = centered_uv / (z + 1.0);
vec2 uv = spherified_uv * 0.5 + 0.5;
vec4 testcol = texture(texture, uv);
gl_FragColor = testcol;
之后要把球体外的部分抹除掉,也就是说把那部分的A值置0这样我们就可以得到一个完整的球体
//抹除超出球体部分的A值
float hight = abs(v_uv0.y - 0.5); //高度
float width = sqrt(0.25 - hight * hight); //根据高度和半径算出宽度
float isInBall = smoothstep(abs(v_uv0.x - 0.5),abs(v_uv0.x - 0.5)+0.01,width); //判断是否处于球体部分
testcol.a *= isInBall;
这里smoothstep最早是用step函数的,效果如下
如果换成smoothstep能起到一定程度的抗锯齿效果
但是,这个球体和常见的地球仪还是有很大的区别,经线和经纬球相似,但是纬线要用另外的方法模拟
单用球面的横坐标,纵坐标继续使用v_uv0.y的话效果如下
把纵坐标按球面的坐标进行扭曲,效果如下
横坐标的处理就简单了,只要进行简单的缩放,加上一个cc_time.x就能实现简单的自转效果
//uv缩放修改
uv.y = asin((v_uv0.y-0.5)/0.5)/3.1415926 + 0.5; //通过v_uv0.y的反三角函数求得垂直方向上的偏移
uv.x *= 0.8; //按道理应该是0.5,不知道是不是图片素材的原因,填0.8才像现实中的地球仪
float speed = 0.2; //自转速度
uv.x += cc_time.x * speed; //转起来
vec4 testcol = texture(texture, uv);
这时可以把球面化uv的xy以红绿色表现出来,会发现这里的表现和球体的法线图十分相似,于是我有了一个大胆的想法
//输出uv值
vec4 testcol = vec4(spherified_uv.x*0.5+0.5,spherified_uv.y*0.5+0.5,0.0,1.0); //spherified_uv的取值范围是-1~1 这里要把他换算成0~1方便计算
尝试性的把法线方向,光线方向,视角方向写出来,就可以把高光和漫反射算出来了,就可以实现布林冯模型了
//输出uv值
vec3 normalDir = normalize(vec3(spherified_uv.x,spherified_uv.y,1.0)); //根据球面化扭曲推出的法线方向
float randomValue = sin(cc_time.x);
float randomValue1 = sin(cc_time.x*0.8);
vec3 lightDir = normalize(vec3(randomValue,-randomValue1,1.0)); //随机生成的平行光,方向大致是往屏幕里面射
vec3 viewDir = normalize(vec3(0.0,0.0,1.0)); //2D环境,视角方向自然是垂直屏幕的
vec3 halfDir = normalize(viewDir + lightDir); //半角方向,方便求高光效果
vec4 diffusCol = vec4(0.0,0.0,0.0,1.0);
float diffusValue = clamp(dot(normalDir,lightDir),0.0,1.0); //点乘n和l的方向,求出漫反射部分
float smoothness = 500.0; //通过这个可以控制光晕大小
float specularValue = pow(clamp(dot(normalDir,halfDir),0.0,1.0),smoothness); //点乘n和h的方向再来n次方,求出高光部分
col.rgb *= diffusValue;//求出漫反射采样效果,col就是上文求出的testcol
vec4 highLightCol = vec4(specularValue,specularValue,specularValue,1.0);//高光效果,默认白光。需要调整高光颜色可以乘一个rgb值
highLightCol.a *= isInBall; //防止高光溢出球体
vec4 ambient = vec4(0.0,0.0,0.0,1.0); //这里是环境光,默认纯黑,写出来意思意思
ambient.a *= isInBall; //防止环境光溢出球体
vec4 finCol = col + highLightCol + ambient; //高光漫反射环境光混合输出
gl_FragColor = finCol;
既然都已经做出伪3D效果了 不如再把法线贴图弄进去吧
//输出uv值
vec4 normalCol = texture(normalTexture, uv);//根据修改后的uv采样发现贴图
//vec3 normalDir = normalize(vec3(spherified_uv.x,spherified_uv.y,1.0));
vec3 normalDir = normalize((vec3(spherified_uv.x,spherified_uv.y,1.0)+(normalize(normalCol.rgb)*2.0-1.0) /2.0);//乘2减1是为了让法线大小从0~1变为-1~1(主要是xy方向)
好了这样就能显示了