基于SDF的云朵消散效果

1.前置

SDF,即Signed Distance Function(符号距离函数)。SDF是一种数学表示方法,通常用于表示二维或三维几何图形的形状。关于这方面我也是找了许多的参考资料,都是二维的。(三维的我还没开始研究😢)

Signed Distance Field与Multi-channel signed distance field - 知乎前言最近总结了一下SDF方面的知识,参考了很多知乎上的文章,但是却发现对于SDF的圆角问题以及多通道SDF的参考资料却少得可怜。但是实际上UE4上已经有相关方面的插件: SharpText for Unreal Engine 4以及原作者的…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/398656596#:~:text=SDF%EF%BC%88signed,distance%20field%EF%BC%89%EF%BC%8C%E4%B8%AD%E6%96%87%E5%90%8D%E5%B8%A6%E7%AC%A6%E5%8F%B7%E8%B7%9D%E7%A6%BB%E5%9C%BA%EF%BC%8C%E6%9C%AC%E8%BA%AB%E5%8D%81%E5%88%86%E7%AE%80%E5%8D%95%EF%BC%8C%E5%B0%B1%E6%98%AF%E5%AF%B9%E6%AF%8F%E4%B8%AA%E5%83%8F%E7%B4%A0%E9%83%BD%E8%AE%B0%E5%BD%95%E8%87%AA%E5%B7%B1%E4%B8%8E%E8%B7%9D%E7%A6%BB%E8%87%AA%E5%B7%B1%E6%9C%80%E8%BF%91%E7%89%A9%E4%BD%93%E4%B9%8B%E9%97%B4%E7%9A%84%E8%B7%9D%E7%A6%BB%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%9C%A8%E7%89%A9%E4%BD%93%E5%86%85%EF%BC%8C%E5%88%99%E8%B7%9D%E7%A6%BB%E4%B8%BA%E6%AD%A3%EF%BC%8C%E6%AD%A3%E5%A5%BD%E5%9C%A8%E7%89%A9%E4%BD%93%E8%BE%B9%E7%95%8C%E4%B8%8A%E5%88%99%E4%B8%BA0%E3%80%82SDF(signed distance field)基础理论和计算 - 知乎一、SDF基础理论1.1SDF简单介绍一般来说,无论2d或者3d资产都有 隐式(implicit)和显式(explicit)两种存储方式,比如3d模型就可以用mesh直接存储模型数据,也可以用sdf、点云(point cloud)、神经网络(nerual re…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/536530019Signed Distance Fieldsicon-default.png?t=N7T8http://www.codersnotes.com/notes/signed-distance-fields/这些资料都详尽准确地给我们介绍了了sdf,SDF描述了空间中的每个点到最近图形表面的有向距离(即距离的正负表示方向)。如果点位于图形表面内部,则距离为负;如果点位于图形表面外部,则距离为正;如果点位于图形表面上,则距离为零。

然后,然后我就照着写了一个python版本的

from PIL import Image
import math

image = Image.open("表情.png")
picture_width = 1024
picture_height = 1024

class Point:
    #dx,dy表示对于当前点的偏移值
    dx = 0;
    dy = 0;
    def __init__(self,y,x):
        self.dx = x
        self.dy = y
    def DisSq(self):
        return self.dx*self.dx + self.dy*self.dy
class Grid:
    grid = None
    def __init__(self,w,h):
        self.grid = [[Point(0,0) for i in range(w)] for j in range(h)]

#g1和g2分别表示内部和外部两部分的距离
g1 = Grid(picture_width,picture_height)
g2 = Grid(picture_width,picture_height)

#inside = Point(0,0)
#empty = Point(999,999)

def Get(g,y,x):
    if x>=0 and x<picture_width and y>=0 and y<picture_height:
        return g.grid[y][x]
    else:
        return None

def Put(g,y,x,p):
    if x>=0 and x<picture_width and y>=0 and y<picture_height:
        g.grid[y][x] = p
    else:
        return None

