UE4_材质基础_切线空间与法线贴图

UE5——材质学习笔记(3):水着色器 常用材质节点:材质蓝图入门2 材质系统根节点设置属性详解:UE4笔记-材质 UE5新特性参考文档:剖析虚幻渲染体系(06)- UE5特辑Part 1(特性和Nanite) 文章目录1、水面波纹-23说明分析Absolute World Position绝对世界位置节点DeriveNormalZ_Function节点BlendAngleCorrectedNormals节点2、水面实现湖泊-24说明分析sceneDepth节点PixelDepth节点3、水面的反射和折射-25说明分析4、水波扰动-26说明分析 阅读详情
AI摘要

本文围绕UE4材质中的切线空间与法线贴图展开。介绍了切线空间的概念、为何需要它及求解方法,阐述了法线贴图存储内容与压缩方式。还讲解了多种法线混合算法,如线性混合、叠加混合等,最后说明了UE4中调整法线强度、融合法线贴图及用普通贴图制作法线的方法。

学习笔记,不喜勿喷,侵权立删,祝愿大家生活越来越好!                 

一、切线空间

在《OpenGL基础11:空间》中提到了观察空间、裁剪空间、世界空间等。切线空间和它们一样,都属于坐标空间

上面就是一个切线空间的例子,对于切线空间:

  • N:该顶点本身的法线方向,z轴
  • T:该顶点的一条切线,但由于切线数量有无数条,其一般由模型给定,对应着UV图中的U,也就是使用和纹理坐标方向相同的那条
  • B:由前两者叉乘得到,对应着UV图中的V

UV图:用于告知计算机,如何用2维的贴图包住3维的物体,本质上UV图提供了一种模型表面与纹理图像之间的连接关系,也就是确定纹理图像上的每一个像素应该放置在模型表面的哪一个顶点上,如果没有UV图,多边形网格将不能被渲染出纹理,其中U和V分别指的是纹理空间的水平轴和垂直轴

二、为什么需要切线空间


在此之前,先需要大致了解一下法线贴图(Normal Mapping):为了得到正确的光照,需要知道物体每个顶点的法向量,但为了保证效率,一般物体的顶点不会太多,就像一块砖块,它的表面往往凹凸不平,但事实上它可能单纯的只是一个立方体,每一面给上了一个贴图。这样如果还想要体现出物体“凹凸不平”的效果,就需要用到法线贴图或者高度贴图,也就是对于纹理的每一个像素,都指定一个特定的法向量!

很巧,法向量是个3维向量,而颜色正好也是一个3维向量,所以直接将向量信息存储成颜色信息没有任何的压力

可是这样就出现了另一个问题:就像下图是一个黑色小包模型的一部分,中间有两个拉链拉头,这两个子模型是完全一样的,唯一的区别就是位置不同从而光照的效果不同。那么很明显,为了节省空间和性能,用的也会是同样的贴图,但是!他们的法向量却不一样,也就是说这两个完全相同的物体并不能使用同一张法线贴图(法线贴图可以说只是个数据存储媒介,和颜色没有关系)

确实可以为这些相同的子模型准备不同的法线贴图,就像一个六个面相同的立方体,为它专门准备6张法线贴图,但是有可能这样的子模型特别多,并且方向都不相同,这个时候还准备不同的法线贴图就比较尴尬了

上面的问题归根结底就是物体的朝向问题,我们只要找到这样的一个空间:无论当前是什么朝向,所有“纹理像素点”的法向量一定都是不变的,并且可以通过空间变换就可以得到世界坐标下正确的法向量,就可以解决问题了。所有相同的面,都可以赋予同样的法线贴图。

这个空间就是切线空间,酷不酷?

三、如何求出切线空间

切线空间是什么?对于一个网格模型,我们逐顶点来分析,每个顶点都有着自己的切线空间,如下图所示,我们可以将其称为TBN空间。其中N代表该点处的法线,T(tangent)和B(binormal)都是该点处的切线。由于一个点处的切线有无数条,我们指定T切线是沿着纹理的u坐标方向的,B切线是沿着纹理的v坐标方向的。 

从最简单的开始算:一个4个顶点100%平坦的平面,怎么求出它的切线空间呢?

T (Tangent) B (Bitangent) N (Normal) 向量一个一个来:

N 就不说了,它就是法向量,然后就是 T 切线向量:

肯定的,T、B、N都是单位长度,这样的话根据右图可以得到:

\begin{array}{l} E_{1}=\Delta U_{1} T+\Delta V_{1} B \\ E_{2}=\Delta U_{2} T+\Delta V_{2} B \end{array}

