一、半透明材质

SSS(sub-Surface Scattering,3S)的中文意思是次表面散射或称半透明材质。它适用于表现各种有次表面反射的材质,如透明橡胶、有机玻璃或玉石等。因为实时渲染是不可能做大量的运算来计算光的折射和反射的,所以SSS属于比较高级的材质范畴。

二、化繁为简

要实现半透明材质,许多方法都进行了大量的运算,比如正弦、余弦的计算、指数的运算等,外加各种贴图和通道的混合,非常复杂。

首先要知道,因为光在半透明物体中沿着各个方向进行折射和反射,所以就会产生一个必然的结果,那就是光的方向性消失了。光在物体内部所能前进的深度依然和物体的密度、物体到光源的距离密切相关。基于此特点,可以方便地写出一个着色器来表现半透明材质的效果。

为了便于控制不同物体的表现,在着色器中提供两个变量:一个用于控制物体到光源距离的偏差,这样就可以表达出从哪个距离光进入了物体内部并开始衰减;另外一个用来控制光在物体中的衰减速度,也就是对物体密度和透明度的控制。主要代码如下:

Shader "Tut/Shader/SSS/SSS_1" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_BaseColor("Base Color of Object",color)=(1,1,1,1)_DistAdjust("Distance Adjust",float)=0_Atten("Control the Density of Object",float)=1}SubShader {Tags { "RenderType"="Opaque" }LOD 200pass{Tags{ "LightMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#pragma target 3.0#include "UnityCG.cginc"struct v2f{float4 pos:SV_POSITION;};v2f vert(appdata_base v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);return o;}float4 frag(v2f i):COLOR{//return 0;}ENDCG}//end passpass{Blend One OneTags{ "LightMode"="ForwardAdd"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma target 3.0#include "UnityCG.cginc"struct v2f{float4 pos:SV_POSITION;float3 N:TEXCOORD0;float3 litDir:TEXCOORD1;//float4 vp:TEXCOORD2;};v2f vert(appdata_base v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);o.N=v.normal;o.litDir=ObjSpaceLightDir(v.vertex);//o.vp=v.vertex;return o;}float4 _BaseColor;float _DistAdjust;float _Atten;float4 frag(v2f i):COLOR{float3 N=normalize(i.N);//float3 litDir=ObjSpaceLightDir(i.vp);float3 litDir=i.litDir;//光源方向float dist=length(litDir);//到光源的原始距离dist=max(0,dist-_DistAdjust);//对原始距离进行一个偏移float att=1/(1+dist*dist);att=pow(att,_Atten);//计算光的衰减速度float4 c= _BaseColor* att*2;//c.a=1-c.a;return c;}ENDCG}//end pass} FallBack "Diffuse"
}

然后在场景加入两个点光源,调整一下参数,效果如下:

代码很简单,连一个通道图都没有用,效果如上图。

三、透明材质

对于透明物体,其表面有反射,内部物体的光线又通过折射到达我们的眼中,因此,对于透明物体,我们想要把这两种现象都表现出来。一种比较直接的办法就是分别渲染物体的正面和背面来达到表现透明物体表面的镜面反射与深度的。

首先看效果图:

这里面有2种shader,WaterBox这个shader表现的是一种类似水体的效果,这个着色器首先正常渲染物体,也就是Cull Back,并且写入Z缓冲区,为后续的渲染在Z缓冲区中占位,其余代码则是对照明比较简单的计算。在第二个通道渲染物体背面的过程中,则使用了一种混合模式,将Z测试的条件设为Greater,从而利用第一个通道在Z缓冲区中的占位,使得Z能够通过测试。

从分层或者画面的角度而言,先渲染的是物体的底面,然后是表面。但是为了使水体在前后都可能存在其他物体的情况下,使前后两个面都能通过深度测试,我们不得不首先渲染物体的正面,并且在Z缓冲区中占位。比如,首先渲染的物体的底面,当Z的条件为Greater时,在存在背景物体的条件下,则无法通过;如果Z的条件设为Less,又因为正面存在,则无法通过;如果Z的条件为Always,并且是正面渲染,则Z测试无法通过。

渲染水体的着色器代码如下:

Shader "Tut/Shader/SSS/WaterBox" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_Deep("Deep Color of Liquid",Color)=(0,0,0,0)_Shallow("Shallow Color of Liquid",Color)=(1,1,1,1)}SubShader {Tags { "RenderType"="Opaque" "Queue"="Geometry+1"}//首先正常渲染,并写入到Z Buffer,这将成为水的表面层//首先渲染正面,是为了使渲染背面的Z测试条件Greater能通过Pass {Blend One ZeroCull BackZTest LessCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct v2f{float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float4 diff:TEXCOORD1;};v2f vert(appdata_full v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);o.uv=v.texcoord.xy;float3 L= ObjSpaceLightDir(v.vertex);o.diff=max(0,dot(L,v.normal))*_LightColor0;return o;}float4 _Shallow;float4 frag(v2f i):COLOR{return i.diff*_Shallow;}ENDCG}Pass {//然后我们渲染背面,有分层概念的人可能会说,我们不是应该渲染底面,再显然表面么//是的,如果这是一幅水彩画的话,的确应该这么做,但是我们为了能够使渲染底面的Z测试条件//Greater能在GPU中通过,恐怕不得不首先渲染物体的正面,并且写入到Z缓冲,从而能够使背面正确的被渲染Blend OneMinusDstAlpha DstAlphaCull FrontZTest GreaterZWrite offCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct v2f{float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float4 diff:TEXCOORD1;};v2f vert(appdata_full v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);o.uv=v.texcoord.xy;float3 L= ObjSpaceLightDir(v.vertex);//因为渲染的是背面,所以需要翻转一下法线o.diff=max(0,dot(L,-v.normal))*_LightColor0;return o;}float4 _Deep;sampler2D _MainTex;float4 frag(v2f i):COLOR{float4 c=tex2D(_MainTex,i.uv);return c*i.diff*_Deep;}ENDCG}} FallBack "Diffuse"
}

对于可能出现在水中的物体,则使用了一个有两个通道的着色器。对于这个名为FloatObject的材质,其第一个通道负责对物体正面的渲染。第二个通道的Z测试条件为Greater,从而使其处于水体中的部分也能够渲染,并且使用了一种适当的混合方式写入到颜色缓冲区中,代码如下:

Shader "Tut/Shader/SSS/FloatObject" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_refVal("Stencil Ref Value",int)=0_Deep("Deep Color of Liquid",Color)=(0,0,0,0)_Front("Shallow Color of Liquid",Color)=(1,1,1,1)}SubShader {//这是一个为了和WaterBox配合使用,描述漂浮在水面的物体而写的ShaderTags { "RenderType"="Opaque" "Queue"="Geometry+2"}Pass {Blend One ZeroCull BackZTest LessCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct v2f{float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float4 diff:TEXCOORD1;};v2f vert(appdata_full v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);o.uv=v.texcoord.xy;float3 L= ObjSpaceLightDir(v.vertex);o.diff=max(0,dot(L,v.normal))*_LightColor0;return o;}float4 _Front;sampler2D _MainTex;float4 frag(v2f i):COLOR{float4 c=tex2D(_MainTex,i.uv);return c*i.diff*_Front*2;}ENDCG}Pass {Blend SrcAlpha OneMinusSrcAlphaCull BackZTest GreaterZWrite offCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct v2f{float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float4 diff:TEXCOORD1;};v2f vert(appdata_full v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);o.uv=v.texcoord.xy;float3 L= ObjSpaceLightDir(v.vertex);o.diff=max(0,dot(L,v.normal))*_LightColor0;return o;}float4 _Deep;sampler2D _MainTex;float4 frag(v2f i):COLOR{float4 c=tex2D(_MainTex,i.uv);return c*i.diff*_Deep*2;}ENDCG}} FallBack "Diffuse"
}

