SSSSS屏幕空间次表面散射

2023-10-09 16:20

本文主要是介绍SSSSS屏幕空间次表面散射,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • SSSSS
  • 代码实现
    • Camera Script
    • Camera Shader
    • Mask 遮罩

refer:
雷火知乎
毛星云总结
参考1
参考2
参考3

(有一个想法,厚度图,通过厚度图来控制SSSSS的范围和强度)

  • 严格来讲并不是基于物理的渲染,但是其出发点是对BSSRDF的近似,因此我归到PBR这个专栏了,其实本来就不好分类

  • 如果希望理解原理,有更深入的理解的话,欢迎来看我的BSSRDF

  • 主要解释都在代码注释里

SSSSS

流程:

  1. 分别获取Object的 遮罩漫反射颜色_A深度 各自存入RenderTex中
  2. 遮罩内的漫反射进行blur
    两个要点:1、根据Object到Camera的距离确定一个总体的blur范围
         2、根据当前片元的深度值,进行微调
  3. 再获取一张 漫反射颜色_B
  4. A和B 相加
  5. 再加上遮罩内的单独的高光
  6. 得到最后结果

流程示意

关于blur的详细介绍可以看本人的另一篇文章




注意:后处理中无法使用模板测试

  • 多次尝试后,尚未发现能在后处理中使用模板缓冲的办法,SSSSS的案例考虑采用蒙版
    后续发现解决办法再来更新

后处理中是不能使用模板测试的,如果使用则会失效,这是因为后处理是在虚拟的渲染纹理中进行的,而这个渲染纹理并没有继承屏幕空间中的各个缓冲(不确定,但应该是这样)
官方API文档中有说 RenderTexture.GetTemporary(rtW, rtH,24); 第三个参数改成24会保留深度模板缓冲,经测试无效
一篇文章介绍说再添加一个语句

RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH,24); 
Graphics.SetRenderTarget(buffer.colorBuffer, src.depthBuffer);

这样会保留缓冲, 但经测试依然无效


代码实现

  • 本人学艺不精,现在还没有搞懂遮罩的脚本部分,因此无法完整再现上述流程
    但本文的目的是为了理解,因此下面的代码部分,使用了本人自己写的较为基础的版本:没有遮罩,没有深度图和摄像机距离,仅介绍SSSSS中核心的部分

如果有需要完整代码的,Unity的AssetStore中有前辈写好的免费资源


Camera Script

using UnityEngine;public class SSS_Camera : PostEffectsBase
{public Shader SSS_Shader;private Material SSS_Mat = null;public Material material{get{SSS_Mat = CheckShader_CreateMat(SSS_Shader, SSS_Mat);return SSS_Mat;}}//模糊所需参数[Range(0,4)]public int iterations = 3;[Range(0.2f, 10.0f)]public float blurSpread = 0.6f;[Range(1,8)]public int downSample = 2;    //bloom截取强度[Range(0.0f, 4f)]public float lumi = 0.6f; //不止到1,是为了HDRvoid OnRenderImage(RenderTexture src, RenderTexture dest) {if (material != null){material.SetFloat("_Lumi", lumi);int rtW = src.width/downSample;int rtH = src.height/downSample;RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH,24); //Graphics.SetRenderTarget(buffer0.colorBuffer, src.depthBuffer);buffer0.filterMode = FilterMode.Bilinear;//先走第一个pass提取需要bloom的部分Graphics.Blit(src, buffer0,material,0);//注意循环内部创建的RenderTex在循环外是访问不到的,因此需要左手倒右手for (int i = 0; i < iterations; i++) {material.SetFloat("_BlurSize", 1.0f + i * blurSpread);RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 24);Graphics.Blit(buffer0, buffer1, material, 1);RenderTexture.ReleaseTemporary(buffer0);buffer0 = buffer1;buffer1 = RenderTexture.GetTemporary(rtW, rtH, 24);Graphics.Blit(buffer0, buffer1, material, 2);RenderTexture.ReleaseTemporary(buffer0);buffer0 = buffer1;}//这一步很重要啊,把bloom好的图像传递给Shadermaterial.SetTexture("_Bloom", buffer0);Graphics.Blit(src, dest, material, 3);RenderTexture.ReleaseTemporary(buffer0);}else{Graphics.Blit(src, dest);}}
}



Camera Shader