只要理解了这个公式后面就都好办了,首先可以看出,这是求的顶点P2的切线空间,而P1、P2、P3是当前P2所在的一个三角形片元,其次,E1、E2其实已经当前点的其中的两条切线了,只不过为了统一切线,切线的方向必须是纹理UV的方向,正好点 P1和P3的纹理坐标映射在主副切线方向上的向量之和正是向量E1和向量E2之和,同时也是说E2是三角形的一条边,这个三角形的另外两条边是\DeltaU2和\DeltaV2 ,它们与切线向量T和副切线向量B方向相同。

既然 E、U、V 都是已知的,那么就可以求出 T 和 B 了:

上面的公式可以写成:

\begin{array}{l} \left(E_{1 x}, E_{1 y}, E_{1 z}\right)=\Delta U_{1}\left(T_{x}, T_{y}, T_{z}\right)+\Delta V_{1}\left(B_{x}, B_{y}, B_{z}\right) \\ \left(E_{2 x}, E_{2 y}, E_{2 z}\right)=\Delta U_{2}\left(T_{x}, T_{y}, T_{z}\right)+\Delta V_{2}\left(B_{x}, B_{y}, B_{z}\right) \end{array}

转成矩阵就是:

\left[\begin{array}{ccc} E_{1 x} & E_{1 y} & E_{1 z} \\ E_{2 x} & E_{2 y} & E_{2 z} \end{array}\right]=\left[\begin{array}{cc} \Delta U_{1} & \Delta V_{1} \\ \Delta U_{2} & \Delta V_{2} \end{array}\right]\left[\begin{array}{ccc} T_{x} & T_{y} & T_{z} \\ B_{x} & B_{y} & B_{z} \end{array}\right]

两边都乘以\DeltaU和\DeltaV的逆矩阵:

好了搞定,把未知数成功扔到了左边

转成代码就是(代码中的数据输入是最简单情况:一个平面正方形,4个顶点分别是:(-1, -1, 0)、(-1, 1, 0)、(1, -1, 0)和(1, 1, 0),对应的纹理顶点为(0, 0)、(0, 1)、(1, 0)和(1, 1)):

void GetTangent()
{
    glm::vec3 pos1(-1.0, 1.0, 0.0);
    glm::vec3 pos2(-1.0, -1.0, 0.0);
    glm::vec3 pos3(1.0, -1.0, 0.0);
    glm::vec3 pos4(1.0, 1.0, 0.0);
    glm::vec2 uv1(0.0, 1.0);
    glm::vec2 uv2(0.0, 0.0);
    glm::vec2 uv3(1.0, 0.0);
    glm::vec2 uv4(1.0, 1.0);
    glm::vec3 normal(0.0, 0.0, 1.0);
 
    glm::vec3 tangent1, bitangent1;     //第一个三角形(1,2,3)的顶点切线空间
    glm::vec3 tangent2, bitangent2;     //第二个三角形(1,3,4)的顶点切线空间
 
    glm::vec3 edge1 = pos2 - pos1;
    glm::vec3 edge2 = pos3 - pos1;
    glm::vec2 deltaUV1 = uv2 - uv1;
    glm::vec2 deltaUV2 = uv3 - uv1;
    GLfloat f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
    tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
    tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
    tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
    tangent1 = glm::normalize(tangent1);
    bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
    bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
    bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
    bitangent1 = glm::normalize(bitangent1);
 
    edge1 = pos3 - pos1;
    edge2 = pos4 - pos1;
    deltaUV1 = uv3 - uv1;
    deltaUV2 = uv4 - uv1;
    f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
    tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
    tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
    tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
    tangent2 = glm::normalize(tangent2);
    bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
    bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
    bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
    bitangent2 = glm::normalize(bitangent2);
 
    GLfloat quadVertices[] =
    {
        //位置                  //法向量          //纹理坐标    //切线                              //副切线
        pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
        pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
        pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
        pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
        pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
        pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z
    };
    //……
}

四、TBN与空间变换

其实关于切线空间的了解到这里就结束了,下面可以当作扩展记录一下:

仔细看上面转换过程中的一个式子:

换一种表示方法就是:

或许就可以更容易发现, T 和 B 其实正是一组基向量,抛开法向量那一维,T 和 B 正好可以将二维uv空间中的向量和点,转到三维世界空间的某个平面上,而这个平面正好是切线平面

也就是说,如果T和B是已知的、切线空间是已知的,那么我们很容易就可以将二维纹理坐标映射到三维空间顶点坐标,而上面计算的所以意义,就在于我们知道二维空间纹理坐标,也知道三维空间顶点坐标,要反过来去找这个空间

