星仔亮晶晶 发表于 2023-3-6 12:18:49

Unreal浅做一个MetaBall

Hello,大家好,今天是raycharching的初学,我是木偶心没。

Raymaching其实就是实时场景的一种渲染方法。主要原理网上有很多详细介绍,简单来说就是,以摄像机为原点,发射很多条射线,而每一条射线以步长为单位向前采样,同时以采样点和最近的物体像素的距离为半径进行一个球形检测。检测到摄像机和场景像素在当前射线方向的距离差小于某个值,就表示射线到达物体表面,然后画这个像素。



开始在unreal里面进行简单的实现

首先上才艺



图片仅供参考,具体以实物为准

1、custom节点算出球体

先上代码

float distance = length(pos-ObjectPosition)-50;

减去50表示小球的半径



2、去掉被遮挡的部分

为了对算法进行优化,我们可以去掉球体被遮挡的部分,比如说地面以下的部分。

判断场景深度是否小于摄像机到物体像素的距离,小球处于地面以下后,深度值就会取平面的深度值,所以如果深度值小于摄像机到像素距离的话,不进行检测。



3、添加法线

求法线就简单粗暴的对检测结果求一个梯度变化,设定一个值,求在这个值前后的检测结果的插值。最后把normal的信息也输出出来。具体结果如下




注意材质球的normal要取消勾选targent space normal,因为算出来的是一个世界法线




4、跟地面的融合效果

参考文档https://iquilezles.org/articles/distfunctions/,里面有很多算形状等基本运算的公式代码,以及详细推导



关于这个公式的详细算法推导链接如下

https://iquilezles.org/articles/smin/

主要就是一个分段函数,d1是检测出来的小球,d2是与其相交的一个物体的距离场,k表示两个相交的物体在相交那部分的一个过渡值,即达到这个值开始相交。

所以d1 = RM.RMSphere(pos-ObjectPosition);

而d2,这里用深度代替距离场,就等于射线方向上那个物体对应的场景深度减去摄像机到小球像素的距离

float d2 = SceneDepth - length(pos - CameraPosition);

这里混合d1和d2用lerp。




最终效果



调整采样步数等可以解决边缘锯齿,但是性能计算会更大,目前还没有找到一个更好的解决办法。

页: [1]
查看完整版本: Unreal浅做一个MetaBall