def Compare(g,curP,curY,curX,offsetY,offsetX):
    curDis = curP.DisSq()    
    if curX + offsetX>=0 and curX + offsetX<picture_width and curY + offsetY>=0 and curY + offsetY<picture_height:
        #nexP是偏移后的点
        nexP = g.grid[curY + offsetY][curX + offsetX]
        nexDis = Point(nexP.dy + offsetY,nexP.dx + offsetX)        
        if nexDis.DisSq()<curDis:
            #更新偏移值
            curP.dy = nexP.dy + offsetY
            curP.dx = nexP.dx + offsetX

#遍历周围8个格子,找到最近距离
def GenerateSDFs(g):
    #由上到下遍历,再由下到上遍历
    for i in range(picture_height):
        #由左到右遍历,再由右到左遍历
        for j in range(picture_width):
            curP = Get(g,i,j)
            Compare(g,curP,i,j,-1,0)
            Compare(g,curP,i,j,-1,-1)
            Compare(g,curP,i,j,0,-1)                

        for k in range(picture_width-1,-1,-1):
            curP = Get(g,i,k)
            Compare(g, curP, i,k,-1, 1)
            Compare(g, curP, i,k,0, 1)


    for i in range(picture_height-1,-1,-1):
        for k in range(picture_width - 1, -1, -1):
            curP = Get(g, i, k)
            Compare(g, curP, i,k,1, 1)
            Compare(g, curP, i,k,0, 1)

        for j in range(picture_width):
            curP = Get(g, i, j)
            Compare(g, curP, i,j,1, 0)
            Compare(g, curP, i,j,1, -1)
            Compare(g, curP, i,j,0, -1)

    return


###########################
####      GenerateSDF
###########################
for i in range(picture_height):
    for j in range(picture_width):
        v = image.getpixel((j,i))
        if v[0]<128:
            Put(g1,i,j,Point(0,0))
            Put(g2,i,j,Point(999,999))
        else:
            Put(g2, i, j, Point(0,0))
            Put(g1, i, j, Point(999,999))
GenerateSDFs(g1)
GenerateSDFs(g2)




###########################
####      Render the picture
###########################

def clamp(v,min,max):
    if v<min:
        return min
    elif v>max:
        return max
    else:
        return v

    
image = Image.new('RGB', (picture_width, picture_height), color='white')

# Access the pixels of the image
pixels = image.load()


# min max
mi_g1 = 999
ma_g1 = 0
mi_g2 = 999
ma_g2 = 0
for y in range(picture_height):
    for x in range(picture_width):
        mi_g1 = min (mi_g1,g1.grid[y][x].DisSq())
        ma_g1 = max (ma_g1,g1.grid[y][x].DisSq())
        mi_g2 = min (mi_g2,g2.grid[y][x].DisSq())
        ma_g2 = max (ma_g2,g2.grid[y][x].DisSq())

# Set the color of each pixel to red
for y in range(picture_height):
    for x in range(picture_width):
        #把外部距离重映射到0-128
        dist1 = math.floor((g2.grid[y][x].DisSq() / (ma_g2 - mi_g2)) * 128)
        #把内部距离重映射到0-128,并用128减去这个数,让距离最远处为0    
        dist2 = 128 - math.floor((g1.grid[y][x].DisSq() / (ma_g1 - mi_g1)) * 128)

        dist = dist1 + dist2
        #rgb
        pixels[x, y] = (dist,dist,dist)
        

# Save the image
image.save('表情sdf.png')
        

输入:

输出:

 (有种难以言表的美,哈哈哈哈)

2.云消散效果的思路

做面片云也参考了许多的资料,分享一下