如果理解了这个,就好办了,不用纠结于坐标和法线,它的本质就是如此

五、法线贴图存储的是什么?

法线贴图其实并不是真正的贴图,所以也不会直接贴到物体的表面,它所起的作用就是记录每个点上的法线的方向。所以这个贴图如果看起来也会比较诡异,经常呈现一种偏蓝紫色的样子,主要是因为法线纹理的RGB通道存储了在每个顶点各自的切线空间中的法线方向的映射值,其实法线向量有三个值,这三个值可以分别对应RGB三个值,一般法线垂直于物体的分量多一些,也就是Blue多一些,也就偏向于蓝色了。

六、法线压缩

 压缩的第一步很简单,由于归一化的法线长度为1,且在切线空间下,法线的z分量不可能为负数,所以只需要存储x和y值即可。本文的压缩方法在这一步压缩的基础上,利用现有的纹理压缩方法,进行进一步压缩。

  在支持DirectX10的显卡上,可以使用BC5格式进行压缩。BC5的压缩方法内存情况如图1所示,该格式有两个颜色通道(R和G),每个通道使用两个1Byte的值来表示,每个像素使用3Bit在这两个颜色值之间进行插值。将法线贴图中每个法线的x和y值利用BC5格式进行压缩,如图2所示。对每个Block(16个像素)存储x的最大、小值和y的最大、小值,然后每个像素利用3Bit进行插值,相当于在图2右图所示的8*8区域内取样(为了简化表示,图2只画了4*4点)。

使用一般纹理mipmap方法生成的法线贴图对于漫反射表面基本没问题,但是在镜面表面会导致严重的视觉问题。对于漫反射表面来说,光照的计算公式为l·n,l为光线方向的相反方向,n为法线,l·n1 + l·n2 + l·n3 + l·n4 = l·(n1 + n2 + n3 + n4) / 4,而mipmap则是事先计算(n1 + n2 + n3 + n4) / 4,所以对于漫反射表面,对法线贴图使用传统方式的mipmap基本没问题。为什么是基本没问题而不是完全没问题呢?因为这里存在一个近似,若l·n < 0,则光照值为0(光照不能为负),若将这个因素考虑进去,漫反射表面也会有问题,不过在实际当中这种情况表现不明显,所以可以认为基本没问题。

  对于镜面表面来说,当视线偏离反射光线方向的时候,光照强度会急剧下降,反映在公式中是因为其含有cosm(h·n)项(具体公式可以Google),而漫反射光照是线性变化,所以对于镜面表面,不能使用传统方法生成法线贴图的mipmap。法线贴图对于镜面反射的mipmap如图3所示,第一幅图中有4个像素,每个像素有法线和镜面反射波瓣(红色的是法线,周围一圈是镜面反射波瓣,镜面反射波瓣用于表示不同方向的反射强度)。图2中间部分,表示正确的mipmap情况,分别从4个像素合并为2个像素,从两个像素合并为1个像素。而现有的方法中,没有方法可以做到这样的mipmap,所以只能用其他方法进行近似。

图2的底部左图,是使用一般纹理的mipmap方法对法线进行平均,可以看到这种方法产生出的镜面反射波瓣和正确的镜面反射波瓣差距很大,其根本原因是使用线性方法对非线性的参数进行计算。图2底部图右图,每次在平均法线的同时,改变表面的光泽度(即改变镜面光公式中的m),虽然最终结果与正确的mipmap有一些差距,但是比一般纹理的mipmap的方法要好很多。

  所以,对法线贴图的mipmap方法之一,就是在使用一般纹理的mipmap方法对法线进行平均的同时,每张mipmap都必须附带一张光泽贴图(gloss map),记录每个像素点的光泽度(即m),m的计算原则就是让最后的镜面反射波瓣与正确的镜面反射波瓣最接近。当然,还有其他很多方法能得到不错的结果,具体可以参看《Real-Time Rendering 3rd》,或去搜索相关论文。

七、法线混合算法

在平时的工作中,我们经常需要在一张基础的法线贴图上融合一张细节纹理贴图,也即将两张法线贴图融合。这一节我们就来简单讲一讲有哪些常用的法线融合算法。

Linear Blending(线性混合)

简单的线性混合代码如下:

float3 n1 = tex2D(texBase,   uv).xyz*2 - 1;
float3 n2 = tex2D(texDetail, uv).xyz*2 - 1;
float3 r  = normalize(n1 + n2);
return r*0.5 + 0.5;

