Unity URP 仿原神角色渲染过程记录

想学一下NPR渲染,话不多说,先搞一只芙再说,边做边学

一、资源整理

终于是把东西全都集齐了

1、纹理设置 

首先要把将Diffuse和Lightmap的压缩改成"无"或"高质量"。

法线贴图的纹理类型改成"法线贴图"。

除颜色图外其它贴图全部取消勾选sRGB。

如果最终的渲染结果,出现贴图不清晰,有锯齿,有杂色,颜色深浅不对等问题,那大概率是贴图设置有问题,建议先重新认真检查一遍贴图设置。 

2、纹理分析

body和hair的diffuse贴图的a通道存放了自发光的遮罩

face的a通道则存放了腮红的遮罩

hair和body的lightmap的4个通道分别存放了高光范围,AO,高光强度,ramp分层

Body

lightmap.r:高光范围
lightmap.g:AO
lightmap.b:高光强度
lightmap.a:ramp分层

Hair

lightmap.r:高光范围
lightmap.g:AO
lightmap.b:高光强度
lightmap.a:ramp分层

 两张ShadowRamp分别控制白天和晚上的阴影颜色

NoramlMap是正常的法线贴图

MetalMap控制金属高光

FaceLightMap是一张SDF面部阴影图。

ShadowMap控制了阴影区域的遮罩。

ShadowMap.r/g
ShadowMap.a

二、渲染设置

原神的角色实际上应该是渲染了三遍,第一遍用第一套UV渲染正面,第二遍用第二套UV渲染背面,第三遍渲染描边,这样可以做到单面片正反两面的贴图不一样,崩铁应该也是使用了这套技术。

RendererFeatures

URP使用多pass需要使用RendererFeatures,先设置一下RendererFeatures。在项目大纲找到UniversalRenderer,默认路径在Assets/Settings/UniversalRenderer。

然后在检查器找到RendererFeatures,点击Add RendererFeature添加一个RenderObjects,然后在LightModeTags添加三个元素,三个元素分别为“渲染正面pass、渲染背面pass和渲染描边pass”。

元素0代表正面pass,元素1代表背面pass,元素2代表描边pass

然后在LayerMask(图层蒙版)把角色对应的图层勾上,默认在Default层,勾上Everything会所有图层都显示。

LayerMask勾上Everything

三、Shader分析

1.Shader准备

正式开始前先把计算需要用到的变量和向量等数据准备好,先来准备面板参数,面板参数如下:

Properties

        [Space(20.0)][Toggle]_genshinShader("是否脸部", float) = 0.0

[Space(20.0)]
//Unity的自定义属性(Attribute),用于在Unity的Inspector面板中为后续的属性或字段添加垂直空间
//这里的20.0表示这个空间的高度为20个像素。这有助于组织Inspector面板中的属性,使其更易于阅读和管理

[Toggle]_genshinShader("是否脸部", float) = 0.0
//定义了一个名为_genshinShader的变量,但其实际类型被指定为float
//由于[Toggle]属性的存在,这个float变量实际上在Inspector面板中会被呈现为一个切换开关(Toggle)。

        [Space(20.0)][NoScaleOffset]_diffuse("Diffuse", 2d) = "white"{}_fresnel("边缘光范围", Range(0.0, 10.0)) = 1.7_edgeLight("边缘光强度", Range(0.0, 10.0)) = 0.02

[NoScaleOffset]
//[NoScaleOffset]: 这是一个自定义属性,通常在Shader中用于告诉Unity不要对纹理应用缩放或偏移(Scale或Offset)的默认参数。这通常用于那些不需要或不应该有额外变换的纹理。

_diffuse("Diffuse", 2D) = "white"{}
//_diffuse: 用于存储Diffuse纹理的引用。

_fresnel("边缘光范围", Range(0.0, 10.0)) = 1.7
//_fresnel: 用于存储与Fresnel效应(菲涅尔反射)相关的参数,通常用于控制边缘光的范围。

