这里只是张贴在实时折射和脚本反思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. DIV水平和垂直居中的实现

    在div的宽度和高度固定的情况下,实现div水平和垂直居中普遍采用如下的方式: <!DOCTYPE html> <html> <head> <style ty ...

  2. Unity3D发布WebPlayer时Failed to download data file解决方案

    今天发布WebPlayer时, 发现直接打开html是可以正常运行的, 但是通过iis访问的话就会报错: Failed to download data file. 一开始以为是防火墙, 后来发现不是 ...

  3. 自定义ComboBox,简简单单实现

    private void Button_Click(object sender, RoutedEventArgs e) { Popup1.PlacementTarget = TesTextBox; P ...

  4. C++-传值与传引用的差别

    //值传递与引用传递的差别 #include <iostream> #include <iomanip> using namespace std; void fiddle(in ...

  5. 采用大杀招QEMU调试Linux内核代码

    Linux调试内核代码是非常麻烦.它们一般加printk, 或者使用JTAG调试. 这里的方法是使用QEMU为了调试Linux核心. 由于QEMU自己实现gdb server, 它可以容易地使用gdb ...

  6. hdu2089不要62(数位dp)

    #include <stdio.h> #include <string.h> ][]; ]; /* dp[i][0] 不含62,4 dp[i][1] 2开头 dp[i][2] ...

  7. POJ培训计划2253_Frogger(最短/floyd)

    解决报告 意甲冠军: 乞讨0至1所有最大的道路值的最小数量. 思维: floyd. #include <iostream> #include <cstdio> #include ...

  8. 深度分析DataTable如何筛选

    这项DataTable指SpryMedia专为HTML Table设计的插件页面和发展,官方网站:http://legacy.datatables.net/index. 左右oSettings.aiD ...

  9. [Windows Phone] 实作不同的地图显示模式

    原文:[Windows Phone] 实作不同的地图显示模式 前言 本文章主要示范如何让地图有不同的模式产生,例如平面图.地形图.鸟瞰图.鸟瞰图含街道等. 这部分主要是调整 Map.Cartograp ...

  10. Linux新手命令

    给老婆写了一份速成培训教材--最经常使用的命令及解释.当然每一个人工作内容不同,经常使用命令也不同,这仅仅是我的个人经验,并且要考虑到接受者的基础. ls:列出文件夹下的内容,类似于dos下的dir. ...