可以看出,我们只是简单地Unpack Normal,然后相加后归一化,再pack回去。这种做法类似于做平均化处理,由于两张纹理不尽相同,我们最后得到的结果实际上是对两张纹理"Flattening(平铺化)"的效果。如果其中一张是平面纹理的话(比如(0,0,1)),我们最后得到的结果其实就是另一张纹理图展平后的结果,这可能并不是我们想要的(我们想让另一张不起作用)。

Overlay Blending(叠加混合)

叠加混合代码如下:

float3 n1 = tex2D(texBase,   uv).xyz;
float3 n2 = tex2D(texDetail, uv).xyz;
float3 r  = n1 < 0.5 ? 2*n1*n2 : 1 - 2*(1 - n1)*(1 - n2);
r = normalize(r*2 - 1);
return r*0.5 + 0.5;

叠加混合算法其实就是PS中的叠加混合,这种算法看似合理,实际上仍然显示不正确,我们仍然是对贴图的通道做统一处理,并没有根据矢量的特性对通道进行分别处理。之所以会有人使用叠加混合,可能是因为这种混合方式相比PS其他混合显示效果更好一些吧。

Partial Derivative Blending(偏导混合)

偏导混合的代码如下:

float3 n1 = tex2D(texBase,   uv).xyz*2 - 1;
float3 n2 = tex2D(texDetail, uv).xyz*2 - 1;
float2 pd = n1.xy/n1.z + n2.xy/n2.z; // Add the PDs
float3 r  = normalize(float3(pd, 1));
return r*0.5 + 0.5;

为了代码的健壮性,第三四行代码应改成:

float3 r = normalize(float3(n1.xy*n2.z + n2.xy*n1.z, n1.z*n2.z));

偏导函数理论的细节这里不赘述,从图中我们可以看出,偏导混合的结果相比之前有了很大提升(原始贴图的细节被保留下来),但问题依然存在,仔细观察可以发现圆锥部分的细节贴图仍然被Flatten,但这种融合在处理不同材质间过渡时是非常不错的

处理材质过渡时可能用到的代码:

float2 pd = lerp(n1.xy/n1.z, n2.xy/n2.z, blend);
float3 r = normalize(float3(pd, 1));
WhiteOut Blending

代码如下:

float3 n1 = tex2D(texBase,   uv).xyz*2 - 1;
float3 n2 = tex2D(texDetail, uv).xyz*2 - 1;
float3 r  = normalize(float3(n1.xy + n2.xy, n1.z*n2.z));
return r*0.5 + 0.5;

这种混合方法第一次在SIGGRAPH 2007 上被提出,从代码中可以看出,这种方式类似于偏导混合,只是在xy通道上没有乘以Z分量。从混合结果来看,这种方法很好地解决了圆锥面细节贴图flatten的问题,但仍然存在flatten的问题。

UDN Blending

代码如下:

float3 n1 = tex2D(texBase,   uv).xyz*2 - 1;
float3 n2 = tex2D(texDetail, uv).xyz*2 - 1;
float3 r  = normalize(float3(n1.xy + n2.xy, n1.z));
return r*0.5 + 0.5;

这种更简单的混合方法在虚幻引擎开发者论坛上被提出,相比WhiteOut Blending,这里的变化只是在Z分量上取消乘以n2.z。从另一个角度看,这种混合方式只是在线性混合的基础上取消了z分量上的相加。对比WhiteOut Blending,这种混合方式在边界的混合效果会差一些,flatten的效果更明显,但由于这种混合方式更加节省着色器指令,在低端机的使用上会更频繁。

对于法线纹理混合,我们通常需要满足以下三点:
逻辑性:操作过程可以使用简单数学几何实现
特殊情况:当其中一个纹理是平面时,结果显示为另一纹理
避免Flattening:两张法线纹理的强度都得到保存
上面的几种方法对以上几点很难兼顾,下面的方法将通过旋转(或者说重定向)细节贴图的方法来使细节纹理匹配基础纹理。这个过程就像是对几何物体进行光照计算时对切线空间法线进行变换一样。
举个简单例子,我们有一个物体平面的法线为s,基础纹理的法线方向为 t,细节纹理的法线方向为u,我们可以通过计算s到t的变换矩阵或者说算子,然后将算子应用到u上,我们就得到了最终的结果r,如图:

Unity

代码如下:

float3 n1 = tex2D(texBase,   uv).xyz*2 - 1;
float3 n2 = tex2D(texDetail, uv).xyz*2 - 1;

float3x3 nBasis = float3x3(
     float3(n1.z, n1.y, -n1.x), // +90 degree rotation around y axis
     float3(n1.x, n1.z, -n1.y), // -90 degree rotation around x axis
     float3(n1.x, n1.y,  n1.z));

