Unity Shader总结(十)——Cubemap、镜子、玻璃、程序纹理


Cubemap是环境映射的一种实现方法,使用三维纹理坐标进行采样,这个三维纹理坐标代表世界空间下的一个3D方向,这个方向矢量从立方体中心出发,采样的结果由交点计算得出。
缺点:1.当场景引入新的物体、光源或物体发生移动时,都要重新计算;2.仅可以反射环境,不可以反射使用了Cubemap的物体自身,因为Cubemap不能模拟多次反射,如两个金属球互相反射(全局光照可以实现),因此尽量对凸面体使用,不要对凹面体使用,因为凹面体会反射自身。

天空盒

1.新建材质;
2.在材质的unity shader下选择skybox/6 Sided;
3.把6张纹理的wrap mode设置为Clamp,防止接缝处出现不匹配的现象;
4.把材质赋给lighting中的skybox;
5.将camera中的clear flags设置为skybox;
6.如果希望某些摄像机使用不同的天空盒,可以在摄像机上单击component——rendering——skybox来完成覆盖;

创建立方体纹理

方法有三种:
1.准备一张HDR的立方体展开图,纹理类型设置cubemap;(推荐)
2.准备六张纹理贴到创建的Cubemap上;
3.脚本创建;

脚本创建通过Camera.RenderToCubemap实现:

using UnityEngine;
using UnityEditor;
using System.Collections;

public class RenderCubemapWizard : ScriptableWizard {
   
	//临时摄像机创建位置
	public Transform renderFromPosition;
	public Cubemap cubemap;
	
	void OnWizardUpdate () {
   
		helpString = "Select transform to render from and cubemap to render into";
		isValid = (renderFromPosition != null) && (cubemap != null);
	}
	
	void OnWizardCreate () {
   
		// create temporary camera for rendering
		GameObject go = new GameObject( "CubemapCamera");
		go.AddComponent<Camera>();
		// place it on the object
		go.transform.position = renderFromPosition.position;
		// render into cubemap		
		go.GetComponent<Camera>().RenderToCubemap(cubemap);
		
		// destroy temporary camera
		DestroyImmediate( go );
	}
	
	[MenuItem("GameObject/Render into Cubemap")]
	static void RenderCubemap () {
   
		ScriptableWizard.DisplayWizard<RenderCubemapWizard>(
			"Render cubemap", "Render!");
	}
}

该脚本将摄像机放到物体位置观察到的六张图像渲染到cubemap中,使用方法:创建gameobject,再创建cubemap(legacy->cubemap),勾选readable,最后打开Render into Cubemap功能渲染即可得到立方体纹理,face size代表渲染质量。

环境映射

反射

把前面得到的cubemap_0放到Reflection Cubemap属性中

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 10/Reflection" {
   
	Properties {
   
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		//控制反射颜色
		_ReflectColor ("Reflection Color", Color) = (1, 1, 1, 1)
		//控制反射程度
		_ReflectAmount ("Reflect Amount", Range(0, 1)) = 1
		_Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {
   }
	}
	SubShader {
   
		Tags {
    "RenderType"="Opaque" "Queue"="Geometry"}
		
		Pass {
    
			Tags {
    "LightMode"="ForwardBase" }
			
			CGPROGRAM
			
			#pragma multi_compile_fwdbase
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Color;
			fixed4 _ReflectColor;
			fixed _ReflectAmount;
			samplerCUBE _Cubemap;
			
			struct a2v {
   
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
   
				float4 pos : SV_POSITION;
				float3 worldPos : TEXCOORD0;
				fixed3 worldNormal : TEXCOORD1;
				fixed3 worldViewDir : TEXCOORD2;
				fixed3 worldRefl : TEXCOORD3;
				SHADOW_COORDS(4)
			};
			
			v2f vert(a2v v) {
   
				v2f o;
				
				o.pos = UnityObjectToClipPos(v.vertex);
				
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);
				
				// Compute the reflect dir in world space
				o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);
				
				TRANSFER_SHADOW(o);
				
				return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
   
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));		
				fixed3 worldViewDir = normalize(i.worldViewDir);		
				
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				
				fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir));
				
				// Use the reflect dir in world space to access the cubemap
				//没有归一化是因为这里的参数只需要是方向变量
				fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;
				
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				
				// Mix the diffuse color with the reflected color
				fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten;
				
				return fixed4(color, 1.0);
			}
			
			ENDCG
		}
	}
	FallBack "Reflective/VertexLit"
}

折射

斯涅尔定律:

η 1 s i n Θ 1 = η 2 s i n Θ 2 \eta _{1}sin\Theta _{1}=\eta _{2}sin\Theta _{2} η1sinΘ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值