Shader "Unlit/SSSSS_Camera"
{Properties{_MainTex ("Base", 2D) = "white" {}_Bloom ("Bloom", 2D) =  "black"{} //用于存储亮度图_BlurSize ("Blur Size", float) = 1.0_Lumi ("lumi", float) = 0.6   //这个值是用来控制bloom的阈值}SubShader{ZTest Always Cull Off ZWrite OffPass//提取亮度Pass{Stencil{Ref 1Comp alwaysPass Keep}CGPROGRAM#pragma vertex vertBloom#pragma fragment fragBloom#include "UnityCG.cginc"sampler2D _MainTex;sampler2D _Bloom;half4 _MainTex_TexelSize; //内置方法,可以获取纹素大小float _BlurSize;float _Lumi;struct v2f{float2 uv : TEXCOORD0; float4 vertex : SV_POSITION;};v2f vertBloom(appdata_img v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;return o;}fixed Luminance(fixed4 color){ //这个是明度的计算,可以去看本人的文章“色彩知识总结”return 0.2125*color.r + 0.7154*color.g + 0.0721*color.b;}fixed4 fragBloom(v2f i): SV_Target {fixed3 c = tex2D(_MainTex, i.uv);fixed l = clamp(Luminance(c) - _Lumi, 0, 1); //clamp函数是一个截取函数,后面两个参数是范围return  fixed4 (c*l,1);//为什么这里要乘?//这里要乘而不是单纯的取0/1,是因为://(1)GPU不擅长分支运算//(2)数值越大的fragment在模糊时,影响的范围更大,符合真实逻辑,乘法保留了这种特性}ENDCG}//模糊Pass//注意这里是直接引用了同工程下的另外一个shader中的Pass,//可以在本人的其他文章中找到,或直接使用《入门精要》附带的文件//UsePass "Unity Shaders Book/Chapter 12/Gaussian Blur/GAUSSIAN_BLUR_HORIZONTAL"UsePass "Unity Shaders Book/Chapter 12/Gaussian Blur/GAUSSIAN_BLUR_HORIZONTAL"UsePass "Unity Shaders Book/Chapter 12/Gaussian Blur/GAUSSIAN_BLUR_VERTICAL"//UsePass "Unity Shaders Book/Chapter 12/Gaussian Blur/GAUSSIAN_BLUR_VERTICAL"Pass//混合Pass{Stencil{Ref 1Comp equalPass Keep}CGPROGRAM#pragma vertex vertMerge#pragma fragment fragMerge#include "UnityCG.cginc"sampler2D _MainTex;sampler2D _Bloom;half4 _MainTex_TexelSize; //内置方法,可以获取纹素大小float _BlurSize;float _Lumi;struct v2fMerg{float4 vertex : SV_POSITION;float4 uv : TEXCOORD0;};v2fMerg vertMerge(appdata_img v){v2fMerg o;o.vertex = UnityObjectToClipPos(v.vertex);//将两张纹理的坐标分开是为了处理平台差异化o.uv.xy = v.texcoord;o.uv.zw = v.texcoord;//平台差异化处理,详见“Unity的一些机制”和《精要》5.6.1//#if UNITY_UV_STARTS_AT_TOP			//if (_MainTex_TexelSize.y < 0.0)//	o.uv.w = 1.0 - o.uv.w;//#endifreturn o;}fixed4 fragMerge(v2fMerg i): SV_Target{//直接加?//当然直接相加,不然不就是单纯的模糊了,bloom的亮度就是要超额,超额也更适合HDRreturn tex2D(_MainTex, i.uv.xy) + tex2D(_Bloom, i.uv.xy);}ENDCG}}Fallback Off
}



Mask 遮罩

既然不能用模板,那么就来学习遮罩吧,但是呢,对于本人而言有那么一点复杂,我不是很会写脚本,这部分先跳过,以后脚本能力够了回来补

这篇关于SSSSS屏幕空间次表面散射的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/174065

相关文章

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

使用Python实现获取屏幕像素颜色值

《使用Python实现获取屏幕像素颜色值》这篇文章主要为大家详细介绍了如何使用Python实现获取屏幕像素颜色值,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、一个小工具,按住F10键,颜色值会跟着显示。完整代码import tkinter as tkimport pyau

MySQL启动报错:InnoDB表空间丢失问题及解决方法

《MySQL启动报错:InnoDB表空间丢失问题及解决方法》在启动MySQL时,遇到了InnoDB:Tablespace5975wasnotfound,该错误表明MySQL在启动过程中无法找到指定的s... 目录mysql 启动报错:InnoDB 表空间丢失问题及解决方法错误分析解决方案1. 启用 inno

在Java中基于Geotools对PostGIS数据库的空间查询实践教程

《在Java中基于Geotools对PostGIS数据库的空间查询实践教程》本文将深入探讨这一实践,从连接配置到复杂空间查询操作,包括点查询、区域范围查询以及空间关系判断等,全方位展示如何在Java环... 目录前言一、相关技术背景介绍1、评价对象AOI2、数据处理流程二、对AOI空间范围查询实践1、空间查

MySQL表空间结构详解表空间到段页操作

《MySQL表空间结构详解表空间到段页操作》在MySQL架构和存储引擎专题中介绍了使用不同存储引擎创建表时生成的表空间数据文件,在本章节主要介绍使用InnoDB存储引擎创建表时生成的表空间数据文件,对... 目录️‍一、什么是表空间结构1.1 表空间与表空间文件的关系是什么?️‍二、用户数据在表空间中是怎么

CentOS7增加Swap空间的两种方法

《CentOS7增加Swap空间的两种方法》当服务器物理内存不足时,增加Swap空间可以作为虚拟内存使用,帮助系统处理内存压力,本文给大家介绍了CentOS7增加Swap空间的两种方法:创建新的Swa... 目录在Centos 7上增加Swap空间的方法方法一:创建新的Swap文件(推荐)方法二:调整Sww

macOS Sequoia 15.5 发布: 改进邮件和屏幕使用时间功能

《macOSSequoia15.5发布:改进邮件和屏幕使用时间功能》经过常规Beta测试后,新的macOSSequoia15.5现已公开发布,但重要的新功能将被保留到WWDC和... MACOS Sequoia 15.5 正式发布!本次更新为 Mac 用户带来了一系列功能强化、错误修复和安全性提升,进一步增

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络