Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikibooksThe Free Textbook Project
Search

Cg Programming/Unity/Water Reflection and Refraction

From Wikibooks, open books for an open world
<Cg Programming |Unity
This page or section is an undeveloped draft or outline.
You can help todevelop the work, or you can ask for assistance in theproject room.
usingUnityEngine;usingSystem.Collections;usingSystem;usingSystem.Collections.Generic;/// <summary>/// 水面/// </summary>[AddComponentMenu("GameCore/Effect/Water/Water (Base)")][ExecuteInEditMode]publicclassWater:MonoBehaviour{publicenumFlageWaterRefType{Both=0,Reflection=1,Refraction=2}publicboolDisablePixelLights=false;publicLayerMaskLayers=-1;publicintTexSize=512;publicFlageWaterRefTypeRefType=FlageWaterRefType.Both;publicfloatReflectClipPlaneOffset=0;publicfloatRefractionAngle=0;privatestaticCamera_reflectionCamera;privatestaticCamera_refractionCamera;privateint_OldTexSize=0;privateRenderTexture_reflectionRenderTex;privateRenderTexture_refractionRenderTex;privatebool_insideRendering=false;privatefloat_refType=(float)FlageWaterRefType.Both;voidOnWillRenderObject(){if(!enabled||!renderer||!renderer.sharedMaterial||!renderer.enabled)return;Cameracam=Camera.current;if(!cam)return;Material[]materials=renderer.sharedMaterials;if(_insideRendering)return;_insideRendering=true;intoldPixelLightCount=QualitySettings.pixelLightCount;if(DisablePixelLights)QualitySettings.pixelLightCount=0;if(RefType==FlageWaterRefType.Both||RefType==FlageWaterRefType.Reflection){DrawReflectionRenderTexture(cam);foreach(Materialmatinmaterials){if(mat.HasProperty("_ReflectionTex"))mat.SetTexture("_ReflectionTex",_reflectionRenderTex);}}if(RefType==FlageWaterRefType.Both||RefType==FlageWaterRefType.Refraction){this.gameObject.layer=4;DrawRefractionRenderTexture(cam);foreach(Materialmatinmaterials){if(mat.HasProperty("_RefractionTex"))mat.SetTexture("_RefractionTex",_refractionRenderTex);}}_refType=(float)RefType;Matrix4x4projmtx=CoreTool.UV_Tex2DProj2Tex2D(transform,cam);foreach(Materialmatinmaterials){mat.SetMatrix("_ProjMatrix",projmtx);mat.SetFloat("_RefType",_refType);}if(DisablePixelLights)QualitySettings.pixelLightCount=oldPixelLightCount;_insideRendering=false;}/// <summary>/// 绘制反射RenderTexture/// </summary>privatevoidDrawReflectionRenderTexture(Cameracam){Vector3pos=transform.position;Vector3normal=transform.up;CreateObjects(cam,ref_reflectionRenderTex,ref_reflectionCamera);CoreTool.CloneCameraModes(cam,_reflectionCamera);floatd=-Vector3.Dot(normal,pos)-ReflectClipPlaneOffset;Vector4reflectionPlane=newVector4(normal.x,normal.y,normal.z,d);Matrix4x4reflection=CoreTool.CalculateReflectionMatrix(Matrix4x4.zero,reflectionPlane);Vector3oldpos=cam.transform.position;Vector3newpos=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.Vector4clipPlane=CoreTool.CameraSpacePlane(_reflectionCamera,pos,normal,1.0f,ReflectClipPlaneOffset);Matrix4x4projection=cam.projectionMatrix;projection=CoreTool.CalculateObliqueMatrix(projection,clipPlane,-1);_reflectionCamera.projectionMatrix=projection;_reflectionCamera.cullingMask=~(1<<4)&Layers.value;// never render water layer_reflectionCamera.targetTexture=_reflectionRenderTex;GL.SetRevertBackfacing(true);_reflectionCamera.transform.position=newpos;Vector3euler=cam.transform.eulerAngles;_reflectionCamera.transform.eulerAngles=newVector3(0,euler.y,euler.z);_reflectionCamera.Render();_reflectionCamera.transform.position=oldpos;GL.SetRevertBackfacing(false);}/// <summary>/// 绘制折射RenderTexture/// </summary>privatevoidDrawRefractionRenderTexture(Cameracam){CreateObjects(cam,ref_refractionRenderTex,ref_refractionCamera);CoreTool.CloneCameraModes(cam,_refractionCamera);Vector3pos=transform.position;Vector3normal=transform.up;Matrix4x4projection=cam.worldToCameraMatrix;projection*=Matrix4x4.Scale(newVector3(1,Mathf.Clamp(1-RefractionAngle,0.001f,1),1));_refractionCamera.worldToCameraMatrix=projection;Vector4clipPlane=CoreTool.CameraSpacePlane(_refractionCamera,pos,normal,1.0f,0);projection=cam.projectionMatrix;projection[2]=clipPlane.x+projection[3];//xprojection[6]=clipPlane.y+projection[7];//yprojection[10]=clipPlane.z+projection[11];//zprojection[14]=clipPlane.w+projection[15];//w_refractionCamera.projectionMatrix=projection;_refractionCamera.cullingMask=~(1<<4)&Layers.value;// never render water layer_refractionCamera.targetTexture=_refractionRenderTex;_refractionCamera.transform.position=cam.transform.position;_refractionCamera.transform.eulerAngles=cam.transform.eulerAngles;_refractionCamera.Render();}voidOnDisable(){if(_reflectionRenderTex){DestroyImmediate(_reflectionRenderTex);_reflectionRenderTex=null;}if(_reflectionCamera){DestroyImmediate(_reflectionCamera.gameObject);_reflectionCamera=null;}if(_refractionRenderTex){DestroyImmediate(_refractionRenderTex);_refractionRenderTex=null;}if(_refractionCamera){DestroyImmediate(_refractionCamera.gameObject);_refractionCamera=null;}}voidCreateObjects(CamerasrcCam,refRenderTexturerenderTex,refCameradestCam){// Reflection render textureif(!renderTex||_OldTexSize!=TexSize){if(renderTex)DestroyImmediate(renderTex);renderTex=newRenderTexture(TexSize,TexSize,0);renderTex.name="__RefRenderTexture"+renderTex.GetInstanceID();renderTex.isPowerOfTwo=true;renderTex.hideFlags=HideFlags.DontSave;renderTex.antiAliasing=4;renderTex.anisoLevel=0;_OldTexSize=TexSize;}if(!destCam)// catch both not-in-dictionary and in-dictionary-but-deleted-GO{GameObjectgo=newGameObject("__RefCamera for "+srcCam.GetInstanceID(),typeof(Camera),typeof(Skybox));destCam=go.camera;destCam.enabled=false;destCam.transform.position=transform.position;destCam.transform.rotation=transform.rotation;destCam.gameObject.AddComponent("FlareLayer");go.hideFlags=HideFlags.HideAndDontSave;}}}
usingUnityEngine;usingSystem.Collections;usingSystem;usingUnityEditor;[CustomEditor(typeof(Water))]publicclassWaterEditor:Editor{GUIContent[]_renderTextureOptions=newGUIContent[8]{newGUIContent("16"),newGUIContent("32"),newGUIContent("64"),newGUIContent("128"),newGUIContent("256"),newGUIContent("512"),newGUIContent("1024"),newGUIContent("2048")};int[]_renderTextureSize=newint[8]{16,32,64,128,256,512,1024,2048};publicoverridevoidOnInspectorGUI(){Waterwater=targetasWater;EditorGUILayout.PropertyField(this.serializedObject.FindProperty("RefType"),newGUIContent("RefType"));EditorGUILayout.PropertyField(this.serializedObject.FindProperty("DisablePixelLights"),newGUIContent("DisablePixelLights"));EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Layers"),newGUIContent("Layers"));EditorGUILayout.IntPopup(this.serializedObject.FindProperty("TexSize"),_renderTextureOptions,_renderTextureSize,newGUIContent("TexSize"));if(NGUIEditorTools.DrawHeader("Reflect Settings")){NGUIEditorTools.BeginContents();{EditorGUILayout.Slider(this.serializedObject.FindProperty("ReflectClipPlaneOffset"),0,0.1f,newGUIContent("ClipPlane Offset"));}NGUIEditorTools.EndContents();}if(NGUIEditorTools.DrawHeader("Refraction Settings")){NGUIEditorTools.BeginContents();{EditorGUILayout.Slider(this.serializedObject.FindProperty("RefractionAngle"),0,1,newGUIContent("Refraction Angle"));}NGUIEditorTools.EndContents();}this.serializedObject.ApplyModifiedProperties();}}
usingSystem.Collections;usingSystem;usingUnityEngine;/// <summary>/// 工具类/// </summary>publicstaticclassCoreTool{#region Config配置/// <summary>/// 验证当前文件是否为配置文件/// </summary>/// <param name="filePath">文件路径</param>/// <returns></returns>publicstaticboolIsConfig(stringfilePath){returntrue;}#endregion#region Camera/// <summary>/// 将源摄像机状态克隆到目标相机/// </summary>/// <param name="src">源相机</param>/// <param name="dest">目标相机</param>publicstaticvoidCloneCameraModes(Camerasrc,Cameradest){if(dest==null)return;// set camera to clear the same way as current cameradest.clearFlags=src.clearFlags;dest.backgroundColor=src.backgroundColor;if(src.clearFlags==CameraClearFlags.Skybox){Skyboxsky=src.GetComponent(typeof(Skybox))asSkybox;Skyboxmysky=dest.GetComponent(typeof(Skybox))asSkybox;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.depth=src.depth;dest.farClipPlane=src.farClipPlane;dest.nearClipPlane=src.nearClipPlane;dest.orthographic=src.orthographic;dest.fieldOfView=src.fieldOfView;dest.aspect=src.aspect;dest.orthographicSize=src.orthographicSize;}/// <summary>/// 计算反射矩阵/// </summary>/// <param name="reflectionMat">原始矩阵</param>/// <param name="plane">反射平面</param>/// <returns>反射矩阵</returns>publicstaticMatrix4x4CalculateReflectionMatrix(Matrix4x4reflectionMat,Vector4plane){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;returnreflectionMat;}/// <summary>/// 计算指定平面在摄像机中的空间位置/// </summary>/// <param name="cam">摄像机</param>/// <param name="pos">平面上的点</param>/// <param name="normal">平面法线</param>/// <param name="sideSign">1:平面正面,-1:平面反面</param>/// <param name="clipPlaneOffset">平面法线位置偏移量</param>/// <returns></returns>publicstaticVector4CameraSpacePlane(Cameracam,Vector3pos,Vector3normal,floatsideSign,floatclipPlaneOffset){Vector3offsetPos=pos+normal*clipPlaneOffset;Matrix4x4m=cam.worldToCameraMatrix;Vector3cpos=m.MultiplyPoint(offsetPos);Vector3cnormal=m.MultiplyVector(normal).normalized*sideSign;returnnewVector4(cnormal.x,cnormal.y,cnormal.z,-Vector3.Dot(cpos,cnormal));}/// <summary>/// 由剪裁面计算投影倾斜矩阵/// </summary>/// <param name="projection">投影矩阵</param>/// <param name="clipPlane">剪裁面</param>/// <param name="sideSign">剪裁平面(-1:平面下面,1:平面上面)</param>publicstaticMatrix4x4CalculateObliqueMatrix(Matrix4x4projection,Vector4clipPlane,floatsideSign){Vector4q=projection.inverse*newVector4(sgn(clipPlane.x),sgn(clipPlane.y),1.0f,1.0f);Vector4c=clipPlane*(2.0F/(Vector4.Dot(clipPlane,q)));// third row = clip plane - fourth rowprojection[2]=c.x+Mathf.Sign(sideSign)*projection[3];projection[6]=c.y+Mathf.Sign(sideSign)*projection[7];projection[10]=c.z+Mathf.Sign(sideSign)*projection[11];projection[14]=c.w+Mathf.Sign(sideSign)*projection[15];returnprojection;}privatestaticfloatsgn(floata){if(a>0.0f)return1.0f;if(a<0.0f)return-1.0f;return0.0f;}/// <summary>/// 由水平、垂直距离修改倾斜矩阵/// </summary>/// <param name="projMatrix">倾斜矩阵</param>/// <param name="horizObl">水平方向</param>/// <param name="vertObl">垂直方向</param>/// <returns>修改后的倾斜矩阵</returns>publicstaticMatrix4x4CalculateObliqueMatrix(Matrix4x4projMatrix,floathorizObl,floatvertObl){Matrix4x4mat=projMatrix;mat[0,2]=horizObl;mat[1,2]=vertObl;returnmat;}#endregion#region Shader Matrix4x4/// <summary>/// tex2DProj到tex2D的uv纹理转换矩阵/// 在shader中,/// vert=>o.posProj = mul(_ProjMatrix, v.vertex);/// frag=>tex2D(_RefractionTex,float2(i.posProj) / i.posProj.w)/// </summary>/// <param name="transform">要显示纹理的对象</param>/// <param name="cam">当前观察的摄像机</param>/// <returns>返回转换矩阵</returns>publicstaticMatrix4x4UV_Tex2DProj2Tex2D(Transformtransform,Cameracam){Matrix4x4scaleOffset=Matrix4x4.TRS(newVector3(0.5f,0.5f,0.5f),Quaternion.identity,newVector3(0.5f,0.5f,0.5f));Vector3scale=transform.lossyScale;Matrix4x4_ProjMatrix=transform.localToWorldMatrix*Matrix4x4.Scale(newVector3(1.0f/scale.x,1.0f/scale.y,1.0f/scale.z));_ProjMatrix=scaleOffset*cam.projectionMatrix*cam.worldToCameraMatrix*_ProjMatrix;return_ProjMatrix;}#endregion}
Shader"GameCore/Mobile/Water/Diffuse"{Properties{_ReflectionTex("Reflection",2D)="white"{}_RefractionTex("Refraction",2D)="white"{}_RefColor("Color",Color)=(1,1,1,1)}SubShader{Tags{"RenderType"="Opaque"}LOD100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include"UnityCG.cginc"uniformfloat4x4_ProjMatrix;uniformfloat_RefType;sampler2D_ReflectionTex;sampler2D_RefractionTex;float4_RefColor;structoutvertex{float4pos:SV_POSITION;float4uv0:TEXCOORD0;float4refparam:COLOR0;//r:fresnel,g:none,b:none,a:none};outvertexvert(appdata_tanv){outvertexo;o.pos=mul(UNITY_MATRIX_MVP,v.vertex);float4posProj=mul(_ProjMatrix,v.vertex);o.uv0=posProj;float3r=normalize(ObjSpaceViewDir(v.vertex));floatd=saturate(dot(r,normalize(v.normal)));//r+(1-r)*pow(d,5)o.refparam=float4(d,0,0,0);returno;}float4frag(outvertexi):COLOR{half4flecol=tex2D(_ReflectionTex,float2(i.uv0)/i.uv0.w);half4fracol=tex2D(_RefractionTex,float2(i.uv0)/i.uv0.w);half4outcolor=half4(1,1,1,1);if(_RefType==0){outcolor=lerp(flecol,fracol,i.refparam.r);}elseif(_RefType==1){outcolor=flecol;}elseif(_RefType==2){outcolor=fracol;}returnoutcolor*_RefColor;}ENDCG}}}
Retrieved from "https://en.wikibooks.org/w/index.php?title=Cg_Programming/Unity/Water_Reflection_and_Refraction&oldid=2667201"
Category:
Hidden category:

[8]ページ先頭

©2009-2025 Movatter.jp