(三十一)unity shader之——————透明和半透明材质相关推荐

  1. Unity Shader 之 不锈钢(各向异性材质)

    Unity Shader 之 不锈钢(各向异性材质) 常见的实现方案 思路: 先求出半角向量halfVector 再求法线方向与光照方向的点积NdotL 半角向量与各向异性方向点积HdotA 求出各向 ...

  2. Unity Shader 之 透明效果

    本文引用 Unity Shader入门精要 开启透明混合后,一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值外,还有--透明度.透明度为1,则完全不透明,透明度为0,则完全不会显示. 在Unity ...

  3. Unity Shader 实现透明护盾效果

    这是大致的效果图,图片压得有点糊.我参考了本篇博客 Unity shader护盾特效. 这是原博客展示的图片: 本例采用了特殊的模型与贴图,原博客里有视频链接的教程,从模型到贴图. 以下是代码 // ...

  4. Unity Shader UV动画之高光材质加上透明材质与UV动画

    理解,UV动画实质是对UV的坐标进行变化,从而使纹理产生动态变化 例子:从高光材质进行修改 1,加上透明材质的标签以及混合模式,再使用带透明通道的贴图,可以实现:不透明部分的图案,材质是高光材质,透明 ...

  5. unity shader 纹理透明效果

    1.纹理映射基础 (1)纹理映射通过(u,v)坐标实现.注意:这句话时博主当时面试一家外企被问到的问题. (2)添加纹理属性:--MainTex("Main Tex",2D)=&q ...

  6. AGG第三十一课 pattern_perspective样式透明

    摘自:http://article.gmane.org/gmane.comp.graphics.agg/2911/ > I've read the pattern_perspective.cpp ...

  7. unity shader 入门 全透明与半透明效果实现

    片元函数的fixed4类型的返回值的第4位即为阿尔法值,0代表完全不显示(透明),1代表完全显示.中间的数值代表半透明.但只修改这个值是不能直接修改透明度的,因为还要对队列等进行修改. 本文介绍透明度 ...

  8. 【unity shader 入门精要 读书笔记】透明

    一.透明 1.透明度测试[Alpha Test] 它采用一种"霸道极端"的机制:只要有一个片元的透明度不满足条件[通常是小于某个阈值],那么它对应的片元就会被舍弃.被舍弃的片元将不 ...

  9. Unity Shader知识点(三)高光反射Shader

    前言 此文及专栏系是以Shader入门精要为基础整理的Unity Shader学习笔记,尽量以初学者视角还原(其实半年前我就是初学者),错误还需指正. 本篇是实操部分的第三个Shader,即高光反射S ...

