Cocos Creator 3D 热力图|征稿活动V5

1. 最终效果

2D的热力图

3D热力图

2.思路

热力图的输入数据就是 热力点的位置,和热力点强度值,组成的一个一维数组。

不管是啥输入,都要处理成 上面这个样子

生成热力图的流程 就是生成热力点,由热力点 生成灰度图,由灰度图 作为模型贴图,用灰度图决定 模型的颜色

2.1 生成3D热力点

热力点长啥样,热力点就是一个圆,从中间到边缘,透明度越来越低,中间最实,边缘最虚

从圆心(0.5,0.5)到边缘,alpha从1 到 0

我们可以生成3D的热力点就是一个片 quad

image

我们知道纹理采样,是从0到1,那么中心位置就是(0.5,0.5)

如何判断边缘,我们在片段着色器 fragment 中可以拿到 模型的uv坐标,本来这个片是一个正方形,我们要将其变成一个圆形,那我们计算出 uv 到中心点的距离 了 L, 圆圈中的点的到中心点的距离是0 到0.5,即 L的取值范围是0到0.5

我们要根据L的值 决定 alpha 的范围,apha的范围是由1=》0,

image
alphaFix 是热力点的强度,这个值越大,实的地方越多,虚的地方越少

2.2 生成灰度图

就是用一个3D 热力点的预制体,生成很多个热力点进行叠加
我们使用一个专门的3D摄像机拍摄这些热力点 ,在将摄像机拍摄的内容用RenderTexture来承载,RenderTexture就像照相机的底片,注意摄像机是正交摄像机。不会有

2.3 灰度图决定plane 的颜色输出

我们有灰度图之后,在使用一张色板图片,用灰度图的任意一个通道,r,g,b,我们选取r通道的值,r的取值范围是[0,1],r的取值越大,输出的颜色应该越红

那么我们使用uv值,对灰度图进行纹理采样,拿到 灰度值,使用灰度值,对色板图片进行纹理采样,纹理采样的坐标是 vec2(gray.r,0.5)
image

2D heatmap shader效果

plane 使用的 RenderTexture 贴图

显示效果
image

2.4 使用灰度值对模型顶点进行偏移

我们可以在顶点着色器,使用 模型顶点uv v_uv对灰度图进行纹理采样,采样得到的color ,取color.r 作为灰度值,来决定 顶点坐标 v_position的 y 。这样就把热力图变成3D的了,如果不需要3D热力图,那么对顶点着色器不进行额外的处理,就好了

2.5 也可以使用2D 的热力点,生成灰度图

我们需要写一个2D 热力点的shader ,图片从(0.5,0.5)中心位置,alpha 是1 到0,

我们也主要改的是片元着色器,思路和3D的热力点一样

我们可以拷贝 引擎里中自带的butlin-sprite这个effect的内容,然后修改片元着色器就好了

注意材质使用的图片,去掉packable的勾选

3.遇到的问题

3.1 不设置RenderTexture的大小,渲染不出灰度图

RenderTexture的大小,要设置大于512 512,保守就设置成10001000

3.2 2Dshader 在浏览器无法渲染,在编辑器中渲染正确

去掉Packable的勾选之后,这张图片就不会参与动态合图

或者

3.3 3D 热力点 Quad 模型重叠 关闭深度测试


3.4 renderTexture 贴图到模型上,上下相反

出现问题的原因是 使用默认的mesh plane

重新动态创建mesh plane ,贴图方向正确



3.4 摄像机是正交摄像机,否则热力点不显示

3.5设置2D 材质的uniform,不生效

生成热力点的逻辑

4.写Shader的Tips

4.1 写3D shader tips

默认创建的effect 是3D的,带了一个默认的片元着色器,但是如果我们想对模型的顶点做一些啥操作,但是自己一行一行敲,很容易出现语法错误

新建一个my-vs的顶点着色器片段,

找到general-vs chunk ,将其复制到my-vs 顶点着色器片段内,然后进行修改

4. 2 写2D shader

就直接找引擎内置的builtin-sprite.effect,拷贝,然后复制到你新建的 effect文件,直接修改frag 着色器就好了,顶点着色器不需要修改

5 继续优化

5.1.没有刷新热力图的功能,如果是动态热力图

就是热力图的热力点数据是变化的

我们要刷新热力图

因为刷新热力图,我们需要动态创建热力点,销毁热力点,动态刷新RenderTexture

我们可以创建3D的热力点,也可以创建2D的热力点

2.进一步优化

我们拿到热力点数据 =》清空所有的热力点节点,重置RenderTexture =》创建所有热力点到画布,设置热力点的强度=》摄像机渲染到RenderTexture

这套逻辑是通用的,抽一个通用的组件出去

后面使用就是获取热力点数据,然后传给这个类就可以了

抽出通用的部分,复用 抽象是编程一个重要的思想

3.为了复用

如果别的子场景也要显示热力图,下一个项目也要用热力图,那么?

我们既可以使用3D的热力点 (quad) ,也可以使用2D热力点(sprite),那么我们需要一个拍摄2D热力点的摄像机,另一个拍3D热力点的摄像机,一个包含所有2D热力点的一个节点。另一个包含所有3D热力点的一个节点。我们提前建好Prefab,设置好参数。

按照想法上面我们创建了一个类,这个类应该有 添加热力点,移除热力点,重置RenderTexture ,render 的方法,,还需要 实例化 HiddenCanvas 预制到场景中这个方法

https://gitee.com/dreamman123/heat-map-demo.git

7赞

大佬 666