这里只是张贴在实时折射和脚本反思shader,

大约NGUI第一部分请下载。

这个版本的主要缺点是折射平面部Layer必须是water层。假设有专家谁可以摆脱这一个。请记得把代码回该条,谢谢!

Water.cs

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
/// <summary>
/// 水面
/// </summary>
[AddComponentMenu("GameCore/Effect/Water/Water (Base)")]
[ExecuteInEditMode]
public class Water : MonoBehaviour
{
public enum FlageWaterRefType
{
Both = 0,
Reflection = 1,
Refraction = 2
}
public bool DisablePixelLights = false;
public LayerMask Layers = -1;
public int TexSize = 512;
public FlageWaterRefType RefType = FlageWaterRefType.Both;
public float ReflectClipPlaneOffset = 0;
public float RefractionAngle = 0; private static Camera _reflectionCamera;
private static Camera _refractionCamera; private int _OldTexSize = 0;
private RenderTexture _reflectionRenderTex;
private RenderTexture _refractionRenderTex; private bool _insideRendering = false;
private float _refType = (float)FlageWaterRefType.Both; void OnWillRenderObject()
{ if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled)
return;
Camera cam = Camera.current;
if (!cam)
return;
Material[] materials = renderer.sharedMaterials;
if (_insideRendering)
return;
_insideRendering = true;
int oldPixelLightCount = QualitySettings.pixelLightCount;
if (DisablePixelLights)
QualitySettings.pixelLightCount = 0;
if (RefType == FlageWaterRefType.Both || RefType == FlageWaterRefType.Reflection)
{
DrawReflectionRenderTexture(cam);
foreach (Material mat in materials)
{
if (mat.HasProperty("_ReflectionTex"))
mat.SetTexture("_ReflectionTex", _reflectionRenderTex);
}
} if (RefType == FlageWaterRefType.Both || RefType == FlageWaterRefType.Refraction)
{
this.gameObject.layer = 4;
DrawRefractionRenderTexture(cam);
foreach (Material mat in materials)
{
if (mat.HasProperty("_RefractionTex"))
mat.SetTexture("_RefractionTex", _refractionRenderTex);
}
}
_refType = (float)RefType;
Matrix4x4 projmtx = CoreTool.UV_Tex2DProj2Tex2D(transform, cam);
foreach (Material mat in materials)
{
mat.SetMatrix("_ProjMatrix", projmtx);
mat.SetFloat("_RefType", _refType);
}
if (DisablePixelLights)
QualitySettings.pixelLightCount = oldPixelLightCount;
_insideRendering = false;
} /// <summary>
/// 绘制反射RenderTexture
/// </summary>
private void DrawReflectionRenderTexture(Camera cam)
{
Vector3 pos = transform.position;
Vector3 normal = transform.up; CreateObjects(cam,ref _reflectionRenderTex, ref _reflectionCamera); CoreTool.CloneCameraModes(cam, _reflectionCamera); float d = -Vector3.Dot(normal, pos) - ReflectClipPlaneOffset;
Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d); Matrix4x4 reflection = CoreTool.CalculateReflectionMatrix(Matrix4x4.zero, 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 = CoreTool.CameraSpacePlane(_reflectionCamera, pos, normal, 1.0f, ReflectClipPlaneOffset); Matrix4x4 projection = 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;
Vector3 euler = cam.transform.eulerAngles;
_reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);
_reflectionCamera.Render();
_reflectionCamera.transform.position = oldpos;
GL.SetRevertBackfacing(false);
} /// <summary>
/// 绘制折射RenderTexture
/// </summary>
private void DrawRefractionRenderTexture(Camera cam)
{
CreateObjects(cam, ref _refractionRenderTex, ref _refractionCamera);
CoreTool.CloneCameraModes(cam, _refractionCamera); Vector3 pos = transform.position;
Vector3 normal = transform.up; Matrix4x4 projection = cam.worldToCameraMatrix;
projection *= Matrix4x4.Scale(new Vector3(1,Mathf.Clamp(1-RefractionAngle,0.001f,1),1));
_refractionCamera.worldToCameraMatrix = projection; Vector4 clipPlane = CoreTool.CameraSpacePlane(_refractionCamera, pos, normal, 1.0f, 0);
projection = cam.projectionMatrix;
projection[2] = clipPlane.x + projection[3];//x
projection[6] = clipPlane.y + projection[7];//y
projection[10] = clipPlane.z + projection[11];//z
projection[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();
} void OnDisable()
{
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;
}
} void CreateObjects(Camera srcCam, ref RenderTexture renderTex, ref Camera destCam)
{
// Reflection render texture
if (!renderTex || _OldTexSize != TexSize)
{
if (renderTex)
DestroyImmediate(renderTex);
renderTex = new RenderTexture(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
{
GameObject go = new GameObject("__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;
}
}
}

WaterEditor.cs

using UnityEngine;
using System.Collections;
using System;
using UnityEditor; [CustomEditor(typeof(Water))]
public class WaterEditor : Editor
{ GUIContent[] _renderTextureOptions = new GUIContent[8] {new GUIContent("16"), new GUIContent("32"), new GUIContent("64"), new GUIContent("128"),
new GUIContent("256"), new GUIContent("512"), new GUIContent("1024"), new GUIContent("2048") };
int[] _renderTextureSize = new int[8] { 16, 32, 64, 128, 256, 512, 1024, 2048 };
public override void OnInspectorGUI()
{
Water water = target as Water;
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("RefType"), new GUIContent("RefType"));
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("DisablePixelLights"), new GUIContent("DisablePixelLights"));
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Layers"), new GUIContent("Layers"));
EditorGUILayout.IntPopup(this.serializedObject.FindProperty("TexSize"), _renderTextureOptions, _renderTextureSize, new GUIContent("TexSize")); if (NGUIEditorTools.DrawHeader("Reflect Settings"))
{
NGUIEditorTools.BeginContents();
{
EditorGUILayout.Slider(this.serializedObject.FindProperty("ReflectClipPlaneOffset"),0,0.1f,new GUIContent("ClipPlane Offset"));
}
NGUIEditorTools.EndContents();
} if (NGUIEditorTools.DrawHeader("Refraction Settings"))
{
NGUIEditorTools.BeginContents();
{
EditorGUILayout.Slider(this.serializedObject.FindProperty("RefractionAngle"),0,1, new GUIContent("Refraction Angle"));
}
NGUIEditorTools.EndContents();
}
this.serializedObject.ApplyModifiedProperties();
}
}

