纳金网

标题: unity3d制作镜面反射脚本 [打印本页]

作者: yeu1233    时间: 2012-8-24 11:41
标题: unity3d制作镜面反射脚本
这里面我转一个镜面反射,再阐述一些遇到的问题,先建立以个Shader,名字可以叫做MirrorReflection,脚本如下:

Shader "FX/Mirror Reflection"

{Properties

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

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

}



        // two texture cards: full thing

Subshader

{Pass

         {SetTexture[_MainTex]{combine texture}

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

  }

}



        // fallback: just main texture

        Subshader

{Pass

  {SetTexture [_MainTex]{combine texture}

  }

        }

}



在建立一个cs脚本,名字叫做MirrorReflection,脚本如下:

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

}



//围绕给定的平面计算折射矩阵

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;

        }

}



作者: humazi    时间: 2014-7-8 15:11
研究下。。。。。。
作者: HIDEOKOJIMA    时间: 2014-7-8 15:50
研究下。。。。。。
作者: xinghonggz    时间: 2014-7-8 17:36
研究下。。。。。。




欢迎光临 纳金网 (http://www.narkii.com/club/) Powered by Discuz! X2.5