Unity水面Shader

shader:

Shader "Tasharen/Water"
{
Properties
{
_WaterTex ("Normal Map (RGB), Foam (A)", 2D) = "white" {}
_ReflectionTex ("Reflection", 2D) = "white" { TexGen ObjectLinear }
_Cube ("Skybox", Cube) = "_Skybox" { TexGen CubeReflect }
_Color0 ("Shallow Color", Color) = (1,1,1,1)
_Color1 ("Deep Color", Color) = (0,0,0,0)
_Specular ("Specular", Color) = (0,0,0,0)
_Shininess ("Shininess", Range(0.01, 1.0)) = 1.0
_Tiling ("Tiling", Range(0.025, 0.25)) = 0.25
_ReflectionTint ("Reflection Tint", Range(0.0, 1.0)) = 0.8
_InvRanges ("Inverse Alpha, Depth and Color ranges", Vector) = (1.0, 0.17, 0.17, 0.0)
}

//==============================================================================================
// Common functionality
//==============================================================================================


CGINCLUDE
#ifdef SHADER_API_D3D11
#pragma target 4.0
#else
#pragma target 3.0
#endif
#include "UnityCG.cginc"

half4 _Color0;
half4 _Color1;
half4 _Specular;
float _Shininess;
float _Tiling;
float _ReflectionTint;
half4 _InvRanges;

sampler2D _CameraDepthTexture;
sampler2D _WaterTex;

half4 LightingPPL (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
half3 nNormal = normalize(s.Normal);
half shininess = s.Gloss * 250.0 + 4.0;

#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
// Phong shading model
half reflectiveFactor = max(0.0, dot(-viewDir, reflect(lightDir, nNormal)));

// Blinn-Phong shading model
//half reflectiveFactor = max(0.0, dot(nNormal, normalize(lightDir + viewDir)));

half diffuseFactor = max(0.0, dot(nNormal, lightDir));
half specularFactor = pow(reflectiveFactor, shininess) * s.Specular;

half4 c;
c.rgb = (s.Albedo * diffuseFactor + _Specular.rgb * specularFactor) * _LightColor0.rgb;
c.rgb *= (atten * 2.0);
c.a = s.Alpha;
return c;
}
ENDCG

//==============================================================================================
// Reflection and refraction
//==============================================================================================


SubShader
{
Lod 400
Tags { "Queue" = "Transparent-10" }

GrabPass
{
Name "BASE"
Tags { "LightMode" = "Always" }
}


Blend Off
ZTest LEqual
ZWrite Off


CGPROGRAM
#pragma surface surf PPL vertex:vert noambient

sampler2D _GrabTexture : register(s0);
sampler2D _ReflectionTex;

uniform half4 _GrabTexture_TexelSize;

struct Input
{
float4 position  : POSITION;
float3 worldPos  : TEXCOORD2;// Used to calculate the texture UVs and world view vector
float4 proj0   : TEXCOORD3; // Used for depth and reflection textures
float4 proj1 : TEXCOORD4; // Used for the refraction texture
};

void vert (inout appdata_full v, out Input o)
{
o.worldPos = v.vertex.xyz;
o.position = mul(UNITY_MATRIX_MVP, v.vertex);
o.proj0 = ComputeScreenPos(o.position);
COMPUTE_EYEDEPTH(o.proj0.z);

o.proj1 = o.proj0;
#if UNITY_UV_STARTS_AT_TOP
o.proj1.y = (o.position.w - o.position.y) * 0.5;
#endif
}

void surf (Input IN, inout SurfaceOutput o)
{
// Calculate the world-space view direction (Y-up)
// We can't use IN.viewDir because it takes the object's rotation into account, and the water should not.
float3 worldView = (IN.worldPos - _WorldSpaceCameraPos);

// Calculate the object-space normal (Z-up)
float offset = _Time.x * 0.5;
half2 tiling = IN.worldPos.xz * _Tiling;
half4 nmap = (tex2D(_WaterTex, tiling + offset) + tex2D(_WaterTex, half2(-tiling.y, tiling.x) - offset)) * 0.5;
o.Normal = nmap.xyz * 2.0 - 1.0;


// World space normal (Y-up)
half3 worldNormal = o.Normal.xzy;
worldNormal.z = -worldNormal.z;

// Calculate the depth difference at the current pixel
float depth = tex2Dproj(_CameraDepthTexture, IN.proj0).r;
depth = LinearEyeDepth(depth);
depth -= IN.proj0.z;

// Calculate the depth ranges (X = Alpha, Y = Color Depth)
half3 ranges = saturate(_InvRanges.xyz * depth);
ranges.y = 1.0 - ranges.y;
ranges.y = lerp(ranges.y, ranges.y * ranges.y * ranges.y, 0.5);

// Calculate the color tint
half4 col;
col.rgb = lerp(_Color1.rgb, _Color0.rgb, ranges.y);
col.a = ranges.x;

// Initial material properties
o.Alpha = col.a;
o.Specular = col.a;
o.Gloss = _Shininess;

// Dot product for fresnel effect
half fresnel = sqrt(1.0 - dot(-normalize(worldView), worldNormal));


// High-quality reflection uses the dynamic reflection texture
IN.proj0.xy += o.Normal.xy * 0.5;
half3 reflection = tex2Dproj(_ReflectionTex, IN.proj0).rgb;
reflection = lerp(reflection * col.rgb, reflection, fresnel * _ReflectionTint);


// High-quality refraction uses the grab pass texture
IN.proj1.xy += o.Normal.xy * _GrabTexture_TexelSize.xy * (20.0 * IN.proj1.z * col.a);
half3 refraction = tex2Dproj(_GrabTexture, IN.proj1).rgb;
refraction = lerp(refraction, refraction * col.rgb, ranges.z);


// Color the refraction based on depth
refraction = lerp(lerp(col.rgb, col.rgb * refraction, ranges.y), refraction, ranges.y);


// The amount of foam added (35% of intensity so it's subtle)
half foam = nmap.a * (1.0 - abs(col.a * 2.0 - 1.0)) * 0.35;


// Always assume 20% reflection right off the bat, and make the fresnel fade out slower so there is more refraction overall
fresnel *= fresnel * fresnel;
fresnel = (0.8 * fresnel + 0.2) * col.a;


// Calculate the initial material color
o.Albedo = lerp(refraction, reflection, fresnel) + foam;

// Calculate the amount of illumination that the pixel has received already
// Foam is counted at 50% to make it more visible at night
fresnel = min(1.0, fresnel + foam * 0.5);
o.Emission = o.Albedo * (1.0 - fresnel);

// Set the final color
#ifdef USING_DIRECTIONAL_LIGHT
o.Albedo *= fresnel;
#else
// Setting it directly using the equals operator causes the shader to be "optimized" and break
o.Albedo = lerp(o.Albedo.r, 1.0, 1.0);
#endif
}
ENDCG
}

//==============================================================================================
// Refraction, but no reflection
//==============================================================================================


SubShader
{
Lod 300
Tags { "Queue" = "Transparent-10" }

GrabPass
{
Name "BASE"
Tags { "LightMode" = "Always" }
}


Blend Off
ZTest LEqual
ZWrite Off


CGPROGRAM
#pragma surface surf PPL vertex:vert noambient

sampler2D _GrabTexture : register(s0);
sampler2D _ReflectionTex;
samplerCUBE _Cube;


uniform half4 _GrabTexture_TexelSize;


struct Input
{
float4 position  : POSITION;
float3 worldPos  : TEXCOORD2;// Used to calculate the texture UVs and world view vector
float4 proj0   : TEXCOORD3; // Used for depth and reflection textures
float4 proj1 : TEXCOORD4; // Used for the refraction texture
};

void vert (inout appdata_full v, out Input o)
{
o.worldPos = v.vertex.xyz;
o.position = mul(UNITY_MATRIX_MVP, v.vertex);
o.proj0 = ComputeScreenPos(o.position);
COMPUTE_EYEDEPTH(o.proj0.z);

o.proj1 = o.proj0;
#if UNITY_UV_STARTS_AT_TOP
o.proj1.y = (o.position.w - o.position.y) * 0.5;
#endif
}

void surf (Input IN, inout SurfaceOutput o)
{
// Calculate the world-space view direction (Y-up)
// We can't use IN.viewDir because it takes the object's rotation into account, and the water should not.
float3 worldView = (IN.worldPos - _WorldSpaceCameraPos);

// Calculate the object-space normal (Z-up)
float offset = _Time.x * 0.5;
half2 tiling = IN.worldPos.xz * _Tiling;
half4 nmap = (tex2D(_WaterTex, tiling + offset) + tex2D(_WaterTex, half2(-tiling.y, tiling.x) - offset)) * 0.5;
o.Normal = nmap.xyz * 2.0 - 1.0;


// World space normal (Y-up)
half3 worldNormal = o.Normal.xzy;
worldNormal.z = -worldNormal.z;

// Calculate the depth difference at the current pixel
float depth = tex2Dproj(_CameraDepthTexture, IN.proj0).r;
depth = LinearEyeDepth(depth);
depth -= IN.proj0.z;

// Calculate the depth ranges (X = Alpha, Y = Color Depth)
half3 ranges = saturate(_InvRanges.xyz * depth);
ranges.y = 1.0 - ranges.y;
ranges.y = lerp(ranges.y, ranges.y * ranges.y * ranges.y, 0.5);

// Calculate the color tint
half4 col;
col.rgb = lerp(_Color1.rgb, _Color0.rgb, ranges.y);
col.a = ranges.x;

// Initial material properties
o.Alpha = col.a;
o.Specular = col.a;
o.Gloss = _Shininess;

// Dot product for fresnel effect
half fresnel = sqrt(1.0 - dot(-normalize(worldView), worldNormal));

// Low-quality reflection uses the cube map
half3 reflection = texCUBE(_Cube, reflect(worldView, worldNormal)).rgb * _ReflectionTint;


// High-quality refraction uses the grab pass texture
IN.proj1.xy += o.Normal.xy * _GrabTexture_TexelSize.xy * (20.0 * IN.proj1.z * col.a);
half3 refraction = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(IN.proj1)).rgb;
refraction = lerp(refraction, refraction * col.rgb, ranges.z);


// Color the refraction based on depth
refraction = lerp(lerp(col.rgb, col.rgb * refraction, ranges.y), refraction, ranges.y);

// The amount of foam added (35% of intensity so it's subtle)
half foam = nmap.a * (1.0 - abs(col.a * 2.0 - 1.0)) * 0.35;

// Always assume 20% reflection right off the bat, and make the fresnel fade out slower so there is more refraction overall
fresnel *= fresnel * fresnel;
fresnel = (0.8 * fresnel + 0.2) * col.a;

// Calculate the initial material color
o.Albedo = lerp(refraction, reflection, fresnel) + foam;

// Calculate the amount of illumination that the pixel has received already
// Foam is counted at 50% to make it more visible at night
fresnel = min(1.0, fresnel + foam * 0.5);
o.Emission = o.Albedo * (1.0 - fresnel);

// Set the final color
#ifdef USING_DIRECTIONAL_LIGHT
o.Albedo *= fresnel;
#else
// Setting it directly using the equals operator causes the shader to be "optimized" and break
o.Albedo = lerp(o.Albedo.r, 1.0, 1.0);
#endif
}
ENDCG
}

