目前采用比较多的反射,最终效果示例:

代码已经中文注解,有2部分需扩展:反射矩阵、歪截头体矩阵。注解中有来源链接可以去理解推导过程。
可用于镜面和水面。

咱还是直接看注解过的代码
MirrorReflection.cs

using UnityEngine;
using System.Collections;
using UnityEditor;[ExecuteInEditMode]
public class MirrorReflection : MonoBehaviour
{//public Material m_matCopyDepth;// 为效率,禁用像素级光public bool m_DisablePixelLights = true;public int m_TextureSize = 256;// 微调,获得更准确反射public float m_ClipPlaneOffset = 0.07f;// 参与反射的layerpublic LayerMask m_ReflectLayers = -1;private Hashtable m_ReflectionCameras = new Hashtable(); // Camera -> Camera tablepublic RenderTexture m_ReflectionTexture = null;//public RenderTexture m_ReflectionDepthTexture = null;private int m_OldReflectionTextureSize = 0;private static bool s_InsideRendering = false;// 渲染摄像机public Camera m_Camera;// 即将渲染public void OnWillRenderObject(){if (!enabled || !GetComponent<Renderer>() || !GetComponent<Renderer>().sharedMaterial || !GetComponent<Renderer>().enabled)return;Camera cam = Camera.current;if (!cam)return;if (cam != m_Camera )return;// Safeguard from recursive reflections.// 本过程不支持打断if (s_InsideRendering)return;s_InsideRendering = true;// 创建反射摄像机、渲染纹理Camera reflectionCamera;CreateMirrorObjects(cam, out reflectionCamera);// find out the reflection plane: position and normal in world space// 反射平面Vector3 pos = transform.position;Vector3 normal = transform.up;// Optionally disable pixel lights for reflection// 像素级光设为无效int oldPixelLightCount = QualitySettings.pixelLightCount;if (m_DisablePixelLights)QualitySettings.pixelLightCount = 0;// 从cam克隆出反射摄像机fov什么的UpdateCameraModes(cam, reflectionCamera);// Render reflection// Reflect camera around reflection plane// 通过offset调整过的反射面float d = -Vector3.Dot(normal, pos) - m_ClipPlaneOffset;Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);// 使用反射屏幕得到反射矩阵Matrix4x4 reflection = Matrix4x4.zero;CalculateReflectionMatrix(ref reflection, reflectionPlane);// 用反射矩阵得到摄像机的镜面位置,并设置其worldtoCamera矩阵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 = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f);Matrix4x4 projection = cam.projectionMatrix;CalculateObliqueMatrix(ref projection, clipPlane);reflectionCamera.projectionMatrix = projection;// 不渲染自己LayerreflectionCamera.cullingMask = ~(1 << 4) & m_ReflectLayers.value; // never render water layer// 设置渲染纹理reflectionCamera.targetTexture = m_ReflectionTexture;//GL.SetRevertBackfacing(true);GL.invertCulling = true;reflectionCamera.transform.position = newpos;Vector3 euler = cam.transform.eulerAngles;reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);reflectionCamera.depthTextureMode = DepthTextureMode.Depth;reflectionCamera.clearFlags = CameraClearFlags.Color;reflectionCamera.Render();// copy depth//Graphics.SetRenderTarget(m_ReflectionDepthTexture);//m_matCopyDepth.SetPass(0);//DrawFullscreenQuad();//Graphics.SetRenderTarget(null);// Graphics.Blit(m_ReflectionTexture, m_ReflectionDepthTexture, m_matCopyDepth);// 渲染完毕,恢复参数,设置给shader纹理reflectionCamera.transform.position = oldpos;//GL.SetRevertBackfacing(false);GL.invertCulling = false;Material[] materials = GetComponent<Renderer>().sharedMaterials;foreach (Material mat in materials){mat.SetTexture("_ReflectionTex", m_ReflectionTexture);//mat.SetTexture("_ReflectionDepthTex", m_ReflectionDepthTexture);}// // Set matrix on the shader that transforms UVs from object space into screen// // space. We want to just project reflection texture on screen.// 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 mtx = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));// mtx = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * mtx;// foreach (Material mat in materials)// {//   mat.SetMatrix("_ProjMatrix", mtx);// }// Restore pixel light countif (m_DisablePixelLights)QualitySettings.pixelLightCount = oldPixelLightCount;s_InsideRendering = false;}// Cleanup all the objects we possibly have createdvoid OnDisable(){if (m_ReflectionTexture){DestroyImmediate(m_ReflectionTexture);m_ReflectionTexture = null;}/*if (m_ReflectionDepthTexture){DestroyImmediate(m_ReflectionDepthTexture);m_ReflectionDepthTexture = null;}*/foreach (DictionaryEntry kvp in m_ReflectionCameras)DestroyImmediate(((Camera)kvp.Value).gameObject);m_ReflectionCameras.Clear();}private void UpdateCameraModes(Camera src, Camera dest){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){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.farClipPlane = src.farClipPlane;dest.nearClipPlane = src.nearClipPlane;dest.orthographic = src.orthographic;dest.fieldOfView = src.fieldOfView;dest.aspect = src.aspect;dest.orthographicSize = src.orthographicSize;}// On-demand create any objects we needprivate void CreateMirrorObjects(Camera currentCamera, out Camera reflectionCamera){reflectionCamera = null;// Reflection render textureif (!m_ReflectionTexture || m_OldReflectionTextureSize != m_TextureSize){if (m_ReflectionTexture)DestroyImmediate(m_ReflectionTexture);m_ReflectionTexture = new RenderTexture(m_TextureSize, m_TextureSize, 16);m_ReflectionTexture.name = "__MirrorReflection" + GetInstanceID();m_ReflectionTexture.isPowerOfTwo = true;m_ReflectionTexture.hideFlags = HideFlags.DontSave;m_ReflectionTexture.filterMode = FilterMode.Bilinear;/*if (m_ReflectionDepthTexture)DestroyImmediate(m_ReflectionDepthTexture);m_ReflectionDepthTexture = new RenderTexture(m_TextureSize, m_TextureSize, 0, RenderTextureFormat.RHalf);// m_ReflectionDepthTexture = new RenderTexture(m_TextureSize, m_TextureSize, 0, RenderTextureFormat.R8);m_ReflectionDepthTexture.name = "__MirrorReflectionDepth" + GetInstanceID();m_ReflectionDepthTexture.isPowerOfTwo = true;m_ReflectionDepthTexture.hideFlags = HideFlags.DontSave;m_ReflectionDepthTexture.filterMode = FilterMode.Bilinear;*/m_OldReflectionTextureSize = m_TextureSize;}// Camera for reflectionreflectionCamera = m_ReflectionCameras[currentCamera] as Camera;if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO{GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));reflectionCamera = go.GetComponent<Camera>();reflectionCamera.enabled = false;reflectionCamera.transform.position = transform.position;reflectionCamera.transform.rotation = transform.rotation;reflectionCamera.gameObject.AddComponent<FlareLayer>();go.hideFlags = HideFlags.HideAndDontSave;m_ReflectionCameras[currentCamera] = reflectionCamera;}}// Extended sign: returns -1, 0 or 1 based on sign of aprivate static float sgn(float a){if (a > 0.0f) return 1.0f;if (a < 0.0f) return -1.0f;return 0.0f;}// Given position/normal of the plane, calculates plane in camera space.// 计算cam空间中平面private Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign){Vector3 offsetPos = pos + normal * m_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));}// Adjusts the given projection matrix so that near plane is the given clipPlane// clipPlane is given in camera space. See article in Game Programming Gems 5 and// http://aras-p.info/texts/obliqueortho.html// 歪截头体矩阵计算private static void CalculateObliqueMatrix(ref Matrix4x4 projection, Vector4 clipPlane){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 rowprojection[2] = c.x - projection[3];projection[6] = c.y - projection[7];projection[10] = c.z - projection[11];projection[14] = c.w - projection[15];}// Calculates reflection matrix around the given plane// 反射矩阵,大家推导的都是这个结果private static void CalculateReflectionMatrix(ref 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;}// 0 引用static public void DrawFullscreenQuad(float z = 1.0f){GL.Begin(GL.QUADS);GL.Vertex3(-1.0f, -1.0f, z);GL.Vertex3(1.0f, -1.0f, z);GL.Vertex3(1.0f, 1.0f, z);GL.Vertex3(-1.0f, 1.0f, z);GL.Vertex3(-1.0f, 1.0f, z);GL.Vertex3(1.0f, 1.0f, z);GL.Vertex3(1.0f, -1.0f, z);GL.Vertex3(-1.0f, -1.0f, z);GL.End();}
}