_edgeLight("边缘光强度", Range(0.0, 10.0)) = 0.02
//_edgeLight: 用于存储与边缘光强度相关的参数。

        [Space(8.0)]_diffuseA( "Alpha(1透明, 2自发光)" , Range(0.0, 2.0)) = 0_Cutoff( "透明阈值" , Range(0.0, 1.0)) = 1.0[HDR]_glow( "自发光强度" , color) = (1.0, 1.0, 1.0, 1.0)_flicker( "发光闪烁速度" , float) = 0.8

_diffuseA( "Alpha(1透明, 2自发光)" , Range(0.0, 2.0)) = 0
//用于控制材质的透明度(当值为1时)或自发光强度(当值为2时)。

_Cutoff( "透明阈值" , Range(0.0, 1.0)) = 1.0
//用于确定哪些像素是完全不透明的(高于阈值)和哪些像素是透明的(低于阈值)。

[HDR]_glow( "自发光强度" , color) = (1.0, 1.0, 1.0, 1.0)
//[HDR] 是一个Unity的自定义属性,通常用于指示该属性支持高动态范围(HDR)颜色。这意味着该属性的颜色值可以超过常规的0到1范围。
//用于控制自发光的效果强度。

_flicker( "发光闪烁速度" , float) = 0.8
//用于控制某种发光效果的闪烁速度。

        [NoScaleOffset]_lightmap( "Lightmap/FaceLightmap" , 2d) = "white"{}_bright( "亮面范围" , float) = 0.99_grey( "灰面范围" , float) = 1.14_dark( "暗面范围" , float) = 0.5

_lightmap( "Lightmap/FaceLightmap" , 2d) = "white"{}
//用于全局光照或面部光照。

_bright( "亮面范围" , float) = 0.99
//用于控制材质中亮面部分的范围或强度。

_grey( "灰面范围" , float) = 1.14
//用于控制材质中灰色或中间亮度部分的范围或强度。

_dark( "暗面范围" , float) = 0.5
//用于控制材质中暗面部分的范围或强度。

        [NoScaleOffset]_bumpMap( "Normalmap" , 2d) = "bump"{}_bumpScale( "法线强度" , float) = 1.0

_bumpMap( "Normalmap" , 2d) = "bump"{}
//用于存储法线贴图(normal map)数据。

_bumpScale( "法线强度" , float) = 1.0
//整法线贴图产生的凹凸效果的强弱。

        [NoScaleOffset]_ramp( "Shadow_Ramp" , 2d) = "white"{}[Toggle]_dayAndNight("是否是白天" , float) = 0.0

_ramp( "Shadow_Ramp" , 2d) = "white"{}
//在Inspector中显示的属性标签。

[Toggle]_dayAndNight("是否是白天" , float) = 0.0
//显示为一个切换按钮

        _lightmapA0("1.0_Ramp条数" , Range(1, 5)) = 1_lightmapA1("0.7_Ramp条数" , Range(1, 5)) = 4_lightmapA2("0.5_Ramp条数" , Range(1, 5)) = 3_lightmapA3("0.3_Ramp条数" , Range(1, 5)) = 5_lightmapA4("0.0_Ramp条数" , Range(1, 5)) = 2

_lightmapA0 到 _lightmapA4
//用于控制不同光照强度下的Ramp条数。Ramp通常用于创建渐变或层次效果。

        [NoScaleOffset]_metalMap( "MetalMap" , 2d) = "white"{}_gloss( "高光范围" , Range(1, 256.0)) = 1_glossStrength( "高光强度" , Range(0.0, 1.0)) = 1_metalMapColor( "金属反射颜色" , color) = (1.0, 1.0, 1.0, 1.0)

_metalMap( "MetalMap" , 2d) = "white"{}
//与_ramp类似,但这个是用于金属的贴图

_gloss 到 _metalMapColor

//_gloss: 高光范围。