程序化天空盒实现昼夜变换 - 知乎一、资料收集与分析1.昼夜变换 Unity Shader 基于光照图的简易昼夜变化 Unity日夜循环天空球(Procedural Skybox) 【unity URP】昼夜循环天空球 Unity 卡通渲染 程序化天空盒 Unity 卡通渲染 程序化天空盒 昼夜变化…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/603032215Unity 卡通渲染 程序化天空盒 - 知乎写这篇文章快一年过去了,放两张在这期间里,用URP中最后做的仿原神的demo图。之前没考虑到tonemapping和叠加高度雾的效果。色彩参考原神和间谍过家家ED(约尔在天台24h的天空变化)。 分享一下学习过程中的碎碎念…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/540692272Signed Distance Field - 知乎signed distance field最近UE4.26上线了,离UE5又近了一点。UE的各种渲染大量运用了一种名为Signed Distance Field的技术,前段时间刷屏的《黑神话·悟空》的主程,在一次分享会上也介绍说《悟空》项目中,使用了S…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/337944099神作面部阴影渲染还原 - 知乎前几年学过两天渲染,昨天花了一个晚上,学Unity的shaderlab,做的这个还原。 结果折腾了半天我也没访问到shadowmap,只好装了URP然后在这个项目上写的代码 https://github.com/ColinLeung-NiloCat/UnityURPToonLi…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/279334552卡通渲染之基于SDF生成面部阴影贴图的效果实现(URP) - 知乎看了很多大佬的教程: 黑魔姬:神作面部阴影渲染还原 这篇讲了图的制作流程(大概思路) Signed Distance Fields 这篇讲了SDF的算法 橘子猫:如何快速生成混合卡通光照图 这是之前一个群里的大佬写的脚本,可以生…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/361716315大佬们做云阈值图的时候似乎都采用了多张图插值的方式(),这种方法可以自由控制消散的开始位置和结束位置。

但是本懒狗直接把云的贴图扔进python脚本用8ssedt方法处理。(在脚本中我只使用了内部距离)

输入:云.png

(这张图是没有亮部和暗部的,是纯白的云的轮廓图)

 输出:云sdf.png

 效果:

 额,效果不太行,到最后甚至变成了一个不规则多变型,甚至不能称之为云

如果我把云的阴影图和生成的sdf图混合一下会怎样

输入:云.png

(这张图是没有亮部和暗部的,是纯白的云的轮廓图)

云阴影.png

(自己画的云,丑是丑了点)

 输出:

 效果:

 好很多了,虽然到后面还是那样😂,只是让阴影图*0.5 + sdf图 * 0.5

其它优化方法还没试,这种方法的缺点也很明显,消散的最后位置一定是中心(可以用ps的变形工具弄一下)

SDF_cloud

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Unity人物消散Shader是一种用于在Unity引擎中实现人物消散效果的着色器。根据引用中提到的消散信息,可以推测这个Shader通过在人物的顶点色中使用纹理的B通道来实现消散效果消散信息指的是纹理中储存的SDF(Signed Distance Field)信息,用于控制人物消散效果。具体来说,SDF信息可以根据密度的不同在2D UV空间展开的3D空间场中生成。 在Unity中,可以使用Unity图形化Shader编写工具来创建人物消散Shader。这个工具可以帮助不熟悉图形学的人轻松制作出惊艳的效果,降低了Shader制作的入门难度。 关于UV1,它是Unity中的第二个UV通道。通常,第一个UV通道用于纹理映射,而第二个UV通道可以用于其他目的,比如消散效果中的片平铺和旋转等操作。 至于更好的看贴图通道的软件,Photoshop是一款广泛使用的图像处理软件,它提供了丰富的工具和功能,可以满足大多数贴图需求。但除了Photoshop外,还有其他一些专门用于贴图的软件,如Substance Painter和Mari等,它们提供了更高级的功能和工作流程,可以更方便地进行贴图制作。具体选择哪种软件取决于个人的需求和偏好。 总之,Unity人物消散Shader是一种可以通过Unity图形化Shader编写工具来实现的效果,通过使用纹理的消散信息来控制人物的消散效果。而UV1是Unity中的第二个UV通道,可以用于实现消散效果中的一些操作。至于更好的看贴图通道的软件,可以根据个人需求选择合适的软件进行贴图制作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [使用Unity的Shader Graph来制作3D物体溶解出现与消失效果](https://blog.csdn.net/qq_37755462/article/details/108582468)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【Unity Shader 赛博小人01】UV准备 SD制作特效贴图](https://blog.csdn.net/qq_41835314/article/details/128741563)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值