Unity3d 实时折射和反射
这里只是张贴在实时折射和脚本反思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 实时折射和反射的更多相关文章
- 实时折射、镜面反射shader
原文链接:http://www.ceeger.com/forum/read.php?tid=3162&fid=2 Unity没有原生的实时镜面反射Shader,分享几个自己写的,希望能抛砖引玉 ...
- Unity3d 镜面折射 vertex and frag Shader源代码
Unity3d 镜面折射 网上能找到的基本上是固定管道或表面渲染的shader. 特此翻译为顶点.片段渲染的Shader, 本源代码仅仅涉及shader与cs部分, 请自行下载NGUI unity ...
- Unity3d BTDF实时折射模拟有粗糙度的半透明物体
折射的原理是运用BTDF的一个球形高斯近似 需要考虑折射光的来源,一般会想到用环境贴图(IBL)或者grab texture,但是折射光不全都来自一个平面,所以选择环境贴图来作为折射光.这个效果主要是 ...
- Unity shader(CG) 写一个 散色、折射、反射、菲涅尔、gamma、简单后期屏幕特效
http://www.lai18.com/content/506918.html 1.自生要求是很重要的,当然不是什么强迫工作之类的,而是自己有限的能力上不断的扩展兴趣上的内容. 2.用生活的眼光去发 ...
- 【Unity Shaders】Reflecting Your World —— Unity3D中的遮罩反射(Masking Reflections)
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- unity3d Hair real time rendering 真实头发实时渲染(转)
惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确 电镜下真实头 ...
- unity3d Hair real time rendering 真实头发实时渲染
先放上效果 惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确 ...
- CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction)
CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction) 开始 如图所示,本文围绕GLSL里的sam ...
- Unity3D Built-in Shader详解一
Unity3D内置了很多Shader,文档很详细,自己翻一下.便于加深印象. 首先先解释下Unity3D的Shader.Unity里面的Shaders是使用一种叫ShaderLab的语言编写的,它同微 ...
随机推荐
- (转)SWT的CheckBoxTreeViewer的相关用法
最近在项目中需要用到遍历某个目录下所有文件,并按照树形结构展示,同时还需要提供对树形菜单的选择展开等操作.在eclipse中提供了CheckboxTreeViewer组件来满足所需要的功能 下面是需要 ...
- POJ 1838 Banana (并查集)
Description Consider a tropical forrest, represented as a matrix. The cell from the right top corner ...
- POJ 3286 How many 0's?
题目大意: 计算[m,n]之间全部数字有多少个零. 解题思路: 能够用[0,m)之间和[0,n]之间有多少个零然后作差. 规律是计算全部位置在到当前数时有多少个零. 以下是代码: #include ...
- MYSQL正在使用select发现现场记录方法,包括一个逗号分隔的字符串
首先,我们创建一个逗号分隔字符串. CREATE TABLE test(id int(6) NOT NULL AUTO_INCREMENT,PRIMARY KEY (id),pname VARCHAR ...
- java获取指定地址图片高度宽度简单代码
package com.test; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.In ...
- hdu - 4975 - A simple Gaussian elimination problem.(最大流量)
意甲冠军:要在N好M行和列以及列的数字矩阵和,每个元件的尺寸不超过9,询问是否有这样的矩阵,是独一无二的N(1 ≤ N ≤ 500) , M(1 ≤ M ≤ 500). 主题链接:http://acm ...
- WEB网站性能优化
最近做了一个WEB现场.幸运的是,一开始.但后来越来越慢,特别是在调试模式,,这肯定是我们的代码有问题.但是即使业务不是非常复杂的也非常慢,我们就想当然的觉得我们的代码没问题,可最后证明还是我们的代码 ...
- 强大的数据库查询工具Database.NET 9.4.5018.42
原文:强大的数据库查询工具Database.NET 9.4.5018.42 强大的数据库查询工具Database.NET 9.4.5018.42 两个工具的下载地址,两个软件都是绿色免安装的,直接双击 ...
- hdu 2074 堆放篮 好开心图纸标题
堆放篮 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- ECLIPSE中反编译插件JAD的配置安装,轻松查看JAVA源代码
第一步:下载jad的eclipse插件jar包 http://jadclipse.sourceforge.net/wiki/index.php/Main_Page#Download 第二步:将此jar ...