Unity3d 镜面反射 vertex and frag Shader源码

时间:2021-06-25 04:14:28

Unity3d 镜面反射 

网上能找到的基本上是固定管道或表面渲染的shader,

特此翻译为顶点、片段渲染的Shader,

本源码只涉及shader与cs部分,

Editor部分使用NGUI绘制的,

请自行下载NGUI 

unity3d 版本:v4.3.1

ReflectionMirror.cs

using UnityEngine;
using System.Collections;
using System;

/// <summary>
/// 反射效果
/// </summary>
[AddComponentMenu("GameCore/SpecialEffect/Reflection Mirror")]
[ExecuteInEditMode]
public class ReflectionMirror : MonoBehaviour
{
public bool DisablePixelLights = true;
public int TextureSize = 512;
public float ClipPlaneOffset = 0;
public LayerMask ReflectLayers = -1;

private Hashtable m_ReflectionCameras = new Hashtable(); // Camera -> Camera table
private RenderTexture m_ReflectionTexture = null;
private int m_OldReflectionTextureSize = 0;

private static bool s_InsideRendering = false;

// This is called when it's known that the object will be rendered by some
// camera. We render reflections and do other updates here.
// Because the script executes in edit mode, reflections for the scene view
// camera will just work!
public void OnWillRenderObject()
{
if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled)
return;

Camera cam = Camera.current;
if (!cam)
return;

// Safeguard from recursive reflections.
if (s_InsideRendering)
return;
s_InsideRendering = true;

Camera reflectionCamera;
CreateMirrorObjects(cam, out reflectionCamera);

// find out the reflection plane: position and normal in world space
Vector3 pos = transform.position;
Vector3 normal = transform.up;
// Optionally disable pixel lights for reflection
int oldPixelLightCount = QualitySettings.pixelLightCount;
if (DisablePixelLights)
QualitySettings.pixelLightCount = 0;

CoreTool.CloneCameraModes(cam, reflectionCamera);

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


Matrix4x4 reflection = CoreTool.CalculateReflectionMatrix(Matrix4x4.zero, 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 = CoreTool.CameraSpacePlane(reflectionCamera, pos, normal, 1.0f, ClipPlaneOffset);

Matrix4x4 projection = cam.projectionMatrix;

projection = CoreTool.CalculateObliqueMatrix(projection, clipPlane);

reflectionCamera.projectionMatrix = projection;

reflectionCamera.cullingMask = ~(1 << 4) & ReflectLayers.value; // never render water layer
reflectionCamera.targetTexture = m_ReflectionTexture;

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);
Material[] materials = renderer.sharedMaterials;
foreach (Material mat in materials)
{
if (mat.HasProperty("_ReflectionTex"))
mat.SetTexture("_ReflectionTex", m_ReflectionTexture);
}

// Set matrix on the shader that transforms UVs from object space into screen
// space. We want to just project reflection texture on screen.
Matrix4x4 scaleOffset = Matrix4x4.TRS(
new Vector3(0.5f, 0.5f, 0.5f), Quaternion.identity, new Vector3(0.5f, 0.5f, 0.5f));
Vector3 scale = transform.lossyScale;
Matrix4x4 mtx = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
mtx = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * mtx;
foreach (Material mat in materials)
{
mat.SetMatrix("_ProjMatrix", mtx);
}
// Restore pixel light count
if (DisablePixelLights)
QualitySettings.pixelLightCount = oldPixelLightCount;
s_InsideRendering = false;
}


// Cleanup all the objects we possibly have created
void OnDisable()
{
if (m_ReflectionTexture)
{
DestroyImmediate(m_ReflectionTexture);
m_ReflectionTexture = null;
}
foreach (DictionaryEntry kvp in m_ReflectionCameras)
DestroyImmediate(((Camera)kvp.Value).gameObject);
m_ReflectionCameras.Clear();
}

// On-demand create any objects we need
private void CreateMirrorObjects(Camera currentCamera, out Camera reflectionCamera)
{
reflectionCamera = null;

// Reflection render texture
if (!m_ReflectionTexture || m_OldReflectionTextureSize != TextureSize)
{
if (m_ReflectionTexture)
DestroyImmediate(m_ReflectionTexture);
m_ReflectionTexture = new RenderTexture(TextureSize, TextureSize,0);
m_ReflectionTexture.name = "__MirrorReflection" + GetInstanceID();
m_ReflectionTexture.isPowerOfTwo = true;
m_ReflectionTexture.hideFlags = HideFlags.DontSave;
m_ReflectionTexture.antiAliasing = 4;
m_ReflectionTexture.anisoLevel = 0;
m_OldReflectionTextureSize = TextureSize;
}

// Camera for reflection
reflectionCamera = m_ReflectionCameras[currentCamera] as Camera;
if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
{
GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));
reflectionCamera = go.camera;
reflectionCamera.enabled = false;
reflectionCamera.transform.position = transform.position;
reflectionCamera.transform.rotation = transform.rotation;
reflectionCamera.gameObject.AddComponent("FlareLayer");
go.hideFlags = HideFlags.HideAndDontSave;
m_ReflectionCameras[currentCamera] = reflectionCamera;
}
}
}

