UE4 材质 UV膨胀技术

news/2024/11/30 11:42:48/

自动和改进的UV膨胀材质

在处理带有不透明遮罩的纹理时,将边缘像素放大或延伸到背景中可能很重要。对于蒙版材质,这可以防止在低等级的mipmap中的边缘渗出现象。
为什么会有出现这个情况呢?

主要是mipmap是根据DDX,和DDY进行判断的,这两个函数的作用就是用来判断在这个像素的某一个参数值,在屏幕相邻的像素点中是一个什么差值。用来判断使用mipmap的等级,实际的情况还没有看,不过差不多就是这个道理:如果我的mipmap等级很高,也就是距离的非常的远,那么对于蒙版来说,这会导致采样的蒙版贴图的边缘会出现插值,也就是对于蒙版的边缘,会有一些黑边的出现。

对于动态mesh的绘制效果,膨胀的位置纹理贴图(" positional texture maps ")将允许跨越UV边界进行无缝的绘制。位置纹理贴图对膨胀非常敏感,因此为位置贴图正确的执行膨胀非常重要。

在这篇文章中,我们将研究一种为静态网格创建位置纹理贴图的方法,并在unreal engine 4使用像素着色器扩展它们。我们使用一种 slope extrapolation方法,以更精确地重建边缘附近的像素,就好像它们是从边缘开始的一样。

首先,让我们进入到为什么需要这个技术的场景当中。

DilationExample.jpg
与16像素和64像素半径的膨胀相比,上图的第一行第一个图像显示了未膨胀时的纹理。第二行显示应用到蒙版的材质,并演示较低的mipmap在不使用膨胀时背景出现渗出的情况。膨胀版将保持其外观,并且不会在远处出现黑色轮廓。

除了上述的mip-map问题外,如果不使用膨胀,最高级别的mip也会出现问题。在将多边形渲染到纹理贴图时,多边形的边缘倾向于以一定角度横切像素,从而使像素以阶梯状图案跨越多边形的边缘。这些像素将是白色或黑色,因此在纹理分辨率下可以看到台阶。
Dilate_Graph_01.gif
在实时渲染中,这叫做锯齿。暴力的解决方案是以更高的分辨率渲染,然后将图像采样到所需的分辨率。在许多情况下,这是可行的,但是由于纹理过滤的工作方式,边缘伪影仍然可以悄悄地进入,并且我们可能没有足够高的分辨率的原始素材。膨胀通过向外扩展边缘上的像素来解决问题,这样它们可以混合到其他颜色相似的像素而不是纹理背景颜色。

大多数图像编辑程序(PS)都具有可以处理膨胀的插件,并且大多数插件在处理颜色信息时效果很好,而在处理位置或法线时效果不佳。 对于特殊情况,我们需要动态创建展开的UV图,并在该过程中自动对其进行膨胀。
关于展开UV,可以参考
https://papalqi.cn/index.php/archives/521/

结果是,一个膨胀器比Photoshop的xNormal更好地处理位置数据和法线数据,并且速度更快。

拥有一个展开的位置贴图意味着您可以在静态网格上执行光线跟踪类型操作,例如通过在世界上进行光线追踪将spheremask绘制到网格上。

这是一些基本膨胀器的代码。它在指定的距离内搜索8个相邻的正方形图案。注意,在变量“offset”中,上下左右在对角线偏移之前。这只是一个简单的方式来确保更短的距离的坐标值能够率先被使用。

float texelsize = 1 / TextureSize;
float2 offsets[8] = {float2(-1,0), float2(1,0), float2(0,1), float2(0,-1), float2(-1,1), float2(1,1), float2(1,-1), float2(-1,-1)};
float3 sample = Tex.SampleLevel(TexSampler, UV, 0);if(sample.x != 0 || sample.y != 0 || sample.z != 0) return sample;
int i, j = 0;while(i < MaxSteps)
{i++;while (j < 8){float2 curUV = UV + offsets[j] * texelsize * i;float3 offsetsample = Tex.SampleLevel(TexSampler, curUV, 0);if(offsetsample.x != 0 || offsetsample.y != 0 || offsetsample.z != 0) return offsetsample;j++;}
}return MinSample;