float3 r = normalize(n2.x*nBasis[0] + n2.y*nBasis[1] + n2.z*nBasis[2]);
return r*0.5 + 0.5;

Unity采用的方法是根据基础法线纹理的x,y轴进行旋转得到重定向后的矩阵,再应用该矩阵对细节法线贴图进行变换得到混合后的结果。但是,这种方法当且仅当n1为(0,0,±1)时表现正确,当n1偏离这个值时,结果会逐渐偏离正确的显示效果。如上图9显示。

我们可以看出,当n1与x轴重合时,这些点会塌缩成一个圈,因为这个时候,细节贴图的变换矩阵为:

Reoriented Normal Mapping(RNM Blending)

代码如下:

float3 t = tex2D(texBase,   uv).xyz*float3( 2,  2, 2) + float3(-1, -1,  0);
float3 u = tex2D(texDetail, uv).xyz*float3(-2, -2, 2) + float3( 1,  1, -1);
float3 r = t*dot(t, u)/t.z - u;
return r*0.5 + 0.5;

相比Unity的做法,这种方法也是使用一个基于n1变换的矩阵来对n2进行变换,只不过变换过程采用四元数代替,修正了图8中unity出现的错误。这种方法的另一个好处是,如果t是单位长度,u的长度是不变的,也就是说如果u也是单位长度,这种方法是不需要进行(normalize)标准化处理的(会节省不少着色器指令消耗)。但在实际操作中这种理论情况很难实现,很多因素诸如:量化、压缩纹理、mipmaping、滤波操作等都可能有所影响。你可能在漫反射效果中无法看出区别,但这仍然会切切实实地影响PBR理论遵循的能量守恒定律。保守起见,我们最好还是对结果进行归一化处理。

float3 r = normalize(t*dot(t, u) - u*t.z);
这种方法是默认法线z值是>=0的,但是这在运算过程中并不总是满足的,这种方法的潜在问题是如果法线在程序编写中已经进行了重定向,然后被压缩进一张双分量格式的法线贴图,虽然解压重建贴图的过程通常假设Z>=0。这种情况下最直接的解决方法就是对z值clamp一下,然后再归一化,这样之后再压缩进贴图。
UE4里的BlendAngleCorrectNormal节点,是RNMBlending。

八、UE4法线调整

1、调整法线强度

想控制一张法线贴图的呈现强度,不能直接对整个贴图的UV进行运算,需要对法线贴图的RG通道进行运算,并将每个通道的计算结果通过追加节点Append组成新的数值,改变强度参数,从而改变物体表现的强度。

1.各通道使用乘法与强度参数NormalIntensify相乘

2.使用追加节点,组合新的向量。并将值与Normal链接。

经过法线增强后:

2、法线贴图融合 BlendAngleCorrectedNormals

使用 BlendAngleCorrectedNormals 节点,完成两张法线贴图的叠加。

3、使用普通贴图制作法线 NormalFromHeightMap

这是个材质函数,可以查看节点组成。

需要将贴图转换为纹理对象

参考教程:https://blog.youkuaiyun.com/Jaihk662/article/details/107917594                      
参考教程:https://blog.youkuaiyun.com/ZJU_fish1996/article/details/83934059

参考教程:OpenGL基础46:切线空间-优快云博客

参考教程:Learn OpenGL, extensive tutorial resource for learning Modern OpenGL

参考教程:https://zhuanlan.zhihu.com/p/364821684

参考教程:https://www.cnblogs.com/wangchengfeng/p/3475489.html

参考教程:

UE4-材质法线强度调整、法线贴图混合、自定义材质函数、材质边缘过渡、植被动态效果_ue4法线强度调节节点-优快云博客

 

UE4材质进阶:别再傻傻调UV了,用BlendAngleCorrectedNormals和自定义函数搞定法线混合 本文深入探讨UE4材质系统中的BlendAngleCorrectedNormals节点与自定义材质函数的结合应用,解决法线贴图混合中的常见问题。通过角度校正算法和模块化设计,实现岩石、积雪、苔藓等材质的自然过渡,提升游戏场景的视觉品质。特别针对植被动态效果提供了优化方案,帮助开发者高效处理复杂材质混合需求。 阅读详情

相关推荐

UE4学习笔记:我的材质集合

以下材质都是我学习过程中制作的材质,或者使用中用到的,基本上都可以在官方文档找到制作教程 1、半透明材质 参考:https://docs.unrealengine.com/zh-CN/Engine/Rendering/Materials/HowTo/Transparency/index.html 将材质属性的Blend Mode设置为Translucent就可以制作半透明材质,但是这种半透明...

少得多惑的博客 5698