ReflectionMirrorEditor.cs

using System.Collections;
using System;
using UnityEditor;
using UnityEngine;
/// <summary>
/// 反射效果
/// </summary>
[CustomEditor(typeof(ReflectionMirror))]
public class ReflectionMirrorEditor : Editor
{
string[] _renderTextureOptions = new string[8] { "16", "32", "64", "128", "256", "512", "1024", "2048" };
int _renderTextureWidthDefaultIndex = 5;
int _renderTextureWidthIndex = 5;
SerializedProperty _sp;
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("This the reflection effect,it has mirror or sphere reflection!",MessageType.Info);
if (NGUIEditorTools.DrawHeader("Reflection Settings"))
{
NGUIEditorTools.BeginContents();
{
NGUIEditorTools.DrawProperty("Disable PixelLights", this.serializedObject, "DisablePixelLights");
NGUIEditorTools.DrawProperty("Reflect Layers", this.serializedObject, "ReflectLayers");
NGUIEditorTools.DrawProperty("ClipPlane Offset", this.serializedObject, "ClipPlaneOffset");
}
NGUIEditorTools.EndContents();
}
if (NGUIEditorTools.DrawHeader("Render Texture Settings"))
{
NGUIEditorTools.BeginContents();
{
_sp = this.serializedObject.FindProperty("TextureSize");
_renderTextureWidthIndex = GetTextureOptionsIndex(_sp.intValue.ToString());
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("TexSize:", GUILayout.Width(100));
_renderTextureWidthIndex = EditorGUILayout.Popup(_renderTextureWidthIndex, _renderTextureOptions);
EditorGUILayout.EndHorizontal();

if (GUILayout.Button("Make Default Value"))
{
_renderTextureWidthIndex = _renderTextureWidthDefaultIndex;
}
_sp.intValue = int.Parse(_renderTextureOptions[_renderTextureWidthIndex]);
}
NGUIEditorTools.EndContents();
}

this.serializedObject.ApplyModifiedProperties();
}

int GetTextureOptionsIndex(string value)
{
int index = 0;
for (int i = 0; i < _renderTextureOptions.Length; i++)
{
if (_renderTextureOptions[i].Equals(value, StringComparison.OrdinalIgnoreCase))
{
index = i;
}
}
return index;
}
}

Shader

Shader "GameCore/SpecialEffect/Reflection Mirror"
{
Properties {
_ReflectionTex ("Reflection", 2D) = "white" {TexGen ObjectLinear }
_ReflectionColor("Color",Color) = (1,1,1,1)
}
//PC
SubShader {
Tags {
"RenderType"="Opaque"}
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

uniform float4x4 _ProjMatrix;
uniform sampler2D _ReflectionTex;
float4 _ReflectionColor;
struct outvertex {
float4 pos : SV_POSITION;
float3 uv : TEXCOORD0;
};
outvertex vert(appdata_tan v) {
outvertex o;
o.pos = mul (UNITY_MATRIX_MVP,v.vertex);
float3 viewDir = ObjSpaceViewDir(v.vertex);
o.uv = mul(_ProjMatrix,float4(viewDir,0));
return o;
}

float4 frag(outvertex i) : COLOR {
half4 reflcol = tex2Dproj(_ReflectionTex,i.uv);
return reflcol*_ReflectionColor;
}
ENDCG
}
}
//Mobile
SubShader {
Tags {
"RenderType"="Opaque"}
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

uniform float4x4 _ProjMatrix;
uniform sampler2D _ReflectionTex;
float4 _ReflectionColor;
struct outvertex {
float4 pos : SV_POSITION;
float3 uv : TEXCOORD0;
float4 posProj;
};
outvertex vert(appdata_tan v) {
outvertex o;
o.pos = mul (UNITY_MATRIX_MVP,v.vertex);
o.posProj = mul(_ProjMatrix, v.vertex);
return o;
}
float4 frag(outvertex i) : COLOR {
half4 reflcol = tex2D(_ReflectionTex,float2(i.posProj) / i.posProj.w);
return reflcol*_ReflectionColor;
}
ENDCG
}
}
}

源码链接: http://pan.baidu.com/s/1gdyzyNL