//_glossStrength: 高光强度。

//_metalMapColor: 金属反射的基础颜色。

        _outline( "描边粗细" , Range(0.0, 1.0)) = 0.4_outlineColor0( "描边颜色1" , color) = (1.0, 0.0, 0.0, 0.0)_outlineColor1( "描边颜色2" , color) = (0.0, 1.0, 0.0, 0.0)_outlineColor2( "描边颜色3" , color) = (0.0, 0.0, 1.0, 0.0)_outlineColor3( "描边颜色4" , color) = (1.0, 1.0, 0.0, 0.0)_outlineColor4( "描边颜色5" , color) = (0.5, 0.0, 1.0, 0.0)

_outline 到 _outlineColor5

//_outline: 描边的粗细。

//_outlineColor0 到 _outlineColor5: 不同的描边颜色。

2.URP框架简单总结

(一)、Bulit-in管线到URP管线的部分改变

本次渲染复刻使用的是Unity的URP管线,与Bulit-in管线存在部分的改变:

1.在URP管线中,我们将原来的CG代码改为HLSL代码

原来为 CGPROGRAM
现在为 HLSLPROGRAM;原来为 ENDCG
现在为 ENDHLSL;

2.一些unity封装的函数名称,以及定义的宏发生了改变,例如:

原来为 UnityObjectToClipPos
现在为 TransformObjectToHClip;原来为 UNITY_DECLARE_TEX2D(name)
现在为 TEXTURE2D(textureName); SAMPLER(samplerName);;

3.引用的头文件发生了改变,例如:

导入库
原来为 #include "UnityCG.cginc"
现在为 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//默认库
原来为 #include "AutoLight.cginc"
现在为 #include "Packages/com.unity.render-pipuniversal/ShaderLibrary/Lighting.hlsl"//光照库

 一个简单总结了Bulit-in到URP变化的blog :From Built-in to URP (teodutra.com)

            //导入库#include "Packages/com.unity.renderpipelines.universal/ShaderLibrary/Core.hlsl"  //默认库#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"  //光照库CBUFFER_START(UnityPerMaterial)  //常量缓冲区开头

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 和 

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

  • 这两行代码是预处理器指令,用于包含(或“导入”)其他HLSL文件。
  • Core.hlsl 通常是URP的核心库,它包含了URP Shader中常用的基础函数和宏定义。
  • Lighting.hlsl 是URP的光照库,它提供了与光照相关的函数和宏定义。
  • 这两个库文件是URP Shader开发的基础,提供了许多便利的函数和工具。

CBUFFER_START(UnityPerMaterial)

  • CBUFFER_START 是一个宏定义,通常用于声明常量缓冲区(Constant Buffer)的开始。
  • 在URP和其他Unity渲染管道中,常量缓冲区是一种高效的方式,用于将大量数据(如材质属性)从CPU传递到GPU。
  • UnityPerMaterial 是这个常量缓冲区的名称。这表示这个常量缓冲区中的数据是每个材质特有的,而不是每个实例或每个顶点特有的。
  • 通常,在这个宏之后,你会看到一系列的变量声明,这些变量将存储在UnityPerMaterial常量缓冲区中。
  • 当你完成常量缓冲区的变量声明后,你会使用CBUFFER_END宏来结束这个常量缓冲区的定义。

 (二)、整体框架