UE4-材质法线强度调整、法线贴图混合、自定义材质函数、材质边缘过渡、植被动态效果

一、法线强度 想控制一张法线贴图的呈现强度,不能直接对整个贴图的UV进行运算,需要对法线贴图的RG通道进行运算,并将每个通道的计算结果通过追加节点Append组成新的数值,改变强度参数,从而改变物体表现的强度。 1.各通道使用乘法与强度参数NormalIntensify相乘 2.使用追加节点,组合新的向量。并将值与Normal链接。 二、法线贴图融合BlendAngleCorrectedNormals 1.使用 BlendAngleCorrectedNormals 节点,完成两张法线贴图的叠.

Stone的博客 1万+

材质系统的隐秘法则:UE4法线处理中的矢量数学之美

本文深入解析了UE4材质系统中法线贴图的矢量数学原理与应用技巧,涵盖法线强度调整、高级混合技术及切线空间操作。特别探讨了如何通过自定义材质函数实现植被动态效果,为游戏开发者提供了优化材质表现的专业指导。

weixin_28077113的博客 641

UE4 材质笔记之岩石(法线初级应用)

文章目录前言一、实现效果二、蓝图1.主要贴图平铺2. 法线贴图的混合总结 前言 本笔记是基于《材质完全学习教程》一书中的讲解。此书适合UE4美术和初级程序学习,属于应用层讲解的书籍,也会涉及到部分图形学原理的讲解。 由于其中的讲解极其细致,这里的笔记尽量不复制粘贴,旨在积累材质素材的同时,将关键巧妙的节点运用进行记录。 本笔记不适合学习参考,仅适用于有一定基础进行照抄,需要学习请参考原书。 本次笔记实现的是岩石材质,参考书102到114页的内容。 一、实现效果 所要实现的效果是石块上叠加有另一法线效果。

xcinkey的博客 1490

UE4材质进阶:法线贴图强度控制的正确方法与常见误区解析

法线贴图是计算机图形学中用于模拟表面凹凸细节的核心技术,它通过存储每个像素点的法线向量方向信息,而非颜色信息,来欺骗光照计算,从而在低模表面呈现高精度细节。其原理基于切线空间,将模型表面的法线方向扰动编码到RGB通道中。正确的法线向量必须是单位向量,以确保光照计算(如点积)的物理正确性。在游戏开发与实时渲染领域,精准控制法线贴图的表现强度对于提升材质真实感和视觉保真度至关重要,直接影响到角色皮肤、金属表面、布料织物等各类材质的最终质感。常见的错误实践,如直接缩放UV或对采样结果进行标量乘法,会破坏向量的归一

weixin_33713707的博客 1325

UE5——材质学习笔记(1)

前言:本系列笔记记录UE上各种常见材质的制作方法; 1、失真(水流扰动)材质 说明 可用于湖泊河流等水流扰动展示(仅限顶部视角) 分析 通过时间节点与二维变量的乘积控制TexCoord节点中的UV实现材质的滚动;使用噪音纹理的RG双通道实现对UV坐标的随机扰动, 对纹理的双通道进行取值可获得二维数组/坐标轴,可用于对纹理原UV值进行扰动取样; texCoord节点: 任何对纹理贴图的改动都需要texCoord节点和add节点; 在材质节点中,TextureCoordinate缩写为TexCoord。 Te

小谁的博客 8267

(192)纹理处理

