Unity3D镜子脚本

QQ图片20170601164658.png

出现了这种拉伸的情况

![D5)CNFF)4F0Q)0R`L]SQE.png](http://upload-images.jianshu.io/upload_images/3960890-2e8c818fcbb4816a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

镜子物体本身也是有UV的,拉伸之后到合适位置就显示正常了!!但是!!

但是!!

按理说应该镜子什么比例,都应该反射出的是正常比例的对像=-=!!

所以!!

镜子可以展好UV再给脚本可能合适些=-=!

另外,大神们的建议是!!

镜子烘培时候别开!!
烘培之后在给shader!!
这种真实的镜面反射代表draw calls翻倍!!
镜子反射不剃除,基本就是两倍渲染量!!
最好在脚本里设置一下标签!那些反哪些不反!

网络上转一个镜面反射,先建立一个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=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;
    }
}
图片.png

这么挂脚本!!以及镜子物体选择镜子shader脚本!!

这是官方CharacterCustomization事例中的镜面反射shader。

1.首先需要一个plane当镜子,将代码MirrorReflection.cs文件绑定到镜子上。

2.新建一个材质,绑定到镜子上,选择shader FX/Reflection。

3.TextureSize 越大,越清晰~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容