CoreTool.cs

using System.Collections;
using System;
using UnityEngine; /// <summary>
/// 工具类
/// </summary>
public static class CoreTool
{
#region Config配置
/// <summary>
/// 验证当前文件是否为配置文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns></returns>
public static bool IsConfig(string filePath)
{
return true;
}
#endregion #region Camera
/// <summary>
/// 将源摄像机状态克隆到目标相机
/// </summary>
/// <param name="src">源相机</param>
/// <param name="dest">目标相机</param>
public static void CloneCameraModes(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.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>
public static Matrix4x4 CalculateReflectionMatrix(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;
return reflectionMat;
} /// <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>
public static Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign,float clipPlaneOffset)
{
Vector3 offsetPos = pos + normal * 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));
} /// <summary>
/// 由剪裁面计算投影倾斜矩阵
/// </summary>
/// <param name="projection">投影矩阵</param>
/// <param name="clipPlane">剪裁面</param>
/// <param name="sideSign">剪裁平面(-1:平面以下,1:平面上面)</param>
public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane,float sideSign)
{
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 + 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];
return projection;
} private static float sgn(float a)
{
if (a > 0.0f) return 1.0f;
if (a < 0.0f) return -1.0f;
return 0.0f;
} /// <summary>
/// 由水平、垂直距离改动倾斜矩阵
/// </summary>
/// <param name="projMatrix">倾斜矩阵</param>
/// <param name="horizObl">水平方向</param>
/// <param name="vertObl">垂直方向</param>
/// <returns>改动后的倾斜矩阵</returns>
public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projMatrix, float horizObl, float vertObl)
{
Matrix4x4 mat = projMatrix;
mat[0, 2] = horizObl;
mat[1, 2] = vertObl;
return mat;
}
#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>
public static Matrix4x4 UV_Tex2DProj2Tex2D(Transform transform,Camera cam)
{
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 _ProjMatrix = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
_ProjMatrix = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * _ProjMatrix;
return _ProjMatrix;
}
#endregion
}

