一墩难求?莫慌!Cocos Creator 带你30分钟拥有一只专属冰墩墩

共 2141字,需浏览 5分钟

 ·

2022-02-19 10:20

素材来自网络

看到了没,看到了没,看到了没?

上面这只被套在塑料壳里,也挡不住它继续蹦哒的“熊猫”,就是这次的冬奥会的吉祥物:冰墩墩

小萌新一出道,就迅速火爆全网。

这几天总是听到有人在唱:“我只想要一只冰墩墩……”,看来,还真是一墩难求啊。

既然买不到(起),那做一个不行吗?要做就要做一个下面这样的:

今天麒麟子就手把手,教大家用 Cocos Creator 制作一只属于自己的冰墩墩。

本次的 DEMO 麒麟子共做了10个小时左右,迫不及待想要上(白)手(嫖)的朋友,可以滚动到文末点击【阅读原文】下载(免费的哟)。

一、去搞个 3D 模型

首先去网上找一个冰墩墩 3D 模型,如果有格式方面的问题,可以放入 Blender 等软件中调整,大概找到的模型和下图中的差不多。

二、导入 Cocos Creator

调整好模型之后,导出为引擎可识别的模型格式(本文用的是 *.glb 格式)。

将导出的文件导入到 Cocos Creator 中(麒麟子目前用的 v3.4.1 版本)。本文使用的冰墩墩 3D 模型由3个部分组成。

  • 身体
  • 胸圈
  • 外壳

如下图所示:

不要忘了设置天空盒,并开启 IBL。

三、调整材质

默认的材质已经很适合身体和胸圈了,所以,我们重点要处理的是外壳效果。

  • 新建一个材质,将材质的 technique 切换为 transparent 。
  • 调节 Albedo 的颜色和 Alpha 值,使外壳透明度和颜色值是自己看上去觉得喜欢的。
  • 调节 roughness 和 matellic 参数,形成高光和反射 并按下图中调节参数(具体参数根据个人喜好,不需要严格遵守)。

可能的效果如下图所示:

四、搭配场景

1、新建了一个圆柱体,调节适合的大小,并将我们制作好的冰墩墩放到上面。如下图所示:

2、新建几个 Quad,经过一系列的缩放、旋转、平移后,选两个面贴上贴图,就可以得到下面这样的台历:

麒麟子还写了一个简单的脚本,用于定时切换台历贴图,大家可以在 DEMO 源码中找到。

五、光影与视觉调节

1、开启 ShadowMap 并调整光源方向,使之与环境贴图的光线方向吻合。

2、调整好摄像机位置。

这里麒麟子写了一个脚本让摄像机围绕着冰墩墩旋转。

最终效果如下图所示:

好了,我们的冰墩墩就做好了。 我知道骗不了人民群众雪亮的眼睛,所以自己先把这话删了。

疑惑三连:

  • 桌子上的倒影呢?
  • 冰墩墩身上的 Blingbling 呢?
  • 冰墩墩边缘看上去的轮廓效果呢?

六、桌子上的倒影

桌子上的倒影采用的是实时反射效果进行渲染的。核心思路如如下:

1、渲染反射的摄像机

在中学时,我们学过上图中的平面镜成像原理。

根据这一原理我们知道,要想获得平面镜中的内容,只需要计算出物体关于镜面对称的空间数据(坐标、旋转)即可。

但整个世界的对象非常多,更高效的方法是计算出摄像机关于镜面的空间数据,生成镜像摄像机,并用这个摄像机进行渲染。

渲染反射的摄像机需要将内容输出到渲染纹理

关于镜像矩阵的推导,请看 Mirror.ts 。

2、自定义用户裁剪面

当摄像机镜像翻转后,可能遇上某物体处于镜面后,且刚好在镜像摄像机视野内的情况。

这种情况下,会渲染出不应该被渲染的物体(我们只想要镜面前方的物体),严重情况下,摄像机会被物体遮挡,无法看到(渲染)前面的物体,此时就要用到自定义用户裁剪面。

自定义用户裁剪面的基本逻辑是:若一个像素处于某平面之前,则保留,若处于平面之后,则丢弃(discard)。

关于 3D 编程中的平面相关内容不属于本文范围,大家可自行搜索,或等麒麟子后面的教程分享。

3、全局 Uniform

由于所有参与渲染的物体都需要进行用户自定义裁剪面的判断,而目前引擎版本没有提供自定义全局 Uniform 的机制。

当镜面发生改变时,需要遍历所有物体找到材质,设置相关 uniform 参数。

