首页 > 其他分享 >UE5 substrate flake normal map 亚克力

UE5 substrate flake normal map 亚克力

时间:2023-10-05 22:33:47浏览次数:56  
标签:1.5 map substrate normal 0.0 0.5 亚克力 randomNormal float3

前言

本篇将运用UE5的substrate系统制作一个亚克力圆盘

效果如下
image-20231005222231093

Flake Normal Map

  • 上图中圆盘内的彩色小点是通过噪声函数flake(个人翻译为薄片) normal map生成的,该函数基于[Cellular Noise]https://www.cnblogs.com/chenglixue/p/17742395.html

  • 用途:汽车喷漆,及各种细小的闪光点材质

  • 参数

    • Flake Scale:缩放薄片大小
      image-20231005183450854
    • FlakeSize:薄片尺寸大小
      image-20231005202917200
    • Flake Size Variance:薄片尺寸的随机性——0所有薄片尺寸都相同
    • Flake Normal Orientation:blend 物体表面法线 和 随机薄片的法线
      image-20231005203908518
  • 实现

    float3 hash3(float3 p) 
    {
        p = float3(dot(p, float3(127.1, 311.7, 74.7)),
    			  dot(p, float3(269.5, 183.3, 246.1)),
    			  dot(p, float3(113.5, 271.9, 124.6)));
    
        return frac(sin(p) * 43758.5453123);
    }
    
    float4 flakesNormalMap(float2 fragCoord, float3 view, float flakeScale, float flakeSize, float flakeSizeVariance, float flakeNormalOrientation)
    {
        float safeFlakeSizeVariance = clamp(flakeSizeVariance, 0.1, 1.0);
        
        // 用于求得九个特征点
        const float3 cellCenters[9] = {
    		float3( 0.5,  0.5,  0.0),
    		float3( 1.5,  0.5,  0.0),
    		float3( 1.5,  1.5,  0.0),
    		float3( 0.5,  1.5,  0.0),
    		float3(-0.5,  1.5,  0.0),
    		float3(-0.5,  0.5,  0.0),
    		float3(-0.5, -0.5,  0.0),
    		float3( 0.5, -0.5,  0.0),
    		float3( 1.5, -0.5,  0.0)
    	};
    
        // 目标像素点
        float3 position = float3(fragCoord.x, fragCoord.y, 0.f);
        position = flakeScale * position;
    
        float3 base = floor(position);
    
        float3 nearestCell = float3(0.f, 0.f, 1.f);
    
        int nearestCellIndex = -1;
    
        // 计算目标点到九个特征点的距离
        for(int cellIndex = 0; cellIndex < 9; ++cellIndex)
        {
            float3 cellCenter = base + cellCenters[cellIndex];
    
            float3 centerOffset = hash3(cellCenter) * 2.f - 1.f;
            centerOffset[2] *= safeFlakeSizeVariance;
            centerOffset = normalize(centerOffset);
    
            cellCenter += 0.5 * centerOffset;
    
            float cellDistance = distance(position, cellCenter);
            //是否是最小距离
            if(cellDistance < flakeSize && cellCenter[2] < nearestCell[2])
            {
                nearestCell = cellCenter;
                nearestCellIndex = cellIndex;
            }
        }
    
        float4 result = float4(0.f, 0.f, 1.f, 0.f);
        if(nearestCellIndex != -1)
        {
            float3 randomNormal = hash3(base + cellCenters[nearestCellIndex] + float3(0.f, 0.f, 1.5f));
            randomNormal = 2.f * randomNormal - 1.f;
            randomNormal = faceforward(randomNormal, view, randomNormal);
            randomNormal = normalize(lerp(randomNormal, float3(0.f, 0.f, 1.f), flakeNormalOrientation));
    
            result.xyz = float3(randomNormal.x, randomNormal.y, randomNormal.z);
            result.w = 1.f;
        }   
    
        return result;
    }
    

    在UE中如下,”GlobalFun”custom node写有如上代码,而”Flakes Normal Map”custom node用于运行flakesNormalMap()函数
    image-20231005212607998

实现

前置设置

  • 由于亚克力是中透明材质,因此需要将”Blend Model”设为”TranslucentColoredTransmittance”
  • “Lighting Mode”设为”Surface ForwardShading”。测试了一下,改模式下材质的闪亮效果最佳,当然也是最耗性能的,而Surface TranslucencyVolume的效果非常差
  • “Refraction Method”设为”Index Of Refraction”
  • 根节点处的”IOR”赋值”1.22”
    image-20231005220940611

确定UV

  • 考虑到需要将得到的flake运用到3维物体上,需要确定uv坐标来自哪两个轴。如果这里仅仅简单地使用物体的世界坐标会得到如下的错误结果
    image-20231005213046353

    为了根据对应的面求得正确的flake结果,需要根据vertex normal的值来确定正确的面。大致思路如下
    image-20231005213224715

  • 不难得到如下效果
    image-20231005213431102