//==============================================================================================
// No reflection or refraction
//==============================================================================================


SubShader
{
Lod 200
Tags { "Queue" = "Transparent-10" }
Blend SrcAlpha OneMinusSrcAlpha
ZTest LEqual
ZWrite Off


CGPROGRAM
#pragma surface surf PPL vertex:vert noambient


samplerCUBE _Cube;

struct Input
{
float4 position  : POSITION;
float3 worldPos  : TEXCOORD2;// Used to calculate the texture UVs and world view vector
float4 proj0   : TEXCOORD3; // Used for depth and reflection textures
};

void vert (inout appdata_full v, out Input o)
{
o.worldPos = v.vertex.xyz;
o.position = mul(UNITY_MATRIX_MVP, v.vertex);
o.proj0 = ComputeScreenPos(o.position);
COMPUTE_EYEDEPTH(o.proj0.z);
}

void surf (Input IN, inout SurfaceOutput o)
{
// Calculate the world-space view direction (Y-up)
// We can't use IN.viewDir because it takes the object's rotation into account, and the water should not.
float3 worldView = (IN.worldPos - _WorldSpaceCameraPos);

// Calculate the object-space normal (Z-up)
float offset = _Time.x * 0.5;
half2 tiling = IN.worldPos.xz * _Tiling;
half4 nmap = (tex2D(_WaterTex, tiling + offset) + tex2D(_WaterTex, half2(-tiling.y, tiling.x) - offset)) * 0.5;
o.Normal = nmap.xyz * 2.0 - 1.0;

// World space normal (Y-up)
half3 worldNormal = o.Normal.xzy;
worldNormal.z = -worldNormal.z;

// Calculate the depth difference at the current pixel
float depth = tex2Dproj(_CameraDepthTexture, IN.proj0).r;
depth = LinearEyeDepth(depth);
depth -= IN.proj0.z;

// Calculate the depth ranges (X = Alpha, Y = Color Depth)
half3 ranges = saturate(_InvRanges.xyz * depth);
ranges.y = 1.0 - ranges.y;
ranges.y = lerp(ranges.y, ranges.y * ranges.y * ranges.y, 0.5);

// Calculate the color tint
half4 col;
col.rgb = lerp(_Color1.rgb, _Color0.rgb, ranges.y);
col.a = ranges.x;

// Initial material properties
o.Specular = col.a;
o.Gloss = _Shininess;

// Dot product for fresnel effect
half fresnel = sqrt(1.0 - dot(-normalize(worldView), worldNormal));

// Low-quality reflection uses the cube map
half3 reflection = texCUBE(_Cube, reflect(worldView, worldNormal)).rgb * _ReflectionTint;

// No refraction -- just use the color tint
half3 refraction = lerp(col.rgb, col.rgb * col.rgb, ranges.y);
o.Alpha = 1.0 - ranges.y * ranges.y;

// Color the refraction based on depth
refraction = lerp(lerp(col.rgb, col.rgb * refraction, ranges.y), refraction, ranges.y);

// The amount of foam added (35% of intensity so it's subtle)
half foam = nmap.a * (1.0 - abs(col.a * 2.0 - 1.0)) * 0.35;

// Always assume 20% reflection right off the bat, and make the fresnel fade out slower so there is more refraction overall
fresnel *= fresnel * fresnel;
fresnel = (0.8 * fresnel + 0.2) * col.a;


// Calculate the initial material color
o.Albedo = lerp(refraction, reflection, fresnel) + foam;

// Calculate the amount of illumination that the pixel has received already
// Foam is counted at 50% to make it more visible at night
fresnel = min(1.0, fresnel + foam * 0.5);
o.Emission = o.Albedo * (1.0 - fresnel);

// Set the final color
#ifdef USING_DIRECTIONAL_LIGHT
o.Albedo *= fresnel;
#else
// Setting it directly using the equals operator causes the shader to be "optimized" and break
o.Albedo = lerp(o.Albedo.r, 1.0, 1.0);
#endif
}
ENDCG
}

