9.球体阴影

上一篇讲的阴影shader是通过两个pass来渲染出的,第一个pass渲染要投影的物体本体,第二个pass渲染物体的阴影,也就是说阴影的渲染是在物体的shader中而不是地面的shader。下面要讲的球体阴影的shader是放在要接受阴影的地面上。

 原理如下图:

1.根据点的入射光矢量和点到球体的矢量计算【点积】求出【角度】。

2.通过【角度】的sin值,求出【对边】并与【球体半径】进行比较。

3.所求【对边的长度】大于【半径】,说明该点被光照,反之该点是阴影点。


// shader,放在需要接受阴影的对象上
Shader "Study/9_SphereShadow" {
	Properties{
		_spPos("Sphere pos", vector) = (0,0,0,1)
		_spR("radius", float) = 1
		_Intensity("Intensity", range(0,1)) = 0.5
	}
		SubShader{
		Pass{
		Tags{ "LightMode" = "ForwardBase" }
		CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
		float4 _spPos;   // 球体位置
	float _spR;    // 球体半径
	float _Intensity;  // 阴影浓度
	float4 _LightColor0; // 颜色
	struct v2f {
		float4 pos:SV_POSITION;
		float3 litDir:TEXCOORD0;// 世界坐标中灯光方向矢量
		float3 spDir:TEXCOORD1; // 在世界坐标中投影球体方向矢量
		float4 vc:TEXCOORD2; // 逐顶点计算的光照
	};
	v2f vert(appdata_base v)
	{
		v2f o;
		o.pos = mul(UNITY_MATRIX_MVP, v.vertex);// 获取顶点视图位置
		o.litDir = WorldSpaceLightDir(v.vertex);// 获取世界坐标中灯光对顶点的方向矢量
		o.spDir = (_spPos - mul(_Object2World, v.vertex)).xyz;//世界坐标中该顶点到投影球体的矢量

															  // 顶点的光照计算。该顶点在对象坐标中的光照方向矢量
		float3 ldir = ObjSpaceLightDir(v.vertex);
		ldir = normalize(ldir);
		o.vc = _LightColor0 * max(0, dot(ldir, v.normal));//根据顶点的入射光线和法线角度求该顶点光照
		return o;
	}
	float4 frag(v2f i) :COLOR
	{
		float3 litDir = normalize(i.litDir);//获取点的入射线单位向量
		float3 spDir = i.spDir; // 获取该点到投影球体的矢量
		float spDistance = length(spDir); //该点到球体的距离
		spDir = normalize(spDir); //该点到投影球体的单位向量
		float cosV = dot(spDir, litDir);// 该点到球体 与 该点到入射线的夹角
		float sinV = sin(acos(max(0, cosV)));// 拿到余弦值大于0的角度,求正弦
		float D = sinV * spDistance;  // 解三角形,求对边
		float shadow = step(_spR, D); // 如果对边小于半径返回0,该点为阴影点
		float c = lerp(1 - _Intensity, 1, shadow);// shadow由0到1
		return i.vc * c; // 为0的时候是阴影点
	}
		ENDCG
	}
	}
}

这个脚本也放在需要接受阴影的对象上:

using UnityEngine;
using System.Collections;

public class ReceiveShadow : MonoBehaviour {

    public GameObject sphere;
    void Start () {
        Vector3 pos = sphere.transform.localPosition;
        GetComponent<Renderer>().sharedMaterial.SetVector("_spPos", new Vector4(pos.x, pos.y, pos.z, 1f));
        GetComponent<Renderer>().sharedMaterial.SetFloat("_spR", sphere.transform.localScale.x / 2);
    }

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值