查看: 1595|回复: 0
打印 上一主题 下一主题

反射的制作过程

[复制链接]

5552

主题

2

听众

8万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
11

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2012-2-23 15:19:49 |只看该作者 |倒序浏览
先写一个c#脚本,代码如下
using UnityEngine;

using System.Collections;
// This is in fact just the Water script from Pro Standard Assets,

// just with refraction stuff removed.
[ExecuteInEditMode] // Make mirror live-update even when not in play mode

public class MirrorReflection : MonoBehaviour

{

public bool m_DisablePixelLights = ***e;

public int m_TextureSize = 256;

public float m_ClipPlaneOffset = 0.07f;
public LayerMask m_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***cutes 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 = ***e;
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( m_DisablePixelLights )

QualitySettings.pixelLightCount = 0;
UpdateCameraModes( cam, reflectionCamera );
// Render reflection

// Reflect camera around reflection plane

float d = -Vector3.Dot (normal, pos) - m_ClipPlaneOffset;

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) & m_ReflectLayers.value; // never render water layer

reflectionCamera.targetTexture = m_ReflectionTexture;

GL.SetRevertBackfacing (***e);

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( m_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();

}
private void UpdateCameraModes( Camera src, Camera dest )

{

if( dest == null )

return;

// set camera to clear the same way as current camera

dest.clearFlags = src.clearFlags;

dest.backgroundColor = src.backgroundColor;

if( src.clearFlags == CameraClearFlags.Skybox )

{

Skybox sky = src.GetComponent(typeof(Skybox)) as Skybox;

Skybox mysky = dest.GetComponent(typeof(Skybox)) as Skybox;

if( !sky || !sky.material )

{

mysky.enabled = false;

}

else

{

mysky.enabled = ***e;

mysky.material = sky.material;

}

}

// update other values to match current camera.

// even if we are supplying custom camera&projection matrices,

// some of values are used elsewhere (e.g. skybox uses far plane)

dest.farClipPlane = src.farClipPlane;

dest.nearClipPlane = src.nearClipPlane;

dest.orthographic = src.orthographic;

dest.fieldOfView = src.fieldOfView;

dest.aspect = src.aspect;

dest.orthographicSize = src.orthographicSize;

}
// 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 != m_TextureSize )

{

if( m_ReflectionTexture )

DestroyImmediate( m_ReflectionTexture );

m_ReflectionTexture = new RenderTexture( m_TextureSize, m_TextureSize, 16 );

m_ReflectionTexture.name = "__MirrorReflection" + GetInstanceID();

m_ReflectionTexture.isPowerOfTwo = ***e;

m_ReflectionTexture.hideFlags = HideFlags.DontSave;

m_OldReflectionTextureSize = m_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;

}

}
// Extended sign: returns -1, 0 or 1 based on sign of a

private static float sgn(float a)

{

if (a > 0.0f) return 1.0f;

if (a < 0.0f) return -1.0f;

return 0.0f;

}
// Given position/normal of the plane, calculates plane in camera space.

private Vector4 CameraSpacePlane (Camera cam, Vector3 pos, Vector3 normal, float sideSign)

{

Vector3 offsetPos = pos + normal * m_ClipPlaneOffset;

Matrix4x4 m = cam.worldToCameraMatrix;

Vector3 cpos = m.MultiplyPoint( offsetPos );

Vector3 cnormal = m.MultiplyVector( normal ).normalized * sideSign;

return new Vector4( cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos,cnormal) );

}
// 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.

private static void CalculateObliqueMatrix (ref Matrix4x4 projection, Vector4 clipPlane)

{

Vector4 q = projection.inverse * new Vector4(

sgn(clipPlane.x),

sgn(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];

}
// Calculates reflection matrix around the given plane

private 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;

}

}
再创建一个shader脚本,代码如下
Shader "FX/Mirror Blend" {

Properties {

_MainTex ("Base (RGB) RefStrength (A)", 2D) = "white" {}

_ReflectionTex ("Reflection", 2D) = "white" { TexGen ObjectLinear }

}
// two texture cards: full thing

Subshader {

Pass {

SetTexture[_ReflectionTex] { matrix [_ProjMatrix] combine texture }

SetTexture[_MainTex] { combine texture lerp (texture) previous }

}

}
// fallback: just main texture

Subshader {

Pass {

SetTexture [_MainTex] { combine texture }

}

}
}
将两个脚本赋予想要有反射效果的物体就可以实现想要的效果
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2025-2-24 02:47 , Processed in 0.091626 second(s), 32 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部