//==============================================================================================
// Unity Free-compatible shader
//==============================================================================================


SubShader
{
Lod 100
Tags { "Queue" = "Transparent-10" }
Blend SrcAlpha OneMinusSrcAlpha
ZTest LEqual
ZWrite Off


CGPROGRAM
#pragma surface surf PPL vertex:vert noambient


samplerCUBE _Cube;

struct Input
{
float4 position  : POSITION;
float3 worldPos  : TEXCOORD2;// Used to calculate the texture UVs and world view vector
};

void vert (inout appdata_full v, out Input o)
{
o.worldPos = v.vertex.xyz;
o.position = mul(UNITY_MATRIX_MVP, v.vertex);
}

void surf (Input IN, inout SurfaceOutput o)
{
// Calculate the world-space view direction (Y-up)
// We can't use IN.viewDir because it takes the object's rotation into account, and the water should not.
float3 worldView = (IN.worldPos - _WorldSpaceCameraPos);

// Calculate the object-space normal (Z-up)
float offset = _Time.x * 0.5;
half2 tiling = IN.worldPos.xz * _Tiling;
half4 nmap = (tex2D(_WaterTex, tiling + offset) + tex2D(_WaterTex, half2(-tiling.y, tiling.x) - offset)) * 0.5;
o.Normal = nmap.xyz * 2.0 - 1.0;

// World space normal (Y-up)
half3 worldNormal = o.Normal.xzy;
worldNormal.z = -worldNormal.z;

// Calculate the color tint
half4 col;
col.rgb = lerp(_Color1.rgb, _Color0.rgb, 0.5);

// Initial material properties
o.Specular = 1.0;
o.Gloss = _Shininess;

// Dot product for fresnel effect
half fresnel = dot(-normalize(worldView), worldNormal);
fresnel *= fresnel;

// Low-quality reflection uses the cube map
half3 reflection = texCUBE(_Cube, reflect(worldView, worldNormal)).rgb * _ReflectionTint;

// No refraction -- just use the color tint
half3 refraction = col.rgb * col.rgb;
o.Alpha = lerp(1.0, 0.75, fresnel);


// Calculate the initial material color
o.Albedo = lerp(reflection, refraction, fresnel);

// Calculate the amount of illumination that the pixel has received already
o.Emission = o.Albedo * fresnel;

// Set the final color
#ifdef USING_DIRECTIONAL_LIGHT
o.Albedo *= 1.0 - fresnel;
#else
// Setting it directly using the equals operator causes the shader to be "optimized" and break
o.Albedo = lerp(o.Albedo.r, 1.0, 1.0);
#endif
}
ENDCG
}
Fallback Off
}


