这里只是张贴在实时折射和脚本反思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. H264 编解码框架简单介绍

    阅读完H264/AVC 编解码器的介绍,脑海中仅仅是留下下面三条: 1.H264并没有明白规定一个编解码器怎样实现,仅仅是规定了一个编码后的视频比特流的句法,和该比特流的解码方法,这个与MPEG 类似 ...

  2. 屌丝程序猿赚钱之道之taobao 2

    续上篇,之前写的案例,都是比較0基础的. 案例4:  代写情书.软文.论文等等. 这是我一个同学的真实故事.     我隔壁寝室的小王平时没事就爱谢谢博客.逛逛论坛.大二的时候接触了威客网,開始在网上 ...

  3. ecshop 后台批量上传商品 完整上传

    ecshop 后台批量上传商品,之所以无法上传,是因为后台上传php文件方法中没有导入商品原图路径 将ecshop根目录中的admin/goods_batch.php文件全部修改为 <?php ...

  4. cocos2d-x截图功能clippingnode它也可用于——白费

    许多其他精彩分享:http://blog.csdn.net/u010229677 3.1版本号: 在Director数: bool Director::saveScreenshot(const std ...

  5. Android开发之文件下载,状态时显示下载进度,点击自动安装

    在进行软件升级时,需要进行文件下载,在这里实现自定义的文件下载,并在状态栏显示下载进度,下载完成后,点击触发安装. 效果如图: 用于下载文件和显示现在进度的线程类如下: [java]  view pl ...

  6. php-GD库函数(三)

    <?php //imagefilledellipse — 画一椭圆并填充 /*bool imagefilledellipse ( resource $image , int $cx , int ...

  7. jQuery中间each实施例的方法

    $.each()和$(selector).each()很阶段似,但它是不一样的. 前者可用于遍历数组或json对象 后者被设计成遍历jQuery对象 第一个是$.each()对,通常这么用 $.eac ...

  8. JavaScript语言基础知识10

    JavaScript中间if声明: <span style="font-size:18px;"><HTML> <HEAD> <TITLE& ...

  9. APUE学习总结

    简介 本文总结了个人,一个数字,对应称号<APUE>第一版的每一章,但是,独立的二级标题和书,人需求进行编写. 3.文件I/O 本章所说明的函数常常被称之为不带缓存的I/O(与第5章中说明 ...

  10. [Windows Phone] 在 Windows Phone 8 控制闪光灯

    原文:[Windows Phone] 在 Windows Phone 8 控制闪光灯 ? 前言 在 Windows Phone 如果想要控制闪光灯,该怎麽做?在 Windows Phone 8 提供类 ...