制作薄片

  • 目前只是求得法线信息,还需为这些薄片赋予normal、F0、F90、roughness、MFP
  • Normal制作如下
    image-20231005213835555
  • F0 F90 Roughness制作如下
    image-20231005215442304
  • SSS MFP
    image-20231005215531043
  • 效果如下
    image-20231005215555730

刻上图案

  • 为了在物体表面刻上图案,需要在水平层面上进行blend
  • 实现
    • 图案层
      image-20231005220055867
    • 水平blend
      image-20231005220107514
    • 效果如下
      image-20231005220130538

制作亚克力

  • 用了将亚克力涂于表面,需要在垂直层面进行blend
  • 实现
    • 亚克力
      image-20231005220331719
    • 垂直层面的blend
      image-20231005220440859
    • 效果
      image-20231005221115546

折射效果

  • 亚克力材质是带有较弱的折射效果的,这里使用POM实现。不使用IOR,是因为IOR只会改变材质后面物体的折射效果

  • 实现

    • POM
      image-20231005221249684
      上图中的“POM UV”为”路由节点”(不懂得可以看这篇)

    • 在normal map 和 blend处加上POM UV
      image-20231005221425645

      image-20231005221500826

    • 效果
      添加POM前
      image-20231005221805992

      添加POM后
      image-20231005221832492

后续

reference

https://docs.chaos.com/display/OSLShaders/Flakes+normal+map

https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_noise.glsl

https://help.autodesk.com/view/ARNOL/ENU/?guid=arnold_user_guide_ac_texture_shaders_ac_texture_flakes_html
https://zhuanlan.zhihu.com/p/658057646

UE5 内容实例

标签:1.5,map,substrate,normal,0.0,0.5,亚克力,randomNormal,float3
From: https://www.cnblogs.com/chenglixue/p/17744045.html

相关文章

  • UE5 blend normal map的四种方式
    前言很多情况下玩家靠近物体想看看物体的细节纹理,如果仅仅使用basenormalmaps不会给予玩家好的观感,此时就需要用到detailnormalmaps。也就是说,当玩家靠近物体的,物体的法线将更偏向于detailnormalmaps,更准确地说是detailnormalmaps和normalmap的blend。本篇将介绍blend......
  • HashMap 的实现原理
    (1)简介HashMap基于map接口,元素以键值对方式存储,允许有null值,HashMap是线程不安全的。(2)基本属性初始化大小,默认16,2倍扩容;负载因子0.75;初始化的默认数组;sizethreshold。判断是否需要调整hashmap容量(3)HashMap的存储结构JDK1.7中采用数组+链表的存储形式。HashMap采取Entry数组来......
  • JUC工具类CountDownLatch、CyclicBarrier、Semaphore介绍
    CountDownLatch:它是一种同步工具,用于控制一个或多个线程等待其他线程完成操作后再继续执行。它的作用是让某个线程等待一组操作执行完成,再继续执行自己的任务。CountDownLatch内部有一个计数器,当计数器的值为0时,等待的线程将会被唤醒。通过CountDownLatch的构造函数可以指定计......
  • MapReduce之学习规约
    1、概念2、代码实现自定义一个类:在JobMain(与之前的基本一样)里面:......
  • MapReduce的排列和序列化的学习
    1、概念和原理--结构化对象转换为字节流2、编程流程(举例说明)1、读取文件为键值对<偏移量,文件内容>2、Map阶段3、排序4、Reduce阶段5、保存结果--使用TextOutputFormat类3、代码编写1、自定义类型和比较器--自定义命名为SortBean并实现接口WritableComparable,还需......
  • MapReduce分区的学习
    1、概念和原理同一个分区的数据会发送给同一个reduce;可以简单解释为————标记一样,放到一个reduce里面:2、代码编写步骤(以中奖编号是否>15进行分区)1、定义Mapper可以自定义名称为PartitionMapper,并继承Mapper类:并重写map方法:2、自定义partitioner可以自定义名称为MyPa......
  • MapReduce运行模式
    1、yarn集群运行先将之前写好的MapReduce程序进行打包--Maven-->package;打包完成之后的jar包在target目录下可以找到!!!之后将jar包上传到我们的虚拟机文件夹里面去;之后输入命令:hadoopjarjar包名称jar包主类的全路径名称回车之后开始运行;在hdfs的浏览器界面(9870)能够找到......
  • HashMap
    ......
  • MapReduce学习二之WordCount案例
    一、案例概述1、第一步--变成偏移量的K1,V1(这一步不需要我们自己写)2、进入Map阶段输出新的<K2,V2>的键值对;3、Shuffle阶段分区、排序、规约、分组输出新的键值对:4、Reduce阶段转换为<K3,V3>的新的形式的键值对;利用TextOutputFormat的类实现结果的输出;二、具体实践1......
  • VC++ MFC 编程--CMap的使用
    本文翻译自: CMapHow-to-CodeProject介绍像我这样的程序员,在CMap之前学习了STL::map,总是认为CMap很难使用,并且总是尝试以STL::map的方式使用CMap。在本文中,我将解释CMap,以及如何将它用于您自己的自定义类。在本文的最后,我将展示一个如何正确使用CMap与CString*的例子(注意,我......