最新文章

  1. java 并发包学习_Java学习笔记—多线程(java.util.concurrent并发包概括,转载)
  2. 125KHz 100cm ID 读卡电路_7 个别出心裁的树莓派优质项目集锦(完整代码+电路设计资料)...
  3. linux文件系统简介
  4. 「SVN」Linux下svn使用命令
  5. MySQL运维常用系统命令
  6. Windows11怎么设置时间?Win11时间设置教程
  7. oracle 区管理系统,oracle区管理和段空间管理详细介绍
  8. Visual Studio Code 编辑器 使用入门
  9. 写论文的一点经验小记
  10. H5使用OCR身份证识别
  11. 阿里云短信发送接口直接HTTP请求调用
  12. 服务器ping不通网址!
  13. 最新CCF会议|2022-2023顶会会议时间+投稿时间+官网链接(视觉+多媒体+数据挖掘+数据库+通用人工智能)
  14. VS C#-EXE文件如何将ICO图片添加进去
  15. 工控流量分析题+wireshark学习
  16. 基于android的ipcamera编程,spydroid-ipcamera-master完整实现源码
  17. 北大CSAPP期末题
  18. 新手SEO需要知道的SEO几个步骤
  19. python一帧一帧读取视频_用Python从视频中提取每一帧的图片
  20. Kubernetes 1.5通过Ceph实现有状态容器

热门文章

  1. jd-gui的eclipse插件安装和使用
  2. 机械结构工程师的日常
  3. 药品招商就到中国医药代理
  4. 20个有用的Excel数据分析函数(教程含案例)
  5. 变压器绕组变形试验的重要性
  6. 单细胞测序流程(三)质控和数据过滤——Seurat包分析,小提琴图和基因离差散点图
  7. win10怎么用记事本打开html文件,给win10系统右键菜单添加“用记事本打开”的方法...
  8. Firefox - 附加组件 - 扩展 - Firebug - 更新 - 1.2.0b15
  9. 一文读懂金融行业软件测试
  10. Python opencv库 tkinter 设计屏幕录制工具