Shader

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"}
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc" uniform float4x4 _ProjMatrix;
uniform float _RefType;
sampler2D _ReflectionTex;
sampler2D _RefractionTex;
float4 _RefColor;
struct outvertex {
float4 pos : SV_POSITION;
float4 uv0 : TEXCOORD0;
float4 refparam : COLOR0;//r:fresnel,g:none,b:none,a:none
}; outvertex vert(appdata_tan v) {
outvertex o;
o.pos = mul (UNITY_MATRIX_MVP,v.vertex);
float4 posProj = mul(_ProjMatrix, v.vertex);
o.uv0 = posProj;
float3 r =normalize(ObjSpaceViewDir(v.vertex));
float d = saturate(dot(r,normalize(v.normal)));//r+(1-r)*pow(d,5)
o.refparam =float4(d,0,0,0); return o;
} float4 frag(outvertex i) : COLOR {
half4 flecol = tex2D(_ReflectionTex,float2(i.uv0) / i.uv0.w);
half4 fracol = tex2D(_RefractionTex,float2(i.uv0) / i.uv0.w);
half4 outcolor = half4(1,1,1,1);
if(_RefType == 0)
{
outcolor = lerp(flecol,fracol,i.refparam.r);
}
else if(_RefType == 1)
{
outcolor = flecol;
}
else if(_RefType == 2)
{
outcolor = fracol;
}
return outcolor*_RefColor;
}
ENDCG
}
}
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Unity3d 实时折射和反射的更多相关文章

  1. 实时折射、镜面反射shader

    原文链接:http://www.ceeger.com/forum/read.php?tid=3162&fid=2 Unity没有原生的实时镜面反射Shader,分享几个自己写的,希望能抛砖引玉 ...

  2. Unity3d 镜面折射 vertex and frag Shader源代码

    Unity3d 镜面折射  网上能找到的基本上是固定管道或表面渲染的shader. 特此翻译为顶点.片段渲染的Shader, 本源代码仅仅涉及shader与cs部分, 请自行下载NGUI  unity ...

  3. Unity3d BTDF实时折射模拟有粗糙度的半透明物体

    折射的原理是运用BTDF的一个球形高斯近似 需要考虑折射光的来源,一般会想到用环境贴图(IBL)或者grab texture,但是折射光不全都来自一个平面,所以选择环境贴图来作为折射光.这个效果主要是 ...

  4. Unity shader(CG) 写一个 散色、折射、反射、菲涅尔、gamma、简单后期屏幕特效

    http://www.lai18.com/content/506918.html 1.自生要求是很重要的,当然不是什么强迫工作之类的,而是自己有限的能力上不断的扩展兴趣上的内容. 2.用生活的眼光去发 ...

  5. 【Unity Shaders】Reflecting Your World —— Unity3D中的遮罩反射(Masking Reflections)

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  6. unity3d Hair real time rendering 真实头发实时渲染(转)

    惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确 电镜下真实头 ...

  7. unity3d Hair real time rendering 真实头发实时渲染

    先放上效果 惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确 ...

  8. CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction)

    CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction) 开始 如图所示,本文围绕GLSL里的sam ...

  9. Unity3D Built-in Shader详解一

    Unity3D内置了很多Shader,文档很详细,自己翻一下.便于加深印象. 首先先解释下Unity3D的Shader.Unity里面的Shaders是使用一种叫ShaderLab的语言编写的,它同微 ...

随机推荐

  1. RESTEasy:@FormParam、@PathParam、@QueryParam、@HeaderParam、@CookieParam、@MatrixParam说明

    在第一RESTEasy教程我们已经学习了基本的Web服务和休息我们已经测试了一个简单的REST风格的Web服务.在本教程中,我们将显示如何将Web应用程序元素(形式参数,查询参数和更多)为REST风格 ...

  2. SWT的TableVierer的使用二(数据排序)

    有一个功能是我们常使用的,就是在列的头上点击一下,整个表的记录按照这个列来排序,再点击一下按照这个列的反序来排序.那JFace是如何实现这个功能的呢?在JFace中是通过一个排序器来实现的,就是Vie ...

  3. cocos2d-html5 碰撞检測的几种方法

    游戏中的碰撞还是比較多的,比方角色与角色的碰撞,角色与墙壁的碰撞,角色与怪物的碰撞等,都须要 进行碰撞的检測,来触发一定的事件 近期在尝试制作一个小游戏的时候须要用到碰撞检測,然后就查了下资料,并在论 ...

  4. Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...

  5. onmouseover 执行 ToolTip 控件

    Tooltip控件是一个简单,但非常有用的控件.它能够为我们的软件提供非常漂亮的提示信息,提高软件的可用性,给用户比较好的体验.假设现在有两个按钮,一个用来预览吊线世系图,一个用来预览行转.为了保持按 ...

  6. javamail发送邮件(转)

    今天学习了一下JavaMail,javamail发送邮件确实是一个比较麻烦的问题.为了以后使用方便,自己写了段代码,打成jar包,以方便以后使用.呵呵 以下三段代码是我的全部代码,朋友们如果想用,直接 ...

  7. 打开或导入项目,从脱机 Outlook 数据文件 (.ost)

    打开或导入项目,从脱机 Outlook 数据文件 (.ost) Microsoft Outlook 2010 doesn\rquote t 支持手动打开或导入项目,从一个 脱机 Outlook 数据文 ...

  8. Git双机同步

    如果使用git init 初始化,当客户端仓库push内容时,服务器端仓库可以看到log,但是更新的文件不能显示,必须使用git reset --hard才能更新内容

  9. POJ 2536 Gopher II(二分图的最大匹配)

    题目链接:http://poj.org/problem?id=2536 题意:已知有n仅仅老鼠的坐标,m个洞的坐标,老鼠的移动速度为V,S秒以后有一仅仅老鹰要吃老鼠,问有多少个老鼠被吃. 非常明晰,二 ...

  10. Android 照相功能

    使用内置的Camera 应用程序捕获图像            探索Android 所提供的内置功能,内置的图像捕获与存储功能为Android 上全部媒体功能提供了一个非常好的切入点,为我们在以后的章 ...