这在某些情况下是可行的,但是这个简单方法的问题是它只是将边缘像素从原来的位置向外拉伸。这意味着边缘上的任何过滤的纹理都将被插值到错误的值,因为相邻像素不会倾向于实际位置的方向:
simpledilation.jpg

为了解决这个问题,我们可以在代码中引入一些斜率的数学技巧。这意味着每当代码找到一个可能的像素进行采样时,而不是仅仅使用该值,它就会检查另一个稍微有点偏移的像素,并获取这两个像素之间的差异。使用两个采样点之间的距离,可以建立一个斜率,然后使用该斜率将采样向外外推到实际写入的像素。

SlopeProjection.jpg
在上图中,您可以想象蓝色阴影多边形是某个高度贴图或位置纹理的侧剖面图。绿点是我们理想中想要膨胀到像素点。如果使用简单的膨胀,直接从最近找到的邻居(上面的蓝点)复制值。这会导致红线是平的,并且不会继续保持原始数据的斜率。通过采取一个额外的偏移采样(上面的橙色点),可以计算斜率,最终值可以是原始数据的连续斜率。

若要将其添加到上述着色器,只需要几行。这发生在最后一个if语句的内部,该语句检查找到的邻居是否不等于0。

float2 projectUV = curUV + offsets[i] * texelsize * j * 0.25;
float3 direction = Tex.SampleLevel(TexSampler, projectUV, 0);float3 delta = offsetsample - direction;
MinSample = offsetsample + delta * 4;

无论当前偏移距离是多少,这只会将另一个样本推出0.25倍。选择此值是为了避免跳过太远的前方,并且可能读取所需目标像素另一侧的黑色值。这可以通过另一个迭代检查来找到理想的新样本位置,但在我的测试中,这很好,因为我在uv布局上没有任何非常薄的部分。注意delta乘以4,这是考虑到偏移量是0.25倍的长度。
improveddilation.jpg

现在让我们快速看看这到底是如何改善膨胀效果的。一个只有8个样本方向的标准膨胀看起来质量不是很高,通过控制参数,你会很快开始看到8个样本方向随着距离增加出现一条硬线的形成。斜率外推完全解决了这个问题,甚至完美地连接了此隔离的UV环内部的UV:

ImprovedDilationComparison.jpg

在上面的图像中很难看到,但中心峰值的平滑实际上并不能使它在使用此位置贴图进行渲染时工作得更好。它是原始彩色像素之外数据的斜率和曲率的延续。在下面的例子中,我增加了图像的对比度,并在感兴趣的区域指向箭头。请注意,在左侧,值在原始标注栏的任一侧停止增加,这会导致某种可见的夹点,而在右侧,整个区域是连续的。
ImprovedDilationComparison2.jpg

膨胀代码。请记住,此代码可能不适用于所有类型的UV布局,并且可以通过对相邻的偏移查找代码添加进一步的检查来轻松改进。通过将采样变量更改为float4并使用alpha而不是rgb进行0检查,可以对其进行一些修改以使用常规颜色纹理。采用曲率代替斜率作为输入,可以得到更精确的结果。

UV Positional Dilation ///
//** Tex **// Input Texture Object storing Volume Data
//** UV **// Input float2 for UVs
//** TextureSize **// Resolution of render target
//** MaxSteps **// Pixel Radius to searchfloat texelsize = 1 / TextureSize;
float mindist = 10000000;
float2 offsets[8] = {float2(-1,0), float2(1,0), float2(0,1), float2(0,-1), float2(-1,1), float2(1,1), float2(1,-1), float2(-1,-1)};float3 sample = Tex.SampleLevel(TexSampler, UV, 0);
float3 curminsample = sample;if(sample.x == 0 && sample.y == 0 && sample.z == 0)
{int i = 0;while(i < MaxSteps){ i++;int j = 0;while (j < 8){float2 curUV = UV + offsets[j] * texelsize * i;float3 offsetsample = Tex.SampleLevel(TexSampler, curUV, 0);if(offsetsample.x != 0 || offsetsample.y != 0 || offsetsample.z != 0){float curdist = length(UV - curUV);if (curdist < mindist){float2 projectUV = curUV + offsets[j] * texelsize * i * 0.25;float3 direction = Tex.SampleLevel(TexSampler, projectUV, 0);mindist = curdist;if(direction.x != 0 || direction.y != 0 || direction.z != 0){float3 delta = offsetsample - direction;curminsample = offsetsample + delta * 4}else{curminsample = offsetsample;}}}j++;}}
}return curminsample;