可运行的UnityPackage

更多Shader实例

Shader实例:Planar Reflection 平面反射相关推荐

  1. Unity URP Planar reflection 平面反射

    利用双休天写的,代码和shader还有不少问题 修复中.... 一开始是用模板测试和后处理写的,后面改成屏幕坐标,更方便了,加入到我的水体康康 主要思想是动态创建一个翻转的反射摄像机 ,但是不打开这个 ...

  2. Unity下平面反射实现

    平面反射通常指的是在镜子或者光滑地面的反射效果上,如下图所示, 上图是一个光滑的平面,平面上的物体在平面上有对称的投影. 一.平面反射的原理 对于光照射到物体表面然后发生完美镜面反射的示意图,如下所示 ...

  3. 平面反射builltinURP—— UnityShader学习记笔记

    文章目录 自言自语 一.C# builltin 二.URP 总结 自言自语 又是好久没有更新笔记了.最近项目真的很忙.一直想更新的笔记现在才有空梳理.今天要记载的就是平面反射. 一.C# buillt ...

  4. Vulkan_平面反射

    平面反射 屏幕空间反射是利用屏幕空间数据进行计算反射的一种技术.它通常用于创建更精细的反射,如在潮湿的地板表面或水坑. 一.实现思路 主要分两次进行基本的离屏渲染.第一遍将镜像的场景渲染到具有颜色和深 ...

  5. Java Reflection (JAVA反射) 选择自 leek2000 的 Blog

    Java Reflection (JAVA反射)   作者:  corlin 日期:  04-05-10 10:32 点击数:  748   Reflection 是 Java 程序开发语言的特征之一 ...

  6. OpenGL渲染纹理和平面反射

    OpenGL渲染纹理和平面反射 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL ...

  7. JAVA Reflection(反射机制)续

    接上一篇文章  JAVA Reflection(反射机制) 动态数组 java.lang.reflect.Array static Object set(Object array, int index ...

  8. android 4实例分析,OpenGL Shader实例分析(4)闪光效果

    本文实例为大家分享了opengl shader实例闪光效果的具体代码,供大家参考,具体内容如下 在游戏中,当战斗结束后,对一些获取的宝贝需要进行闪光处理.这篇文章介绍一个进行闪光处理的shader,运 ...

  9. shader实例:实现类似宝可梦 Pokemon 的战斗转场

    宝可梦游戏在进入战斗前会有类似这样转场动画. 例子中使用的纹理质量较差,边缘比较模糊,和shader无关. 这个UI是盖在所有UI最前面的.可以使用shader来完成这个工作,而不是复杂的动画. 使用 ...

最新文章

  1. Button的使用(十):ImageButton
  2. 【暑假训练 7.10】 codevs 2492 上帝造题的七分钟2
  3. 思科nat配置实例_Cisco ASA 5520(8.2.4)配置企业内网案例
  4. java 异常_学习Java,你需要知道这些Java异常
  5. JAVA 反射 动态获取类,并调用方法
  6. SharePoint 2010 价格计算器
  7. 单片机1到十五c语言,手把手教你学单片机的C语言程序设计(十五).pdf
  8. 我的世界java版合成快捷键_我的世界常用快捷键指令大全 Minecraft必知的快捷键...
  9. HCIE大师之路——Lab讲解
  10. 聊天记录软件工作记录
  11. 路由器配置出现192.168.1.0 overlaps with Vlan2的解决方案
  12. JAVA学习笔记(第五章 接口与继承)
  13. ubuntu18.04安装与更新NVIDIA驱动
  14. 个人计算机全都是多媒体计算机系统组成,多媒体计算机系统组成
  15. Li‘s 核磁共振影像数据处理-23-itk-snap调整影像方向功能介绍
  16. 目标检测yolo系列
  17. requests/lxml的简单用例
  18. JMicroVision教程-应用于测井岩层电镜图像分析
  19. 深度式睡眠潜入虚拟世界_潜入swiftui的惊人世界
  20. 《玄奘西行》华盛顿上演 美国观众称“美轮美奂”

热门文章

  1. vue实现全屏登录视频背景并适配浏览器窗口大小
  2. 使用Git切换分支(创建本地分支,远程分支,合并分支代码)
  3. UBI制作人:传统开发商不必恐惧社交游戏
  4. Linux 基础 之 yum 黑名单 和 安装虚拟机脚本
  5. uni-app引入阿里矢量图在移动端不显示的问题
  6. PHP使用基于SMAL协议的AzureAD认证实现SSO
  7. 整合资源,创造价值:企业如何“借力共赢”
  8. DataWhale_python训练营task7
  9. 电脑怎么锁定EDID
  10. 2022-07-09 第八组 张明敏 学习笔记