为了解决这样的麻烦事,麒麟子灵光一闪:不让新增,还不让借吗?空闲的全局变量是否可以借来用用?

在查阅了相关代码后,麒麟子找到了几个空闲的全局变量分量:

  • cc_time.w
  • cc_fogBase.w
  • cc_fogAdd.w
  • cc_nearFar.zw

Shader代码中如下使用:

void checkClipPlane(){
  vec4 clipPlane = vec4(0.0,0.0,0.0,0.0);
  clipPlane.w = cc_time.w;
  clipPlane.x = cc_fogBase.w;
  clipPlane.y = cc_nearFar.z;
  clipPlane.z = cc_nearFar.w;
  bool enabled = (clipPlane.x != 0.0) || (clipPlane.y != 0.0) || (clipPlane.z != 0.0);
  float dist = dot(v_position,clipPlane.xyz) + clipPlane.w;
  if( enabled && dist <= 0.0 ){
    discard;
  }
}

与之协作的 TypeScript 代码请查看 Demo 中的 GlobalUniformMgr.ts、Mirro.ts。

最终我们得到的纹理内容如下:

可以很明显看出来,它是倒着的。

4、投影纹理映射

投影纹理映射是一个专有名词,它的原理其实非常简单:在进行纹理映射时,不采用顶点的 uv 坐标信息,而使用顶点投影到屏幕上的位置信息。

当顶点 Pl(x,y,z,1)经过 WVP 变换后,进入裁剪坐标系,得到点 Pc(x,y,z,w),Pc 已经是一个屏幕空间的坐标了。

Pc 经过透视除法后,可以得到 NDC 坐标系中的点 Pndc(x/w,y/w,z/w,1)。

而 NDC 坐标系中 x,y 的取值为[-1,1],z的取值为[0,1]或者[-1,1](视图形 API 环境而定)。

//计算屏幕空间坐标 通常在 vs 中进行
v_screenPos = cc_matProj * (cc_matView * matWorld) * In.position;

//计算屏幕空间 uv 坐标, 需要在 fs 中进行,否则会出现精度问题。
vec2 screenUV = v_screenPos.xy / v_screenPos.w * 0.5 + 0.5;
screenUV = vec2(1.0 - screenUV.x,screenUV.y);

上面源码示例中的 screenUV 就是需要用到的 uv 值,用它进行反射贴图采样,即可得到我们想要的镜面反射效果,如下图所示:

详细代码请参考 Mirror.ts、effect-mirror.effect。

七、Blingbling 与轮廓

先给我们的冰墩墩来个特写吧。

上图中的冰墩墩外壳看起来晶莹剔透的主要原因,是因为渲染走的是折射机制,并不是普通的 Alpha 混合。

这个机制和把大象装进冰箱一样简单,只需三步:

第一步

使用一个专门的摄像机,渲染非透明物体到一张 RenderTexture 上,如下图所示:

第二步

切换到主摄像机,正常渲染场景物体。

第三步

在渲染半透明物体时,使用投影纹理技术对非透明物体 RenderTexture。核心代码如下:

#if AS_REAL_TRANSPARENT
  vec3 V = normalize(v_position - cc_cameraPos.xyz);
  vec3 N = normalize(s.normal);
  float fresnel = 1.0 - dot( -V, N);
  fresnel = pow(fresnel,fresnelPower);
  
  vec3 R = V - 2.0 * N * dot(N,V);
  
  vec2 offset = -v_normal_view.xy * refrIntensity;
  
  vec2 screenUV = v_screenPos.xy / v_screenPos.w * 0.5 + 0.5;

  vec3 sceneColor = texture(sceneMap,screenUV + offset).rgb;
  vec4 temp = texture(envMap,R);
  vec3 reflectionColor = unpackHDRI(temp);
  s.albedo.rgb = mix(sceneColor, reflectionColor * reflIntensity,fresnel);
  s.metallic = 0.1;
#endif

当摄像机转动的时候,可以清晰地感知到折射造成的扭曲效果。

冰墩墩身体边缘也会出现这样的效果。

目前版本的折射并未使用折射率进行计算,而是使用摄像机空间的法线方向进行采样偏移。

八、添加参数控制面板

为了所见即所得的调出满意的效果,参数控制面板是必须的,如下图所示:

九、最终效果与源码

点击文末【阅读原文】即可下载 DEMO。

特别提醒:本 DEMO 中使用的冰墩墩 3D 模型来自网络素材库,本文仅供学习,不涉及商业用途,如有侵权请与我们联系。

欢迎关注麒麟子随笔
获取更多图形渲染相关内容
往期精彩
浏览 121
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报