Script:

using UnityEngine;
using System.Collections;


/// <summary>
/// Tasharen Water -- started with the Unity's built-in water, with refraction logic replaced by GrabPass.
/// </summary>


[ExecuteInEditMode]
[RequireComponent(typeof(Renderer))]
[AddComponentMenu("Tasharen/Water")]
public class TasharenWater : MonoBehaviour
{
public enum Quality
{
Fastest, // No refraction, skybox reflection
Low, // Refraction, skybox reflection
Medium, // Refraction, 512 reflection reflecting ships
High, // Refraction, 512 reflection reflecting everything
Uber, // Refraction, 1024 reflection reflecting everything
}


/// <summary>
/// Active quality level.
/// </summary>


public Quality quality = Quality.High;


/// <summary>
/// Reflection mask used when the quality is "High" or above.
/// </summary>


public LayerMask highReflectionMask = -1;


/// <summary>
/// Reflection mask used when the quality is set to "Medium".
/// </summary>


public LayerMask mediumReflectionMask = -1;


/// <summary>
/// Whether to always reposition the water, always keeping it underneath the main camera.
/// </summary>


public bool keepUnderCamera = true;


/// <summary>
/// Quality of the water.
/// </summary>


Transform mTrans;
Hashtable mCameras = new Hashtable();
RenderTexture mTex = null;
int mTexSize = 0;
Renderer mRen;


// Whether rendering is already in progress (stops recursive rendering)
static bool mIsRendering = false;


/// <summary>
/// Return the texture size we should be using for reflection.
/// </summary>


public int reflectionTextureSize
{
get
{
switch (quality)
{
case Quality.Uber: return 1024;
case Quality.High:
case Quality.Medium: return 512;
}
return 0;
}
}


/// <summary>
/// Return the reflection layer mask we should be using.
/// </summary>


public LayerMask reflectionMask
{
get
{
switch (quality)
{
case Quality.Uber:
case Quality.High: return highReflectionMask;
case Quality.Medium: return mediumReflectionMask;
}
return 0;
}
}


/// <summary>
/// Whether refraction will be used.
/// </summary>


public bool useRefraction { get { return (int)quality > (int)Quality.Fastest; } }


/// <summary>
/// Extended sign: returns -1, 0 or 1
/// </summary>


static float SignExt (float a)
{
if (a > 0.0f) return 1.0f;
if (a < 0.0f) return -1.0f;
return 0.0f;
}


/// <summary>
/// Adjusts the given projection matrix so that near plane is the given clipPlane
/// clipPlane is given in camera space. See article in Game Programming Gems 5 and
/// http://aras-p.info/texts/obliqueortho.html
/// </summary>


static void CalculateObliqueMatrix (ref Matrix4x4 projection, Vector4 clipPlane)
{
Vector4 q = projection.inverse * new Vector4(SignExt(clipPlane.x), SignExt(clipPlane.y), 1.0f, 1.0f);
Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));


