本文主要是介绍基于SDF的云朵消散效果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.前置
SDF,即Signed Distance Function(符号距离函数)。SDF是一种数学表示方法,通常用于表示二维或三维几何图形的形状。关于这方面我也是找了许多的参考资料,都是二维的。(三维的我还没开始研究😢)
Signed Distance Field与Multi-channel signed distance field - 知乎前言最近总结了一下SDF方面的知识,参考了很多知乎上的文章,但是却发现对于SDF的圆角问题以及多通道SDF的参考资料却少得可怜。但是实际上UE4上已经有相关方面的插件: SharpText for Unreal Engine 4以及原作者的…https://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…https://zhuanlan.zhihu.com/p/536530019Signed Distance Fieldshttp://www.codersnotes.com/notes/signed-distance-fields/这些资料都详尽准确地给我们介绍了了sdf,SDF描述了空间中的每个点到最近图形表面的有向距离(即距离的正负表示方向)。如果点位于图形表面内部,则距离为负;如果点位于图形表面外部,则距离为正;如果点位于图形表面上,则距离为零。
然后,然后我就照着写了一个python版本的
from PIL import Image
import mathimage = Image.open("表情.png")
picture_width = 1024
picture_height = 1024class Point:#dx,dy表示对于当前点的偏移值dx = 0;dy = 0;def __init__(self,y,x):self.dx = xself.dy = ydef DisSq(self):return self.dx*self.dx + self.dy*self.dy
class Grid:grid = Nonedef __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 Nonedef Put(g,y,x,p):if x>=0 and x<picture_width and y>=0 and y<picture_height:g.grid[y][x] = pelse:return Nonedef 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 + offsetYcurP.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 minelif v>max:return maxelse:return vimage = 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-128dist1 = 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#rgbpixels[x, y] = (dist,dist,dist)# Save the image
image.save('表情sdf.png')
输入:
输出:
(有种难以言表的美,哈哈哈哈)
2.云消散效果的思路
做面片云也参考了许多的资料,分享一下
程序化天空盒实现昼夜变换 - 知乎一、资料收集与分析1.昼夜变换 Unity Shader 基于光照图的简易昼夜变化 Unity日夜循环天空球(Procedural Skybox) 【unity URP】昼夜循环天空球 Unity 卡通渲染 程序化天空盒 Unity 卡通渲染 程序化天空盒 昼夜变化…https://zhuanlan.zhihu.com/p/603032215Unity 卡通渲染 程序化天空盒 - 知乎写这篇文章快一年过去了,放两张在这期间里,用URP中最后做的仿原神的demo图。之前没考虑到tonemapping和叠加高度雾的效果。色彩参考原神和间谍过家家ED(约尔在天台24h的天空变化)。 分享一下学习过程中的碎碎念…https://zhuanlan.zhihu.com/p/540692272Signed Distance Field - 知乎signed distance field最近UE4.26上线了,离UE5又近了一点。UE的各种渲染大量运用了一种名为Signed Distance Field的技术,前段时间刷屏的《黑神话·悟空》的主程,在一次分享会上也介绍说《悟空》项目中,使用了S…https://zhuanlan.zhihu.com/p/337944099神作面部阴影渲染还原 - 知乎前几年学过两天渲染,昨天花了一个晚上,学Unity的shaderlab,做的这个还原。 结果折腾了半天我也没访问到shadowmap,只好装了URP然后在这个项目上写的代码 https://github.com/ColinLeung-NiloCat/UnityURPToonLi…https://zhuanlan.zhihu.com/p/279334552卡通渲染之基于SDF生成面部阴影贴图的效果实现(URP) - 知乎看了很多大佬的教程: 黑魔姬:神作面部阴影渲染还原 这篇讲了图的制作流程(大概思路) Signed Distance Fields 这篇讲了SDF的算法 橘子猫:如何快速生成混合卡通光照图 这是之前一个群里的大佬写的脚本,可以生…https://zhuanlan.zhihu.com/p/361716315大佬们做云阈值图的时候似乎都采用了多张图插值的方式(),这种方法可以自由控制消散的开始位置和结束位置。
但是本懒狗直接把云的贴图扔进python脚本用8ssedt方法处理。(在脚本中我只使用了内部距离)
输入:云.png
输出:云sdf.png
效果:
额,效果不太行,到最后甚至变成了一个不规则多变型,甚至不能称之为云
如果我把云的阴影图和生成的sdf图混合一下会怎样
输入:云.png
云阴影.png
输出:
效果:
好很多了,虽然到后面还是那样😂,只是让阴影图*0.5 + sdf图 * 0.5
其它优化方法还没试,这种方法的缺点也很明显,消散的最后位置一定是中心(可以用ps的变形工具弄一下)
SDF_cloud
这篇关于基于SDF的云朵消散效果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!