http://www.ppmy.cn/news/537133.html

相关文章

功能性镜片之一——变色镜片

每个人都有过这样的体会&#xff1a; 一位朝夕相处、每天见面的同事&#xff0c;如果突然换了一副近视眼镜&#xff0c;你会感觉整个人的外表都会有所变化。这是因为看一个人的外表&#xff0c;首先会注意到的是眼睛&#xff0c;而眼镜长期与双眼相伴&#xff0c;成为最容易被…

虹科技术|半导体制造工艺中使用的UV-LED技术

半导体行业借助紫外光谱范围&#xff08;i 线&#xff1a;365 nm、h线&#xff1a;405 nm和g线&#xff1a;436 nm&#xff09;中的高功率辐射在各种光刻、曝光和显影工艺中创建复杂的微观结构&#xff0c;例如生产集成电路&#xff08;IC&#xff09;、液晶显示器 &#xff08…

【Unity Shader】(十) ------ UV动画原理及简易实现

笔者使用的是 Unity 2018.2.0f2 VS2017&#xff0c;建议读者使用与 Unity 2018 相近的版本&#xff0c;避免一些因为版本不一致而出现的问题。 【Unity Shader】&#xff08;三&#xff09; ------ 漫反射和高光反射的实现【Unity Shader】&#xff08;四&#xff09; ------ …

偏光太阳镜测试图片软件,[专题]真假偏光太阳镜简单、实用辨别方法!

偏光太阳镜主要是通过镜片的平衡排列的结晶体原理&#xff0c;只让与晶体平衡的光波通过&#xff0c;而向其它角度震动的光波会一律被阻挡的方法(如同百叶窗的原理)制作而成。 正是利用这种原理&#xff0c;偏光太阳镜便可以有效地排除和滤除光束中的偏振光&#xff0c;使光线能…

黄色镜片与蓝光

蓝光是指波长范围400~500纳米的可见光&#xff0c;蓝光最大的来源不是屏幕&#xff0c;而是太阳光。 波长在400~470纳米之间的是有害蓝光&#xff0c;而波长在480~500纳米间的蓝光则伤害没有那么大&#xff0c;反而是有益的蓝光[1] 蓝光的范围400-600nm都算&#xff0c;紫外线…

紫外线UV杀菌灯的工作原理

UV是紫外线的意思&#xff0c;LED&#xff0c;发光二极管简称为LED&#xff0c;UV-LED光源即紫外发光二极管。紫外线中包含UVA、UVB、UVC三个波段的紫外光&#xff0c;UVA&#xff08;315~400nm&#xff09;&#xff0c;也称为长波紫光或者“黑光”&#xff1b;UVB&#xff08;…

【Simulink】基于FCS-MPC的带阻感负载的三相逆变器控制(Matlab Function)

之前写过三相并网逆变器FCS-MPC的博客 &#x1f449;【Simulink】基于FCS-MPC的三相并网逆变器控制&#xff08;Matlab Function&#xff09; 应用的对象是并网的&#xff0c;用一个电压源&#xff08;Three-Phase Programmable Voltage Source&#xff09;模拟交流电网。 本篇…

JavaScript实现tab效果图

图片地址&#xff1a;http://download.csdn.net/detail/richard_jason/9669782 效果图&#xff1a; 示例代码&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&qu…