// third row = clip plane - fourth row
projection[2] = c.x - projection[3];
projection[6] = c.y - projection[7];
projection[10] = c.z - projection[11];
projection[14] = c.w - projection[15];
}


/// <summary>
/// Calculates reflection matrix around the given plane.
/// </summary>


static void CalculateReflectionMatrix (ref Matrix4x4 reflectionMat, Vector4 plane)
{
reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
reflectionMat.m01 = (-2F * plane[0] * plane[1]);
reflectionMat.m02 = (-2F * plane[0] * plane[2]);
reflectionMat.m03 = (-2F * plane[3] * plane[0]);


reflectionMat.m10 = (-2F * plane[1] * plane[0]);
reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
reflectionMat.m12 = (-2F * plane[1] * plane[2]);
reflectionMat.m13 = (-2F * plane[3] * plane[1]);


reflectionMat.m20 = (-2F * plane[2] * plane[0]);
reflectionMat.m21 = (-2F * plane[2] * plane[1]);
reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
reflectionMat.m23 = (-2F * plane[3] * plane[2]);


reflectionMat.m30 = 0F;
reflectionMat.m31 = 0F;
reflectionMat.m32 = 0F;
reflectionMat.m33 = 1F;
}


/// <summary>
/// Get the saved quality level for water.
/// </summary>


