製作鏡面反射指令碼

來源:互聯網
上載者:User

這裡面我轉一個鏡面反射,再闡述一些遇到的問題,先建立以個Shader,名字可以叫做MirrorReflection,指令碼如下:[javascript]  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,指令碼如下:[csharp]  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=true;  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 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(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(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(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=true;    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=true;    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;          }  }   值得注意的是,地面,或者鏡面盡量用U3d裡面自建的plane,把shader和cs指令碼直接賦予到該plane上就出效果了。其他物體不必賦予。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.