Unity shader学习之阴影
Unity阴影采用的是 shadow map 的技术,即把摄像机放到光源位置上,看不到的地方就有阴影。
前向渲染中,若一光源开启了阴影,Unity会计算它的阴影映射纹理(shadow map),它其实是一张深度图,记录了从光源位置出发,能看到的场景中距离它最近的表面位置的深度信息。
Unity中采用LightMode为ShadowCaster的Pass来生成这张 shadow map,首先会从本shader中找这个pass,若没有就从fallback的shader中层层寻找。
然后在fragment shader中,比较该点与shadow map中对应的点的深度,若大于,则处在阴影区域,否则不在阴影区域。
阴影包括投射阴影和接收阴影2个部分。
投射阴影,则需将该物体加入到光源的shadow map的计算中。
接收阴影,则需要对shadow map进行采样,把采样结果和最后的光照结果相乘来产生阴影效果。
shader如下:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/Forward Rendering"
{
Properties
{
_MainTex("Main Texture", 2D) = "white" {}
_Specular("Specular", Color) = (,,,)
_Gloss("Gloss", Range(,)) =
} SubShader
{
Pass
{
Tags
{
"LightMode" = "ForwardBase"
} CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase #include "UnityCg.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc" sampler2D _MainTex;
fixed4 _Specular;
float _Gloss; struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
}; struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float4 worldPos: TEXCOORD2;
SHADOW_COORDS()
}; v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
TRANSFER_SHADOW(o);
return o;
} fixed4 frag(v2f i) : SV_TARGET
{
fixed4 albedo = tex2D(_MainTex, i.uv);
fixed4 ambient = albedo * UNITY_LIGHTMODEL_AMBIENT; float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos.xyz));
float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos.xyz));
fixed4 diff = albedo * _LightColor0 * max(, dot(i.worldNormal, worldLight)); float3 halfDir = normalize(worldView + worldLight);
fixed4 spec = albedo * _Specular * pow(max(, dot(halfDir, i.worldNormal)), _Gloss); float shadow = SHADOW_ATTENUATION(i);
fixed4 col = ambient + (diff + spec) * shadow;
return col;
} ENDCG
} Pass
{
Tags
{
"LightMode" = "ForwardAdd"
}
Blend One One CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd #include "UnityCg.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc" sampler2D _MainTex;
fixed4 _Specular;
float _Gloss; struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
}; struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float4 worldPos: TEXCOORD2;
SHADOW_COORDS()
}; v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
TRANSFER_SHADOW(o);
return o;
} fixed4 frag(v2f i) : SV_TARGET
{
fixed4 albedo = tex2D(_MainTex, i.uv); float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos.xyz));
float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos.xyz));
fixed4 diff = albedo * _LightColor0 * max(, dot(i.worldNormal, worldLight)); float3 halfDir = normalize(worldView + worldLight);
fixed4 spec = albedo * _Specular * pow(max(, dot(halfDir, i.worldNormal)), _Gloss); // 参考 AutoLight.cginc
float atten;
#ifdef USING_DIRECTIONAL_LIGHT
atten = ;
#else
float4 lightCoord = mul(unity_WorldToLight, i.worldPos);
#ifdef POINT
atten = tex2D(_LightTexture0, dot(lightCoord.xyz,lightCoord.xyz).xx).UNITY_ATTEN_CHANNEL;
#elif SPOT
atten = (lightCoord.z > ) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).xx).UNITY_ATTEN_CHANNEL;
#endif
#endif float shadow = SHADOW_ATTENUATION(i); fixed4 col = (diff + spec) * atten * shadow;
return col;
} ENDCG
}
} Fallback "VertexLit"
}
效果如下:
Unity shader学习之阴影的更多相关文章
- Unity shader学习之阴影,衰减统一处理
使用unity AutoLight.cginc文件里的内置函数 UNITY_LIGHT_ATTENUATION shader如下: // Upgrade NOTE: replaced 'mul(UNI ...
- Unity Shader 学习之旅
Unity Shader 学习之旅 unityshader图形图像 纸上学来终觉浅,绝知此事要躬行 美丽的梦和美丽的诗一样 都是可遇而不可求的——席慕蓉 一.渲染流水线 示例图 Tips:什么是 GP ...
- Unity Shader 学习之旅之SurfaceShader
Unity Shader 学习之旅之SurfaceShader unity shader 图形图像 如果大地的每个角落都充满了光明 谁还需要星星,谁还会 在夜里凝望 寻找遥远的安慰——江河 官方文档 ...
- 第四章 开始Unity Shader学习之旅(2)
目录 1. 强大的援手:Unity提供的内置文件和变量 1.1 内置的包含文件 1.2 内置的变量 2. Unity提供的Cg/HLSL语义 2.1 什么是语义 2.2 Unity支持的语义 2.3 ...
- Unity Shader学习笔记-1
本篇文章是对Unity Shader入门精要的学习笔记,插图大部分来自冯乐乐女神的github 如果有什么说的不正确的请批评指正 目录 渲染流水线 流程图 Shader作用 屏幕映射 三角形遍历 两大 ...
- 第四章 开始Unity Shader学习之旅(1)
1. 一个最简单的顶点/片元着色器 现在,我们正式开始学习如何编写Unity Shader,更准确的说是,学习如何编写顶点/片元着色器 2.顶点/片元着色器的基本结构 我们在以前已经讲过了Unity ...
- 【Unity Shader学习笔记】Unity基础纹理-单张纹理
1 单张纹理 1.1 纹理 使用纹理映射(Texture Mapping)技术,我们把一张图片逐纹素(Texel)地控制模型的颜色. 美术人员建模时,会在建模软件中利用纹理展开技术把纹理映射坐标(Te ...
- Unity shader学习之屏幕后期处理效果之高斯模糊
高斯模糊,见 百度百科. 也使用卷积来实现,每个卷积元素的公式为: 其中б是标准方差,一般取值为1. x和y分别对应当前位置到卷积中心的整数距离. 由于需要对高斯核中的权重进行归一化,即使所有权重相加 ...
- Unity Shader入门精要学习笔记 - 第5章 开始 Unity Shader 学习之旅
一个顶点/片元 着色器的结构大概如下: Shader "MyShaderName" { Properties { //属性 } SubShader { //针对显卡A的SubSha ...
随机推荐
- Flash and Scalform CLIK
Flash shift + f7 打开组件检查面板 Scaleform As bit define bool Unrolling :1; // indi ...
- 转:centos7/rhel7安装较高版本ruby2.2/2.3/2.4+
centos7/rhel7安装较高版本ruby2.2/2.3/2.4+ 环境需求: 在Centos7.3中,通过yum安装ruby的版本是2.0.0,但是如果有些应用需要高版本的ruby环境,比 ...
- Fiddler怎么可以抓取https的请求包
对于https的协议是带有安全的功能,所有有一些的https的协议是无法抓到的,所以需要通过设置filler中来对,来使用filler的方式的来抓取到https的请求包,那么如何使用filler中抓取 ...
- 2018/05/02 每日一学Linux 之 .bash_profile和.bashrc的区别
最近一直在学习其他,导致博客就疏忽了,很不好(其实就是自己懒了......). -- 为什么要使用 .bash_profile和.bashrc ? 在平常的使用中,有些文件夹或者命令很长,在执行时需要 ...
- Anaconda 虚拟环境安装及应用
首先要安装Anaconda 下载网址:https://www.anaconda.com/distribution/#download-section Miniconda下载网址:https: ...
- Javascript面向对象编程(二):构造函数的继承 作者:yuan一峰
Javascript面向对象编程(二):构造函数的继承 作者: 阮一峰 日期: 2010年5月23日 这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生 ...
- Linux中的轻量级进程
在Linux中,轻量级进程可以是进程,也可以是线程.我们所说的线程,在Linux中,其实是轻量级进程之间共享代码段,文件描述符,信号处理,全局变量时: 如果不共享,就是我们所说的进程. 进程是资源管理 ...
- log4j layout日志信息格式
Log4j提供的layout有以下几种 org.apache.log4j.HTMLLayout(以HTML表格形式布局), org.apache.log4j.PatternLayout(可以灵活地指定 ...
- centos7安装webmin
安装webmin准备centos7系统1.下载http://download.webmin.com/download/yum/选择:webmin-1.700-1.noarch.rpm 安装包 wget ...
- insert select带来的问题
当使用 insert...select...进行记录的插入时,如果select的表是innodb类型的,不论insert的表是什么类型的表,都会对select的表的纪录进行锁定.对于那些从oracle ...