精华内容
下载资源
问答
  • 平面反射

    千次阅读 2020-06-22 22:21:22
    平面反射的实现步骤: 1、抓取屏幕图像——渲染纹理RenderTexture+额外摄像机 2、反射矩阵(ReflectMatrix)——获得反射的屏幕图像 3、斜裁剪矩阵(ObliqueMatrix)——裁剪掉反射平面以下的部分 4、高斯模糊——模糊...

    平面反射
    GitHub项目地址

    平面反射的实现步骤:

    1、抓取屏幕图像——渲染纹理RenderTexture+额外摄像机
    2、反射矩阵(ReflectMatrix)——获得反射的屏幕图像
    3、斜裁剪矩阵(ObliqueMatrix)——裁剪掉反射平面以下的部分
    4、高斯模糊——模糊反射的倒影
    5、将反射纹理渲染到地面

    1、抓取屏幕图像

    之前的文章已经提过了,抓取屏幕图像有两种方法:
    1、GrabPass
    2、渲染纹理RenderTexture+额外摄像机
    这里需要使用第二种方法:

    private Camera mainCamera, reflectCamera;
    private RenderTexture reflectTex;
    private Renderer render;
    private Material reflectMaterial;
    void Start()
    {
      mainCamera = Camera.main;
      GameObject go = new GameObject("ReflectCamera", typeof(Camera));
      reflectCamera = go.GetComponent<Camera>();
      reflectCamera.fieldOfView = mainCamera.fieldOfView;
      reflectCamera.aspect = mainCamera.aspect;
      reflectCamera.cullingMask = mainCamera.cullingMask;
      //自己控制渲染的层级
      //reflectCamera.cullingMask = 1 << LayerMask.NameToLayer("Player");
      reflectCamera.enabled = false;
    
      reflectTex = RenderTexture.GetTemporary(1024, 1024, 24);
      reflectCamera.targetTexture = reflectTex;
    
      render = GetComponent<Renderer>();
      reflectMaterial = render.sharedMaterial;
    }
    

    2、反射矩阵(ReflectMatrix)

    顶点反射
    反射矩阵
    反射矩阵的推导过程https://zhuanlan.zhihu.com/p/92633614

    //计算plane平面的反射矩阵
    private void CalculateReflectMatrix(ref Matrix4x4 matrix, Vector4 plane)
    {
      matrix.m00 = (1F - 2F * plane[0] * plane[0]);
      matrix.m01 = (-2F * plane[0] * plane[1]);
      matrix.m02 = (-2F * plane[0] * plane[2]);
      matrix.m03 = (-2F * plane[3] * plane[0]);
    
      matrix.m10 = (-2F * plane[1] * plane[0]);
      matrix.m11 = (1F - 2F * plane[1] * plane[1]);
      matrix.m12 = (-2F * plane[1] * plane[2]);
      matrix.m13 = (-2F * plane[3] * plane[1]);
    
      matrix.m20 = (-2F * plane[2] * plane[0]);
      matrix.m21 = (-2F * plane[2] * plane[1]);
      matrix.m22 = (1F - 2F * plane[2] * plane[2]);
      matrix.m23 = (-2F * plane[3] * plane[2]);
    }
    

    3、斜裁剪矩阵(ObliqueMatrix)

    需要裁减红色部分
    Unity已经为我们提供了获取斜裁减矩阵的方法CalculateObliqueMatrix,我们只需要注意这个方法的参数是视图空间的平面。

    //为了反射相机近裁剪平面紧贴我们的反射平面,防止错误渲染
    //我们需要重新计算反射相机的投影矩阵,斜裁剪矩阵(ObliqueMatrix)
    Vector4 viewPlane = CameraSpacePlane(reflectCamera.worldToCameraMatrix, transform.position, normal);
    reflectCamera.projectionMatrix = reflectCamera.CalculateObliqueMatrix(viewPlane);
    //计算视图空间的平面
    private Vector4 CameraSpacePlane(Matrix4x4 worldToCameraMatrix, Vector3 pos, Vector3 normal)
    {
      Vector3 viewPos = worldToCameraMatrix.MultiplyPoint3x4(pos);
      Vector3 viewNormal = worldToCameraMatrix.MultiplyVector(normal).normalized;
      float w = -Vector3.Dot(viewPos, viewNormal);
      return new Vector4(viewNormal.x, viewNormal.y, viewNormal.z, w);
    }
    

    斜裁剪矩阵的推导过程https://zhuanlan.zhihu.com/p/92633614

    4、高斯模糊

    高斯模糊我前面的文章已经介绍过了,这里不详细写了。
    平面反射+高斯模糊

    5、将反射纹理渲染到地面

    最后一步,我们需要将获取到的反射纹理渲染到地面。
    我们只需要在渲染地面的时候,叠加反射纹理即可。

    sampler2D _ReflectTex;
    //vert
    o.uvReflect = ComputeScreenPos(o.vertex);
    //frag
    fixed4 reflectCol = tex2Dproj(_ReflectTex, i.uvReflect);
    
    展开全文
  • 根据初级波面像差理论,推导了自准检测法中平面反射镜的误差允许值.所得结果既适用于轴上,也适用于轴外.同时指出了Burch的结果的局限性.
  • 文章目录自言自语一、C# builltin首先声明一个枚举来设置RT尺寸然后进行场景初始化清理在OnwillRender方法中传参并调用平面反射的具体运算进行场景物件的平面反射计算 (这里我把场景角色做了区分,分别用两个反射...


    自言自语

    又是好久没有更新笔记了。最近项目真的很忙。一直想更新的笔记现在才有空梳理。今天要记载的就是平面反射。

    一、C# builltin

    由于平面反射一般只需要传RT(RenderTexture)给shader使用。所以这次笔记就不用放上相应shader了。具体可以用平面反射实现水面效果,镜面反射,倒影等等一些列效果。

    并且,由于转换矩阵都是复杂的推理和运算。超出了我这个美术的现有知识和理解范畴,因此我都是借鉴前辈的函数直接使用。自己只是根据需求做了一些变更。因此就不放相应的平面反射矩阵了。网上前辈们实现好的也很多。Unity也有封装好已经实现的函数可以直接使用。比如/利用Unity提供的 API CalculateObliqueMatrix 来做斜视锥体投影矩阵。

    这里我只记录部分自己做了修改的代码。主要是提醒自己关于RT的管理以及防止RT内存泄漏的问题。

    首先声明一个枚举来设置RT尺寸

    //声明一个枚举类型来控制RT尺寸
        public enum RTSize
        {
            _128 = 128, _256 = 256, _512 = 512, _1024 = 1024, _2048 = 2048, _4096 = 4096, _8192 = 8192,
        }
        public RTSize ReflectTexSize = RTSize._1024;
    

    然后进行场景初始化清理

        private void Start()
        {
            //不管场景中有没有  运行前先清掉一波反射相机
            //这里使用DestroyImmediate方法主要是要再 editmode下使其生效
            DestroyImmediate(GameObject.Find("Reflection Camera"));
            DestroyImmediate(GameObject.Find("Character Reflection Camera"));
    
            noTexture = new RenderTexture(1, 1, 0);
        }
    

    在OnwillRender方法中传参并调用平面反射的具体运算

        private void OnWillRenderObject()
        {
            Shader.SetGlobalTexture("_ReflectTex", noTexture);
            Shader.SetGlobalTexture("_SourceTex", noTexture);
            Shader.SetGlobalTexture("_CHReflectTex", noTexture);
            Shader.SetGlobalTexture("_CHSourceTex", noTexture);
            PlanarReflectionBlur();
            CharacterPlanarReflectionBlur();
        }
    

    进行场景物件的平面反射计算 (这里我把场景角色做了区分,分别用两个反射相机来做。可以实现更多自定义。原理都一样 就只放一个场景的吧)

    另外Camera.main 和 Camera.current 在不同Unity版本和管线产生的观察效果不同.至于为什么不懂…可能是Unity玄学.这点在相应代码处已注释明白

     private void PlanarReflectionBlur()
        {
            //如果没有渲染 也就是脚本勾掉 则返回空  否则 设置渲染状态为true 并进行后边操作
            if (isReflectionCameraRendering == true)
                return;
            isReflectionCameraRendering = true;
            //如果没有反射相机 创建一个反射相机 
            if (!reflectionCamera)
            {
                //不管场景中有没有  运行前先清掉一波反射相机
                DestroyImmediate(GameObject.Find("Reflection Camera"));
    
                //先声明个物体 名字叫 Reflection Camera tag设置好
                GameObject go = new GameObject("Reflection Camera")
                {
                    tag = "ReflectCamera",
                };
                //然后给这个物体添加相机组件
                reflectionCamera = go.AddComponent<Camera>();
                //并把当前相机中的相关参数 copy给反射相机
                reflectionCamera.CopyFrom(Camera.main);
                reflectionCamera.cullingMask &= ~(1 << 8);
                reflectionCamera.cullingMask &= ~(1 << 5);
                reflectionCamera.cullingMask &= ~(1 << 9);
            }
            //如果没有RT 就设置个RT 从当前缓存拿到一个RT 大小格式设置好
            if(!sourceRT)
            {
                sourceRT = RenderTexture.GetTemporary((int)ReflectTexSize / downSample, (int)ReflectTexSize / downSample, 24);
            }
    
            //需要实时同步相机的参数,比如编辑器下滚动滚轮,Editor相机的远近裁剪面就会变化
            UpdateCamearaParams(Camera.main, reflectionCamera);
            //设置反射相机的目标RT 为刚才声明的RT
            reflectionCamera.targetTexture = sourceRT;
            //将反射相机先设置为false  因为并不需要他真的传入屏幕图像 只是把拍到的传入RT中 所以关闭
            reflectionRT = RenderTexture.GetTemporary((int)ReflectTexSize / downSample, (int)ReflectTexSize / downSample, 24);
            Graphics.Blit(sourceRT, reflectionRT);
    
            reflectionCamera.enabled = false;
    
            //即需要保证平面模型的原点在平面上,否则可以尝试增加offset偏移 这里我就加了offsetplanar
            Transform planarPos = GetComponent<Transform>();
            planarPos.localPosition = new Vector3(0, offsetPlanar, 0);
            //根据上文平面定义,需要平面法向量和平面上任意点,此处使用transform.up为法向量,transform.position为平面上的点
            //在不懂的情况下 直接抄一个平面反射矩阵
            var reflectM = CaculateReflectMatrix(transform.up, transform.position);
            //将反射相机的转换矩阵设置为当前相机拍到的平面的反射矩阵.  注意都是在相机空间下进行的转换
            //builltin在我使用的Unity版本中有个BUG 如果 采用Camera.current相机则会造成反射相机的FOV不实时更新,需要销毁RT重新创建才生效.无法实现效果.因此只能调用Camera.main 但带来的问题就是Scene窗口和Game窗口观察效果不一致.
            //后经其他版本,包括URP管线测试,则没有此问题,可以使用Camera.current相机来使Scene窗口观察效果与Game窗口一致
            reflectionCamera.worldToCameraMatrix = Camera.main.worldToCameraMatrix * reflectM;
    
            //确定平面的法线朝向
            var normal = transform.up;
            //求得目标点经过平面的倒影的距离 相关原理能看懂 但矩阵着实弄不明白
            var d = -Vector3.Dot(normal, transform.position);
    
            //将平面到点的距离
            Vector4 plane = new Vector4(normal.x, normal.y, normal.z, d);
           
            //将平面利用相机空间的逆转置矩阵 把平面转换到反射相机空间下
            Vector4 viewSpacePlane = reflectionCamera.worldToCameraMatrix.inverse.transpose * plane;
    
            //利用Unity提供的 API  CalculateObliqueMatrix 来做斜视锥体投影矩阵
            var clipMatrix = Camera.main.CalculateObliqueMatrix(viewSpacePlane);
            //再把转换好的平面 传递给 反射相机的投影矩阵  使相机成像
            reflectionCamera.projectionMatrix = clipMatrix;
            reflectionCamera.depthTextureMode |= DepthTextureMode.Depth;
            //需要将背面裁剪反过来,因为仅改变了顶点,没有改变法向量,绕序反向,裁剪会不对  
            //这段也是完全没懂
            GL.invertCulling = true;
            reflectionCamera.Render();
            GL.invertCulling = false;
    
            //高斯模糊
            if (IsBlur == false)
            {
                如果没有反射材质 则去获取拿到当前平面的渲染组件 获得其材质
                //if (reflectionMaterial == null)
                //{
                //    Renderer renderer = GetComponent<Renderer>();
                //    //因为要可读写 所以需要用到共享材质  而不是Clone材质
                //    reflectionMaterial = renderer.sharedMaterial;
                //    //然后把相机拍到的反射RT 传到材质中
                //}
                Shader.SetGlobalTexture("_ReflectTex", sourceRT);
                Shader.SetGlobalTexture("_SourceTex", sourceRT);
            }
            else
            {
                if (blurShader == null)
                {
                    //if (reflectionMaterial == null)
                    //{
                    //    Renderer renderer = GetComponent<Renderer>();
                    //    //因为要可读写 所以需要用到共享材质  而不是Clone材质
                    //    reflectionMaterial = renderer.sharedMaterial;
                    //    //然后把相机拍到的反射RT 传到材质中
                    //}
                    Shader.SetGlobalTexture("_ReflectTex", sourceRT);
                    Shader.SetGlobalTexture("_SourceTex", sourceRT);
                }
                else
                {
                    if (blurMaterial == null)
                    {
                        blurMaterial = new Material(blurShader);
                    }
                    //在这里用FOR循环引入Gaussian模糊迭代次数
                    for (int i = 0; i < iteration; i++)
                    {
                        //循环迭代前设置好模糊距离即shader中进行卷积操作的采样范围
                        blurMaterial.SetFloat("_BlurSize", 1.0f + i * blurSpread);
                        RenderTexture buffer = RenderTexture.GetTemporary((int)ReflectTexSize / downSample, (int)ReflectTexSize / downSample,24);
    
                        //然后经过shader中第一个PASS的verticalblur后,把buffer0存入到buffer中
                        Graphics.Blit(reflectionRT, buffer, blurMaterial, 0);
                        //图像再用shader中的第二个pass 进行一次horizontalblur 存入到buffer1中
                        Graphics.Blit(buffer, reflectionRT, blurMaterial, 1);
                        //此时就是已经经历过一次完整迭代的 纵横卷积的图像 存入到buffer1中了 释放buffer0的缓存 以备后用
                        RenderTexture.ReleaseTemporary(buffer);
                    }
                    //if (reflectionMaterial == null)
                    //{
                    //    Renderer renderer = GetComponent<Renderer>();
                    //    //因为要可读写 所以需要用到共享材质  而不是Clone材质
                    //    reflectionMaterial = renderer.sharedMaterial;
                    //    //然后把相机拍到的反射RT 传到材质中
                    //}
                    Shader.SetGlobalTexture("_ReflectTex", reflectionRT);
                    Shader.SetGlobalTexture("_SourceTex", sourceRT);
                }
            }
            RenderTexture.ReleaseTemporary(reflectionRT);
            isReflectionCameraRendering = false;
        }
    

    最后在Disable下清除反射相机和RT

    
        private void OnDisable()
        {
            //清楚RT 并销毁相机
                RenderTexture.ReleaseTemporary(sourceRT);
                RenderTexture.ReleaseTemporary(reflectionRT);
                RenderTexture.ReleaseTemporary(CHsourceRT);   
                RenderTexture.ReleaseTemporary(CHreflectionRT);
                noTexture.Release();
    
                if (reflectionCamera)
                    DestroyImmediate(reflectionCamera.gameObject);
    
                if (characterReflectionCamera)
                    DestroyImmediate(characterReflectionCamera.gameObject);
                reflectionCamera = null;
                characterReflectionCamera = null;
        }
    

    实时计算相机参数的方法

        //这个就是实时保持反射相机的参数和主相机参数一致
        private void UpdateCamearaParams(Camera srcCamera, Camera destCamera)
        {
            //如果目标相机和原相机有一个不存在则返回 不做操作 否则当他们都存在的时候进行如下步骤统一参数
            if (destCamera == null || srcCamera == null)
                return;
           
            destCamera.clearFlags = CameraClearFlags.SolidColor;
            destCamera.backgroundColor = Color.clear;
            destCamera.farClipPlane = srcCamera.farClipPlane;
            destCamera.nearClipPlane = srcCamera.nearClipPlane;
            destCamera.orthographic = srcCamera.orthographic;
            destCamera.fieldOfView = srcCamera.fieldOfView;
            destCamera.aspect = srcCamera.aspect;
            destCamera.orthographicSize = srcCamera.orthographicSize;
            destCamera.allowMSAA = srcCamera.allowMSAA;
            destCamera.allowHDR = true;
        }
    

    二、URP

    URP下调用相机的方法有所区别,其他都与builltin大同小异 这里只记录调用相机渲染的不同之处

            GL.invertCulling = true;
            //reflectionCamera.Render();
            //RenderSingleCamera(context,camra) 这个方法看了元数据也没懂啥意思 暂且先抄之。。后续再啃
            UniversalRenderPipeline.RenderSingleCamera(context,reflectionCamera);
            GL.invertCulling = false;
    

    总结

    C#代码学过一段时间,但是关于Unity API及各个版本和管线的变化实在有点繁杂。只能在实践中慢慢掌握了。路真的漫漫啊。

    展开全文
  • UE4平面反射

    2020-09-24 13:26:58
    UE4 支持实时平面反射,它比屏幕空间反射(SSR)更加精确,但渲染开销较高。渲染开销较高的原因来自平面反射的工作原理。因为平面反射实际上将从反射方向再次对关卡进行渲染。 在渲染方面,屏幕空间反射(SSR)比...

    UE4 支持实时平面反射,它比屏幕空间反射(SSR)更加精确,但渲染开销较高。渲染开销较高的原因来自平面反射的工作原理。因为平面反射实际上将从反射方向再次对关卡进行渲染

    在渲染方面,屏幕空间反射(SSR)比平面反射更为高效,但可靠性较差。下图将SSR的缺陷和平面反射进行了对比。

    屏幕空间反射:左图展示了屏幕空间反射的局限性。注意图像边缘出现了大量"泄露",或者说面向摄像机视角的池塘部分上的反射开始淡出。出现此现象的原因是SSR无法反射画面外的物体

    平面反射:右图为相同的关卡,启用的是平面反射。注意图像中,甚至池塘的两侧和边缘均未出现"泄露",反射保持了连贯和精准。原因是平面反射能够无视摄像机视角,反射画面外的物体

    启用平面反射

    平面反射Actor被添加到关卡后,附近的反射材质将自动受到影响放置在关卡中的静态网格体的法线用于反射的失真,模拟波纹效果

    平面反射Actor的属性

    平面反射Actor的场景采集属性:

    平面反射的限制

    1. 平面反射会导致整个场景被渲染两次,所以要把一半的帧时间花在渲染线程和GPU上。
    2. 限制世界场景中放置的平面反射数量。很多时候,一个还是多个是问题。
    3. 适当地调整它的大小,使其能够在不可见的情况下被剔除
    4. 渲染平面反射角色的开销直接来自当前在关卡中进行渲染的内容。当启用此功能时,因为这些开销不随着屏幕百分比缩放,所以存在大量三角形和绘制调用的场景将遭受最多的性能问题

    平面反射性能

    1. 在项目中启用平面反射可实现相当精确的反射,但该功能会对项目性能产生直接影响。以下部分将说明在针对高端 PC 的项目和针对移动设备的项目中启用平面反射后的性能影响。
    2. 高端PC中平面反射对关卡的视觉效果提升十分大,使用全动态光影对性能的影响也极大—约带来略小于一倍的时间。使用静态/预计算光影的关卡再次进行平面反射渲染时效率更高
    3. 移动设备中,可以只需要一个平面反射,将其缩放匹配关卡中放置的水面静态网格体即可。可能仅仅需要1,2ms的时间即可。

    展开全文
  • shader反射——平面反射

    千次阅读 2019-04-01 20:17:11
    的话,性能至少是在可以接受的范围,并且相对于其他几种反射效果来说,平面反射的效果是最好的, 所以Planar Reflection目前是实时反射效果中使用的比较多的一种方案。 平面反射效果实现 首先,我们需要一个相机...

    C#代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlanarReflection : MonoBehaviour
    {
        private Camera reflectionCamera = null;
        private RenderTexture reflectionRT = null;
        private Material reflectionMaterial = null;
        private static bool isReflectionCameraRendering = false;
    
        private void OnWillRenderObject()
        {
            if (isReflectionCameraRendering) return;
            isReflectionCameraRendering = true;
    
            if (reflectionCamera == null)
            {
                var go = new GameObject("Reflection Camera");
                reflectionCamera = go.AddComponent<Camera>();
                reflectionCamera.CopyFrom(Camera.current);
            }
    
            if (reflectionRT == null)
            {
                reflectionRT = RenderTexture.GetTemporary(1024, 1024, 24);
            }
    
            UpdateCameraParams(Camera.current, reflectionCamera);
            reflectionCamera.targetTexture = reflectionRT;
            reflectionCamera.enabled = false;
    
            var reflectM = CalculateReflectMatrix(transform.up, transform.position);
            reflectionCamera.worldToCameraMatrix = Camera.current.worldToCameraMatrix * reflectM;
            GL.invertCulling = true;
            reflectionCamera.Render();
            GL.invertCulling = false;
    
            if(reflectionMaterial == null)
            {
                var renderer = GetComponent<Renderer>();
                reflectionMaterial = renderer.sharedMaterial;
            }
            reflectionMaterial.SetTexture("_ReflectionTex", reflectionRT);
            isReflectionCameraRendering = false;
        }
    
        Matrix4x4 CalculateReflectMatrix(Vector3 normal, Vector3 positionOnPlane)
        {
            var d = -Vector3.Dot(normal, positionOnPlane);
            var reflectM = new Matrix4x4();
            reflectM.m00 = 1 - 2 * normal.x * normal.x;
            reflectM.m01 = -2 * normal.x * normal.y;
            reflectM.m02 = -2 * normal.x * normal.z;
            reflectM.m03 = -2 * d * normal.x;
    
            reflectM.m10 = -2 * normal.x * normal.y;
            reflectM.m11 = 1 - 2 * normal.y * normal.y;
            reflectM.m12 = -2 * normal.y * normal.z;
            reflectM.m13 = -2 * d * normal.y;
    
            reflectM.m20 = -2 * normal.x * normal.z;
            reflectM.m21 = -2 * normal.y * normal.z;
            reflectM.m22 = 1 - 2 * normal.z * normal.z;
            reflectM.m23 = -2 * d * normal.z;
    
            reflectM.m30 = 0;
            reflectM.m31 = 0;
            reflectM.m32 = 0;
            reflectM.m33 = 1;
            return reflectM;
        }
    
        private void UpdateCameraParams(Camera srcCamera, Camera destCamera)
        {
            if (destCamera == null || srcCamera == null)
                return;
    
            destCamera.clearFlags = srcCamera.clearFlags;
            destCamera.backgroundColor = srcCamera.backgroundColor;
            destCamera.farClipPlane = srcCamera.farClipPlane;
            destCamera.nearClipPlane = srcCamera.nearClipPlane;
            destCamera.orthographic = srcCamera.orthographic;
            destCamera.fieldOfView = srcCamera.fieldOfView;
            destCamera.aspect = srcCamera.aspect;
            destCamera.orthographicSize = srcCamera.orthographicSize;
        }
    }
    
    

    shader代码:

    Shader "Custom/PlanarReflection"
    {
    	SubShader
    	{
    		Tags { "RenderType" = "Opaque" }
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    			};
    
    			struct v2f
    			{
    				float4 vertex : SV_POSITION;
    				float4 screenPos: TEXCOORD0;
    			};
    
    			sampler2D _ReflectionTex;
    
    			v2f vert(appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.screenPos = ComputeScreenPos(o.vertex);
    				return o;
    			}
    
    			fixed4 frag(v2f i) : SV_Target
    			{
    				fixed4 col = tex2D(_ReflectionTex,  i.screenPos.xy / i.screenPos.w);
    				return col;
    			}
    			ENDCG
    		}
    	}
    }
    
    

    运行的结果为:
    在这里插入图片描述
    原理解释:
    Planar Reflection
    平面反射顾名思义,就是在平面上运用的反射,名字也正是这种反射方式的限制,只能用于平面,
    而且是高度一致的平面,多个高度不一的平面效果也不正确。一般情况下,一个平面整体反射效果
    基本可以满足需求,而且对于实时渲染反射效果,需要将反射的物体多渲染一次,控制好层级数量
    的话,性能至少是在可以接受的范围,并且相对于其他几种反射效果来说,平面反射的效果是最好的,
    所以Planar Reflection目前是实时反射效果中使用的比较多的一种方案。

    平面反射效果实现
    首先,我们需要一个相机,与当前正常相机关于平面对称,也就是说,我们把正常相机变换到这个
    对称的位置,然后将这个相机的渲染结果输出到一张RT上,就可以得到对称位置的图像了。我们得到了
    平面反射的矩阵R,下面我们需要考虑的就是在哪个阶段使用这个反射矩阵R。我们知道,渲染物体
    需要通过MVP变换,物体首先通过M矩阵,从物体空间变换到世界空间,然后通过V矩阵,从世界空间
    变换到视空间,最后通过投影矩阵P变换到裁剪空间。我们把R矩阵插在V之后,在一个物体在进行MV
    变换后,变到正常相机坐标系下,然后再进行一次反射变换,就相当于变换到了相机对于屏幕对称的
    相机坐标系下,然后再进行正常的投影变换,就可以得到反射贴图了。

    要使用反射贴图,我们在shader中增加相应的Texture变量即可。不过这个贴图的采样并非使用正常的uv
    坐标,因为我们的贴图是反射相机的输出的RT,假设这个RT我们输出在屏幕上,反射平面上当前像素点
    对应位置我们屏幕上的位置作为uv坐标才能找到这一点对应RT上的位置。需要在vertex shader中通过
    ComputeScreenPos计算屏幕坐标,fragment shader采样时进行透视校正纹理采样。

    参考网址:
    https://blog.csdn.net/puppet_master/article/details/80808486
    项目地址:
    https://gitee.com/yichichunshui/Reflection.git

    展开全文
  • UE4-(反射)平面反射

    千次阅读 2020-05-09 14:44:33
    平面反射会捕获反射信息,只能用于平面反射效果,所以只适用于平整的对象,例如镜子,水池水面、窗户玻璃。任何尺寸较小表面平整的对象,都可以用平面反射覆盖。 二、属性 1.平面反射既可以实时渲染,也可以一次性...
  • 1 常见规则平面的反射声场如附图所示,设在一各向同性且材质均匀工件中,有一任意形状表面光滑平面反射体。将坐标原点取在该平面的几何中心,z轴沿其法线方向,x轴和y轴在平面内。设探头距反射体足够远且反射面的尺寸甚...
  • 为了解决光学相关器无法与发生旋转的目标进行光学相关识别的问题,提出了使用平面反射镜组获取目标图像,与模板图像进行相关识别。在获取目标的光学系统中,加入一个由多个平面反射镜围成的正多棱柱体,它可以使目标...
  • 在论述X光掠入射平面反射镜工作原理的基础上,重点讨论了超高精度X光镍平面反射镜的制备过程,研制出表面粗糙度小于1.5 nm的平面反射镜。测试和使用表明:在掠入射角为5°时,该反射镜的反射率在54%以上。
  • 针对现有的面向聚类的数据扰动方法隐私保护度低的问题,提出一种基于平面反射的数据扰动方法。将发布对象的全部属性两两配对构成平面上的点,再随机选择一条直线作每对属性关于直线的对称点,转换后的数据即为发布的...
  • 本文围绕平面反射阵天线设计中双频的问题进行了深入探讨和研究,提出一种新型的Ku/Ka平面反射阵列天线单元,并针对双频单元之间相互耦合的问题创新性地提出一种耦合抑制结构,获得了良好的耦合抑制效果,最后将双频...
  • 推导了斜入射法检测平面反射镜面形的公式,并考虑了此方法可能引入的误差。对尺寸为124 mm×42 mm的平面反射镜分别在垂直和不同斜入射角条件下进行了测量,垂直入射时测得镜子工作表面面形起伏高度均方根(RMS)和...
  • Unity URP Planar reflection 平面反射

    千次阅读 2020-12-26 23:15:14
    把RenderTexture传入后处理shader,模板测试需要两个shader,一个后处理一个平面,因为有模板测试所以后处理只会渲染在平面上 如果用屏幕坐标,只需要一个平面的shader,把传入的RenderTexture用屏幕坐标采样,和主...
  • 采用V形地平面反射天线向馈电结构的辐射,调整了天线的输入匹配状况和辐射方向图。使用专业射频(RF)和微波软件进行数值仿真,分析地平面延伸角度和延伸位置对天线输入反射损耗和辐射方向图的影响,得到优化的天线...
  • OpenGL渲染纹理和平面反射先上图,再解答。完整主要的源代码源代码剖析 先上图,再解答。 完整主要的源代码 #include <stdio.h> #include "GL/glus.h" #include "wavefront.h" static GLfloat g_viewMatrix...
  • 首先采用快慢轴准直透镜压缩LDA的发散角, 然后采用双平行平面反射镜光束整形装置, 将压缩后的LDA慢轴方向的光束分为4束(也可以根据需要分为任意多束), 并将4束子光束在快轴方向重新排列, 最后通过聚焦系统, 将整形后...
  • 面向聚类的平面反射数据扰动方法.pdf
  • 基于反射相机的平面反射实现

    千次阅读 2021-12-10 19:53:57
    此方法并不依赖shader,而是使用MonoBehaviour脚本(挂载到反射平面或者相机上) 核心思路: 简单粗暴,利用脚本创建一个新的相机,这个相机与主相机参数位置一致,将此相机的图像翻转即可,大体步骤为 创建一...
  • 同抛物面反射器相比,菲涅尔区相位修正平面反射器的相位效率因子对天线效率的影响显著。本文在讨论其效率因子组成的基础上,首先定义了这一因子,并导出其数学表达式。通过具体的数值计算,给出图表形式的结果,可为...
  • 菲涅尔区相位修正平面反射器天线具有较好的偏轴扫描特性。作者以物理光学方法为手段,通过考察该类反射器对不同角度入射平面波所形成的聚焦场,从理论上深入探讨其偏轴扫描特性。数值计算所给出的一组曲线有助于对该...
  • 面向隐私保护聚类的平面反射数据扰动方法.pdf
  • 平面反射 openGL实例

    2009-06-15 19:58:29
    平面反射 openGL实例 ile for "Drawing Reflections" lesson of the OpenGL tutorial on * www.videotutorialsrock.com
  • 行业分类-物理装置-一种连续平面反射式光链路的光束抖动仿真方法.zip
  • AdamPlaneReflection:来自Adam内部环境包的平面反射效果
  • 电信设备-一种移动补偿式平面反射镜激光干涉仪及使用方法.zip
  • 行业分类-设备装置-一种运动平台上平面反射镜的支撑结构.zip
  • 行业分类-设备装置-一种磁性微位移平台式平面反射镜激光干涉仪
  • 行业分类-设备装置-一种磁性微位移平台式阶梯平面反射镜激光干涉仪
  • 行业分类-电子电器-一种复杂电磁环境信号产生仪.zip
  • 行业分类-设备装置-一种磁性微位移平台式平面反射镜激光干涉仪及标定方法和测量方法

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,529
精华内容 8,611
关键字:

平面反射