static public Quality GetQuality ()
{
Quality q = (Quality)PlayerPrefs.GetInt("Water", (int)Quality.High);
return q;
}


/// <summary>
/// Set the water quality, saving it in player prefs as well.
/// </summary>


static public void SetQuality (Quality q)
{
TasharenWater[] wws = FindObjectsOfType(typeof(TasharenWater)) as TasharenWater[];
if (wws.Length > 0) foreach (TasharenWater ww in wws) ww.quality = q;
else PlayerPrefs.SetInt("Water", (int)q);
}


/// <summary>
/// Caching is always a good idea.
/// </summary>


void Awake ()
{
mTrans = transform;
mRen = GetComponent<Renderer>();
quality = GetQuality();
}


/// <summary>
/// Cleanup all the objects we possibly have created.
/// </summary>


void OnDisable ()
{
Clear();
foreach (DictionaryEntry kvp in mCameras) DestroyImmediate(((Camera)kvp.Value).gameObject);
mCameras.Clear();
}


/// <summary>
/// Release the texture and the temporary cameras
/// </summary>


void Clear ()
{
if (mTex)
{
DestroyImmediate(mTex);
mTex = null;
}
}


/// <summary>
/// Copy camera settings from source to destination.
/// </summary>


void CopyCamera (Camera src, Camera dest)
{
if (src.clearFlags == CameraClearFlags.Skybox)
{
Skybox sky = src.GetComponent<Skybox>();
Skybox mysky = dest.GetComponent<Skybox>();


if (!sky || !sky.material)
{
mysky.enabled = false;
}
else
{
mysky.enabled = true;
mysky.material = sky.material;
}
}


dest.clearFlags = src.clearFlags;
dest.backgroundColor = src.backgroundColor;
dest.farClipPlane = src.farClipPlane;
dest.nearClipPlane = src.nearClipPlane;
dest.orthographic = src.orthographic;
dest.fieldOfView = src.fieldOfView;
dest.aspect = src.aspect;
dest.orthographicSize = src.orthographicSize;
dest.depthTextureMode = DepthTextureMode.None;
dest.renderingPath = RenderingPath.Forward;
}


/// <summary>
/// Get or create the camera used for reflection.
/// </summary>


Camera GetReflectionCamera (Camera current, Material mat, int textureSize)
{
if (!mTex || mTexSize != textureSize)
{
if (mTex) DestroyImmediate(mTex);
mTex = new RenderTexture(textureSize, textureSize, 16);
mTex.name = "__MirrorReflection" + GetInstanceID();
mTex.isPowerOfTwo = true;
mTex.hideFlags = HideFlags.DontSave;
mTexSize = textureSize;
}


Camera cam = mCameras[current] as Camera;


if (!cam)
{
GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + current.GetInstanceID(), typeof(Camera), typeof(Skybox));
go.hideFlags = HideFlags.HideAndDontSave;


cam = go.GetComponent<Camera>();
cam.enabled = false;


Transform t = cam.transform;
t.position = mTrans.position;
t.rotation = mTrans.rotation;


cam.gameObject.AddComponent<FlareLayer>();
mCameras[current] = cam;
}