Shader "Furina"
{Properties{[Space(20.0)]                                      [Toggle]_genshinShader("是否脸部", float) = 0.0[Space(20.0)][NoScaleOffset]_diffuse("Diffuse", 2d) = "white"{}_fresnel("边缘光范围", Range(0.0, 10.0)) = 1.7_edgeLight("边缘光强度", Range(0.0, 10.0)) = 0.02[Space(8.0)]_diffuseA( "Alpha(1透明, 2自发光)" , Range(0.0, 2.0)) = 0_Cutoff( "透明阈值" , Range(0.0, 1.0)) = 1.0[HDR]_glow( "自发光强度" , color) = (1.0, 1.0, 1.0, 1.0)_flicker( "发光闪烁速度" , float) = 0.8[Space(30.0)][NoScaleOffset]_lightmap( "Lightmap/FaceLightmap" , 2d) = "white"{}_bright( "亮面范围" , float) = 0.99_grey( "灰面范围" , float) = 1.14_dark( "暗面范围" , float) = 0.5[Space(30.0)][NoScaleOffset]_bumpMap( "Normalmap" , 2d) = "bump"{}_bumpScale( "法线强度" , float) = 1.0[Space(30.0)][NoScaleOffset]_ramp( "Shadow_Ramp" , 2d) = "white"{}[Toggle]_dayAndNight("是否是白天" , float) = 0.0[Space(8.0)]_lightmapA0("1.0_Ramp条数" , Range(1, 5)) = 1_lightmapA1("0.7_Ramp条数" , Range(1, 5)) = 4_lightmapA2("0.5_Ramp条数" , Range(1, 5)) = 3_lightmapA3("0.3_Ramp条数" , Range(1, 5)) = 5_lightmapA4("0.0_Ramp条数" , Range(1, 5)) = 2[Space(30.0)][NoScaleOffset]_metalMap( "MetalMap" , 2d) = "white"{}_gloss( "高光范围" , Range(1, 256.0)) = 1_glossStrength( "高光强度" , Range(0.0, 1.0)) = 1_metalMapColor( "金属反射颜色" , color) = (1.0, 1.0, 1.0, 1.0)[Space(30.0)]_outline( "描边粗细" , Range(0.0, 1.0)) = 0.4_outlineColor0( "描边颜色1" , color) = (1.0, 0.0, 0.0, 0.0)_outlineColor1( "描边颜色2" , color) = (0.0, 1.0, 0.0, 0.0)_outlineColor2( "描边颜色3" , color) = (0.0, 0.0, 1.0, 0.0)_outlineColor3( "描边颜色4" , color) = (1.0, 1.0, 0.0, 0.0)_outlineColor4( "描边颜色5" , color) = (0.5, 0.0, 1.0, 0.0)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{HLSLPROGRAM#pragma vertex vert#pragma fragment frag//导入库#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"  //默认库#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"  //光照库CBUFFER_START(UnityPerMaterial)  //常量缓冲区开头//声明面板参数float _genshinShader;  //是否是脸部//diffusefloat _fresnel;  //边缘光范围float _edgeLight;  //边缘光强度float _diffuseA;  //diffuseAfloat _Cutoff;  //透明阈值float4 _glow;  //自发光强度float _flicker;  //发光闪烁速度//lightmap/FaceLightmapfloat _bright;  //亮面范围float _grey;  //灰面范围float _dark;  //暗面范围//normalfloat _bumpScale;  //法线强度//rampfloat _dayAndNight;  //是否是白天float _lightmapA0;  //1.0_Ramp条数float _lightmapA1;  //0.7_Ramp条数float _lightmapA2;  //0.5_Ramp条数float _lightmapA3;  //0.3_Ramp条数float _lightmapA4;  //0.0_Ramp条数//高光float _gloss;  //高光范围float _glossStrength;  //高光强度float3 _metalMapColor;  //金属折射颜色//描边float _outline;  //描边粗细float3 _outlineColor0;  //描边颜色1float3 _outlineColor1;  //描边颜色2float3 _outlineColor2;  //描边颜色3float3 _outlineColor3;  //描边颜色4float3 _outlineColor4;  //描边颜色5CBUFFER_END  //常量缓冲区结尾//声明贴图TEXTURE2D(_diffuse);  //DiffuseSAMPLER(sampler_diffuse);TEXTURE2D(_lightmap);  //Lightmap/FaceLightmapSAMPLER(sampler_lightmap);TEXTURE2D(_bumpMap);  //NormalSAMPLER(sampler_bumpMap);TEXTURE2D(_ramp);  //Shadow_RampSAMPLER(sampler_ramp);TEXTURE2D(_metalMap);  //MetalMapSAMPLER(sampler_metalMap);ENDHLSL           struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);return o;}fixed4 frag (v2f i) : SV_Target{// sample the texturefixed4 col = tex2D(_MainTex, i.uv);// apply fogUNITY_APPLY_FOG(i.fogCoord, col);return col;}ENDHLSL}}
}

3.正面Pass

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/29752.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【如何在Python中使用turtle库】

在Python中使用turtle库来绘制图形非常简单。下面是一些基本步骤,说明如何使用turtle库进行简单的绘图操作。 步骤 1: 导入turtle模块 首先,你需要在你的Python脚本或交互式环境中导入turtle模块。 import turtle步骤 2: 创建一个Turtle对象 通常&am…

HarmonyOS 角落里的知识 —— 状态管理

一、前言 在探索 HarmonyOS 的过程中,我们发现了许多有趣且实用的功能和特性。有些总是在不经意间或者触类旁通的找到。或者是某些开发痛点。其中,状态管理是ArkUI开发非常核心的一个东西,我们进行了大量的使用和测试遇到了许多奇奇怪怪的问…

Android平台下VR头显如何低延迟播放4K以上超高分辨率RTSP|RTMP流

技术背景 VR头显需要更高的分辨率以提供更清晰的视觉体验、满足沉浸感的要求、适应透镜放大效应以及适应更广泛的可视角度,超高分辨率的优势如下: 提供更清晰的视觉体验:VR头显的分辨率直接决定了用户所看到的图像的清晰度。更高的分辨率意…

spring boot自定义注解校验参数(枚举校验)

引入spring boot的spring-boot-starter-validation实现自定义注解校验参数&#xff0c;实现校验枚举值参数数据是否合规&#xff0c;提高接口的安全性和开发效率。 1.引入validation的starter <dependency><groupId>org.springframework.boot</groupId><…

001.VMware Workstation Pro虚拟平台安装

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

《数字图像处理-OpenCV/Python》第16章:图像的特征描述

《数字图像处理-OpenCV/Python》第16章&#xff1a;图像的特征描述 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第16章&#xff1a;图像的特征描述 特征通常是针对图像中的目标或…

快排(霍尔排序实现+前后指针实现)(递归+非递归)

前言 快排是很重要的排序&#xff0c;也是一种比较难以理解的排序&#xff0c;这里我们会用递归的方式和非递归的方式来解决&#xff0c;递归来解决是比较简单的&#xff0c;非递归来解决是有点难度的 快排也称之为霍尔排序&#xff0c;因为发明者是霍尔&#xff0c;本来是命名…

基于Spring Boot+VUE旧物置换网站

1前台首页功能模块 旧物置换网站&#xff0c;在系统首页可以查看首页、旧物信息、网站公告、个人中心、后台管理等内容&#xff0c;如图1所示。 图1系统功能界面图 用户注册&#xff0c;在用户注册页面通过填写用户名、密码、姓名、性别、头像、手机、邮箱等内容进行用户注册&…

【linux 常用命令】

以下是一些常用的Linux命令&#xff1a; ls&#xff1a;列出当前目录的文件和文件夹。cd&#xff1a;更改当前目录。pwd&#xff1a;显示当前工作目录的路径。mkdir&#xff1a;创建一个新目录。touch&#xff1a;创建一个新文件或更新现有文件的时间戳。cp&#xff1a;复制文…

FlinkCDC介绍及使用

CDC简介 什么是CDC&#xff1f; cdc是Change Data Capture(变更数据获取)的简称。核心思想是&#xff0c;监测并捕获数据库的 变动(包括数据或数据表的插入&#xff0c;更新以及删除等)&#xff0c;将这些变更按发生的顺序完整记录下来&#xff0c;写入到消息中间件以供其它服…

C++笔记之RegisterCallback和setCallback、以及setCallback(lambda表达式)

C++笔记之RegisterCallback和setCallback、以及setCallback(lambda表达式) —— 2024-06-19 code review! 参考博文: C++笔记之RegisterCallback和setCallback、以及setCallback(lambda表达式) C++笔记之注册回调函数常见的5种情况对比 文章目录 C++笔记之RegisterCallback和…

IPv4的报头详解

1.ipv4的报头&#xff1a; 注意&#xff1a;ipv4的报头长度共有20个字节&#xff0c;数据包通过ipv4协议传输后&#xff0c;会进行封装和解封装&#xff1a; 封装&#xff1a;tcp/ip五层参考模型 应用层网络层传输层数据链路层物理层 网络层&#xff1a;tcp/udp 传输层&#…

【odoo】如何开启开发者模式,开启有什么作用?

概要 在 Odoo 中&#xff0c;开发者模式&#xff08;Developer Mode&#xff09;是一种专门为开发和调试提供的模式。启用开发者模式可以让开发人员访问到更多的功能和信息&#xff0c;从而更方便地进行模块开发、调试和测试。 启用方式&#xff08;主要两种&#xff09; 1.设…

百度网盘提速攻略:解决限速问题的实用方法

百度网盘提速攻略&#xff1a;解决限速问题的实用方法 百度网盘作为国内广受欢迎的云存储服务&#xff0c;为用户提供了便捷的文件存储和分享功能。然而&#xff0c;许多用户在使用百度网盘进行文件下载时&#xff0c;常常会遇到限速问题&#xff0c;导致下载速度极慢&#xf…

「iOS」UI——无限轮播图实现与UIPageControl运用

「OC」UI 文章目录 「OC」UI无限轮播图的实现以及UIPageControl的实际运用明确要求简单滚动视图的实现UIPageControl的实现设置NSTimer实现自动移动补充实现 进行无限滚动视图的修改思路实现 完整代码展示 无限轮播图的实现以及UIPageControl的实际运用 明确要求 我们要实现一…

四、C#类型转换

在C#中&#xff0c;类型转换是将一个数据类型的值转换为另一个数据类型的过程。 C#中的类型转换可以分为两种&#xff1a;隐式类型转换和显式类型转换&#xff08;也称为强制类型转换&#xff09;。 隐式类型转换 隐式转换是不需要编写代码来指定的转换&#xff0c;编译器会…

SSM旅游系统

摘要 旅游业正处于快速发展阶段&#xff0c;旅游系统的建设已经成为了旅游业发展的重要核心问题。在这样的背景下&#xff0c;SSM框架正逐步发展为一种主要的架构。但目前青海省旅游业信息化的发展仍面临诸多问题&#xff0c;包括系统功能不完善、用户体验不佳、数据管理不规范…

c语言中的字符函数

1.字符分类函数 c语言中有一系列函数是专门做字符分类的&#xff0c;也就是一个字符属于什么类型的字符。这些函数的使用需要包含一个头文件是ctype.h 可能你看这些感觉很懵&#xff0c;我以islower举例 #include<ctype.h> int main() {int retislower(A);printf("…

Apache Doris 之 Docker 部署篇

前言 在现代数据驱动的商业环境中&#xff0c;实时数据分析和高并发查询能力是企业成功的关键因素之一。传统的数据仓库和分析工具在面对大规模数据处理和实时分析需求时&#xff0c;往往力不从心。Apache Doris 作为一个现代的 MPP 数据库管理系统&#xff0c;凭借其强大的查…

uni-app

uni-app 1.简介 ​ UniApp 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;可以开发跨平台应用&#xff0c;如&#xff1a;iOS、Android、H5、小程序等。UniApp 提供了丰富的组件和 API&#xff0c;使得开发者可以使用一套代码&#xff0c;实现多平台开发。官方文档&a…