纹理处理函数用于对基于纹理的操作进行特殊处理,例如调整纹理的 UV 以及裁切纹理等等。 纹理处理函数 以下是“纹理处理”类别下所有函数的列表。 CylindricalUVs(圆柱形 UV) 此函数使用以对象中心居中的圆柱形投射 UV 来围绕对象平铺纹理。 项目 说明 输入 纹理对象(

革命队伍的螺丝钉 2264

Shader Graph9-世界空间、物体空间、相机空间、切线空间

茶壶这个物体空间的原点是在茶壶底部,红色箭头表示x轴,绿色箭头表示y轴,蓝色箭头表示z轴。当我们移动旋转茶壶时,该茶壶空间相对于世界空间的位置和方向都会发生变化,但是相对壶盖来说,它并没有位置和角度的变换,因为它是相对于茶壶底部的原来来说的,有点像我们在地球上,地球是在公转和自转,但我们并没有感觉到一样。在下用的Blender软件,新建了一个平面,中间的黄色小圆点表示的世界空间的原点,在世界空间的物体的位置,都是相对于这个原点来说的,红色箭头表示x轴,绿色箭头表示y轴,蓝色箭头表示z轴。

zhuziying99的专栏 1608

UE4_材质_材质节点_Fresnel

菲涅尔(Fresnel)这一术语用于说明你看到的光线如何根据视角的变化以不同的强度反射。例如,你站在水池边,低头看脚下的水,你会发现水面的反射不是特别强烈。随着你抬起头,使你的视线与水池中的水面平行,你会开始发现水面越来越波光粼粼。水和玻璃都表现出很强的菲涅尔倾向,即视线垂直于表面时,它们看起来相对透明,视线未垂直于表面时,它们会反射更多光线。从正面看时,相框中的玻璃是透明的,从侧面看时,玻璃中的反光会更明显。在虚幻引擎中,菲涅尔(Fresnel) 材质表达式会根据表面法线与摄像机方向的点积来计算衰减。

Growthofnotes的博客 3791

UE4材质进阶:告别调UV误区,精准控制法线贴图强度

在实时渲染与游戏开发中,法线贴图是提升模型表面细节、模拟复杂凹凸效果的核心技术之一。其原理是通过RGB通道编码表面法线方向信息,在不增加模型几何复杂度的前提下,利用光照计算“欺骗”视觉,实现丰富的质感表现。这项技术的核心价值在于以极低的性能开销,大幅提升场景和角色的视觉真实感与细节密度,广泛应用于角色皮肤、场景物件、武器纹理等需要高细节表现的领域。理解其工作原理后,开发者便能超越基础的贴图应用,进入精准控制的阶段。本文聚焦于一个常见误区与解决方案:许多开发者习惯通过调整UV来改变法线凹凸的明显程度,但这实际

weixin_30376509的博客 314

UE4官方文档学习笔记材质篇——分层材质

一、创建铬合金材质函数 底色(Base Color)- 此部分的网络非常简单。我们已设置线性插值,该插值在铬合金底色与非常深的灰色之间进行混合。底色实际上是名为Tint的函数输入。这个输入设置为 Vector3,从而允许我们将颜色输入到函数中,并更改铬合金颜色。我们使用T_ExampleLayers_Metal_1_BC纹理的红色通道在这两者之间驱动插值。 金...

L人青的博客 1873

UE4Material_分层材质

分层材质 1.在 内容浏览器 中,单击 新增(Add New)按钮并选择 材质与纹理(Materials & Textures)>材质函数(Material Function)。 2.将新函数命名为 Layer_Chrome并打开。 3.右键单击 以打开快捷菜单,搜索 Make 并选择 **建立材质属性(Make Material Attributes)**并将节点连接到 输出结果(...

qq_42716155的博客 4652

解决Substance Painter到UE4的PBR材质白边黑边问题

在基于物理的渲染(PBR)工作流中,材质数据在不同软件间的无损传递是保证视觉质量的关键。其核心原理在于确保法线贴图编码、粗糙度等物理数据的线性空间处理与目标引擎的预期完全一致。金属度/粗糙度工作流作为实时渲染的主流,要求贴图数据(如法线、粗糙度、金属度)的存储与解释必须精准匹配,否则就会在模型边缘产生白边或黑边等渲染伪影,破坏视觉一体感。这类问题常见于Substance Painter(SP)与Unreal Engine(UE)的协作流程中,是技术美术和3D艺术家需要攻克的核心难题。通过标准化SP的导出设置

weixin_30381317的博客 738

虚幻引擎法线贴图旋转问题与解决方案

法线贴图是计算机图形学中用于模拟表面细节的关键技术,其RGB通道分别对应三维法向量的XYZ分量。在游戏开发中,正确处理法线贴图对光照计算至关重要。当需要调整UV方向时,直接旋转会破坏向量数据,导致光照异常。通过构建旋转矩阵或使用引擎内置函数,可以保持向量空间关系。在虚幻引擎材质编辑中,采用3x3旋转矩阵方案性能最优(仅0.023ms),适用于动态旋转和移动端优化。典型应用包括程序化旋转控制和多图层混合,能提升62%的渲染精度,是PBR工作流中不可或缺的技术环节。

weixin_29015801的博客 247

Unity仿UE4湖水材质教程与实战

为了实现自定义效果,你需要了解以下技巧:节点重组:通过混合不同节点来实现特定的视觉效果。参数化:使用Float、Vector和Color节点来创建可调节的参数,增强着色器的灵活性。代码块的嵌入:Shader Forge支持使用HLSL代码块,可以嵌入自定义的高级着色器代码,实现一些图形算法。

weixin_29301059的博客 796

QUIC 协议域名封堵:核心原理、关键技术与实现路径(C/C++代码实现)

随着 QUIC 协议在互联网领域的广泛应用,其基于 UDP 的传输特性与加密设计,打破了传统 TCP 协议下的域名封堵逻辑,给网络合规管理与安全防护带来新的技术难题。本文将脱离具体代码实现,聚焦 QUIC 协议域名封堵的核心原理、关键技术环节与实际落地路径,从协议特性本质出发,解析如何在遵循 RFC 9000、RFC 9001 等规范的前提下,实现对 QUIC 流量的精准域名封堵。

chen1415886044的博客 1467

学习在UE中使用RVT(RuntimeVirtualTexture)将物体与地形混合过渡

前言 基本原理。之前是用RenderTarget,在这里有讨论,附录尝试翻译。 本篇主要参考How to Blend Objects with Your Landscape - UE4 Runtime Virtual Texturing (RVT) Tutorial - YouTube,但使用了更简单的资源做测试。 测试场景准备 我在创建工程时使用了“初学者内容包”。 随意创建一个地形并添加了些随意的噪声。创建一个地形材质时我使用了 T_Ground_Gravel_D 和 T_Ground_Gravel_N

主要记录了工作之余胡乱学习的知识,大部分是入门级别的内容。 主要是为了自己未来有用到时能快速上手,相当于是个备忘录。 当然,也很开心其他人可以从中找到对自己有用的信息。^_^ 1万+

艾德克斯电子负载IT8510维修

2年前从朋友那收了这台艾德克斯电子负载,收来的时候上面的编码器就不好用,就是旋转的时候一会增加一会减小这种现象,不过其他功能都是正常的,自己也就将就用这。直到昨天,电子负载开机发现空载的时候电压不是0,开始有mV级的跳动,心想这个不正常。又测试了一下恒流功能,已经不能正常工作了。

mainbanp 4655

虚幻引擎法线贴图旋转原理与实现方案

法线贴图是3D渲染中增强表面细节的关键技术,通过RGB通道编码切线空间法线方向。其核心原理是利用纹理采样改变表面法线,配合光照计算产生凹凸视觉效果。在虚幻引擎等现代游戏引擎中,正确处理法线贴图旋转需要理解切线空间变换与UV坐标操作的差异。常见工程实践包括材质编辑器UV旋转、世界空间对齐方案以及运行时动态旋转优化,这些方法广泛应用于角色材质、环境贴图和动态交互元素。针对移动平台还需考虑法线压缩格式和计算负载优化,而PC/主机平台则可实现多图层混合和视差贴图等高级效果。掌握这些技术能显著提升材质真实性和渲染效率

weixin_29013129的博客 91

Ubuntu24.04/20.04设置网络共享文件夹

Ubuntu20.04利用向日葵远程控制时,不能传输文件。使用linux版本QQ来传输是可以的,不过linuxqq功能真的很弱。因此,打算在Ubuntu系统中建立一个共享文件夹,可在局域网中访问。 1、新建共享文件夹 获取root权限,或者登陆root账户。可在/home文件夹(或其它文件夹)下新建一个文件夹,如share。 右击文件夹,选择“本地网络共享”菜单。按下图设置。 点击确定。如果系统已经安装了samba服务器,就可以进入第3步。如果没有,会提示安装,按提示安装,可能会出错,可进.

willhu2008的专栏 2万+

2023电视专用!安卓电子相册APP避坑指南(附开源代码)

本文针对2023年智能电视用户,提供安卓电子相册APP的避坑指南与实战教程。文章详细解析了电视端相册应用的常见广告与兼容性陷阱,并指导用户如何安全获取、部署纯净的APK应用,通过核心设置实现无广告的个性化图片轮播体验,最终打造专属的家庭回忆墙。

weixin_29012677的博客 496

UE4角色模型接缝问题深度解析:从切线空间原理到实战修复方案

在实时渲染和游戏开发中,法线贴图是提升模型表面细节的关键技术,其效果依赖于切线空间的正确计算。切线空间定义了每个顶点局部的坐标系,用于将法线贴图中的向量偏移转换到模型表面。当模型在UV展开时产生接缝,同一3D位置在UV空间中被复制为多个顶点,若引擎重算切线算法(如UE4的MikkTSpace)为这些顶点计算出不一致的切向基,就会导致切线空间不连续,从而在渲染时产生视觉断层,即“接缝”问题。这不仅影响视觉保真度,也可能干扰光照一致性。理解此原理对于从事角色美术、技术美术或引擎开发的开发者至关重要,能帮助其从资

weixin_30920597的博客 403
上一篇: UE4_材质_材质节点_DepthFade
下一篇: UE4_地形_悬崖拉伸的解决
Growthofnotes
博客等级 码龄5年 991粉丝 143原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Growthofnotes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值