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 Fields
http://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 卡通渲染 程序化天空盒 昼夜变化…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大佬们做云阈值图的时候似乎都采用了多张图插值的方式(),这种方法可以自由控制消散的开始位置和结束位置。
![](https://img-blog.csdnimg.cn/aa505cc64d874e8f8eae546d550770ab.png)
但是本懒狗直接把云的贴图扔进python脚本用8ssedt方法处理。(在脚本中我只使用了内部距离)
输入:云.png
![](https://img-blog.csdnimg.cn/af75f36206ae48ce89bdfe857da42665.png)
输出:云sdf.png
效果:
额,效果不太行,到最后甚至变成了一个不规则多变型,甚至不能称之为云
如果我把云的阴影图和生成的sdf图混合一下会怎样
输入:云.png
![](https://img-blog.csdnimg.cn/af75f36206ae48ce89bdfe857da42665.png)
云阴影.png
![](https://img-blog.csdnimg.cn/c5ce042089ff4559b35bed4d3c6a9d1d.png)
输出:
效果:
好很多了,虽然到后面还是那样😂,只是让阴影图*0.5 + sdf图 * 0.5
其它优化方法还没试,这种方法的缺点也很明显,消散的最后位置一定是中心(可以用ps的变形工具弄一下)
SDF_cloud