// Automatically update the reflection texture
if (mat.HasProperty("_ReflectionTex")) mat.SetTexture("_ReflectionTex", mTex);
return cam;
}


/// <summary>
/// Given position/normal of the plane, calculates plane in camera space.
/// </summary>


Vector4 CameraSpacePlane (Camera cam, Vector3 pos, Vector3 normal, float sideSign)
{
Matrix4x4 m = cam.worldToCameraMatrix;
Vector3 cpos = m.MultiplyPoint(pos);
Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
}


/// <summary>
/// Keep the water underneath the camera.
/// </summary>


void LateUpdate ()
{
#if UNITY_EDITOR
if (keepUnderCamera && Application.isPlaying)
#else
if (keepUnderCamera)
#endif
{
Transform camTrans = Camera.main.transform;
Vector3 cp = camTrans.position;
cp.y = mTrans.position.y;
if (mTrans.position != cp) mTrans.position = cp;
}
}


/// <summary>
/// Called when the object is being renderered.
/// </summary>


void OnWillRenderObject ()
{
// Safeguard from recursive reflections
if (mIsRendering) return;


if (!enabled || !mRen || !mRen.enabled)
{
Clear();
return;
}


Material mat = mRen.sharedMaterial;
if (!mat) return;


#if UNITY_IPHONE || UNITY_ANDROID
// Mobile platforms can only do the lowest possible quality
quality = Quality.Fastest;
mat.shader.maximumLOD = 100;
#else


#if UNITY_EDITOR
mat.shader.maximumLOD = 700;
#endif
Camera cam = Camera.current;
if (!cam) return;


// Depth texture is always needed for water as we used to to calculate the color (at the very least)
bool imageEffects = SystemInfo.supportsImageEffects;
if (imageEffects) cam.depthTextureMode |= DepthTextureMode.Depth;
else quality = Quality.Fastest;


// No refraction also means no reflection -- lowest quality level
if (!useRefraction)
{
mat.shader.maximumLOD = imageEffects ? 200 : 100;
Clear();
return;
}


// Don't try to do anything else if the reflections have been turned off
LayerMask mask = reflectionMask;
int textureSize = reflectionTextureSize;


if (mask == 0 || textureSize < 512)
{
// No reflection
mat.shader.maximumLOD = 300;
Clear();
}
else
{
// Refraction and reflection -- we first need to create the reflection texture
mat.shader.maximumLOD = 400;
mIsRendering = true;


// Get the reflection camera for the specified game camera (ie: main camera or scene view camera)
Camera reflectionCamera = GetReflectionCamera(cam, mat, textureSize);


// find out the reflection plane: position and normal in world space
Vector3 pos = mTrans.position;
Vector3 normal = mTrans.up;


CopyCamera(cam, reflectionCamera);


// Reflect camera around the reflection plane
float d = -Vector3.Dot(normal, pos);
Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);
Matrix4x4 reflection = Matrix4x4.zero;


CalculateReflectionMatrix(ref reflection, reflectionPlane);


Vector3 oldpos = cam.transform.position;
Vector3 newpos = reflection.MultiplyPoint(oldpos);
reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;


// Setup oblique projection matrix so that near plane is our reflection
// plane. This way we clip everything below/above it for free.
Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f);
Matrix4x4 projection = cam.projectionMatrix;


CalculateObliqueMatrix(ref projection, clipPlane);


reflectionCamera.projectionMatrix = projection;
reflectionCamera.cullingMask = ~(1 << 4) & mask.value;
reflectionCamera.targetTexture = mTex;


GL.SetRevertBackfacing(true);
{
reflectionCamera.transform.position = newpos;
Vector3 euler = cam.transform.eulerAngles;
reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);
reflectionCamera.Render();
reflectionCamera.transform.position = oldpos;
}
GL.SetRevertBackfacing(false);
mIsRendering = false;
}
#endif
}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值