Unity URP 平面反射原理详解 Planar Reflection

Unity Lighting -- 改善场景的反射光照效果 先来看个案例问题,下图中,苹果的反射效果看起来是很奇怪的。在它的表面上反射了两种不同颜色的Spot Light光源,还反射了不属于室内环境的来自天空盒的光线,这是有问题的。在解决这个问题之前,我们需要知道在Unity中反射是如何工作的。 阅读详情

一、平面反射概述

平面反射(Planar Reflection)是计算机图形学中模拟光滑平面(如水面、镜面、抛光地面)反射效果的核心技术。它能够实时生成倒影,让场景更加真实和生动。

在Unity的通用渲染管线(URP)中,实现平面反射需要综合运用以下技术:

  • 反射矩阵计算:将世界空间中的物体沿反射平面进行镜像翻转
  • 反射相机:从镜像视角渲染场景到RenderTexture
  • 斜截视锥体:优化反射相机的裁剪平面,避免渲染不必要的区域
  • Shader投影:将反射纹理正确投影到反射平面上

💡 应用场景:平面反射广泛应用于水面效果、镜面反射、抛光地面、冰面反射等需要真实倒影的场景中。

二、平面反射基本原理

2.1 核心思想

平面反射的核心思想是模拟光线反射:在反射平面的一侧放置一个虚拟的"反射相机",这个相机的位置是主相机关于反射平面的镜像位置,它看到的内容就是倒影应该显示的内容。

2.2 两种实现思路

实现方式核心逻辑特点
无反射矩阵法1. 计算主相机关于反射平面的对称位置,生成反射相机
2. 反射相机渲染的画面需要颠倒Y轴作为UV采样
矩阵计算量较大,逻辑直观
反射矩阵法(推荐)1. 反射相机和主相机位置相同,在MVP变换的V矩阵前插入反射矩阵,将整个世界沿平面镜像
2. 采样时无需颠倒Y轴
计算量更小,是主流实现方式

⚠️ 注意:反射矩阵是左乘,实际是加在M矩阵之后、V矩阵之前,而非网传V矩阵之后。修改反射相机的worldToCameraMatrix后,再修改其transform无实际意义。

三、反射矩阵推导

3.1 数学原理

反射矩阵的作用是将世界空间中任意点变换为关于目标平面的对称点。

推导过程:

  1. 已知平面单位法向量 $\vec{N}(x_n, y_n, z_n)$,平面上任意点 $P_0(x_0, y_0, z_0)$
  2. 任意点 $P(x, y, z)$ 的对称点 $P'(x', y', z')$ 满足: $$P' = P - 2\vec{N} \cdot \|PQ\|$$
  3. 其中$\|PQ\|$是P到平面的带符号距离,代入平面方程展开后得到反射矩阵

反射矩阵公式:

$$M=\begin{bmatrix}
1-2x_n^2 & -2y_nx_n & -2z_nx_n & -2x_nd \\
-2x_ny_n & 1-2y_n^2 & -2z_ny_n & -2y_nd \\
-2x_nz_n & -2y_nz_n & 1-2z_n^2 & -2z_nd \\
0 & 0 & 0 & 1
\end{bmatrix}$$

其中 $d = -\vec{N} \cdot P_0$,即平面方程的常数项。

3.2 代码实现

以下是C#中计算反射矩阵的实现:

private static Matrix4x4 CalculateReflectionMatrix(Vector4 plane)
{
    Matrix4x4 reflectionMat = Matrix4x4.identity;
    
    // 平面方程: ax + by + cz + d = 0
    // plane = (a, b, c, d)
    float a = plane.x;
    float b = plane.y;
    float c = plane.z;
    float d = plane.w;
    
    reflectionMat.m00 = 1f - 2f * a * a;
    reflectionMat.m01 = -2f * a * b;
    reflectionMat.m02 = -2f * a * c;
    reflectionMat.m03 = -2f * a * d;
    
    reflectionMat.m10 = -2f * b * a;
    reflectionMat.m11 = 1f - 2f * b * b;
    reflectionMat.m12 = -2f * b * c;
    reflectionMat.m13 = -2f * b * d;
    
    reflectionMat.m20 = -2f * c * a;
    reflectionMat.m21 = -2f * c * b;
    reflectionMat.m22 = 1f - 2f * c * c;
    reflectionMat.m23 = -2f * c * d;
    
    reflectionMat.m30 = 0f;
    reflectionMat.m31 = 0f;
    reflectionMat.m32 = 0f;
    reflectionMat.m33 = 1f;
    
    return reflectionMat;
}

四、反射相机实现

4.1 斜截视锥体(Oblique View Frustum)

问题描述:默认反射相机的视锥体和主相机完全一致,会导致反射画面包含反射平面"背后"的物体(即反射平面下方的物体),出现错误的倒影。

解决方案:将反射相机的近裁剪面设置为反射平面本身,仅渲染平面"上方"的内容。

Unity提供了内置API:Camera.CalculateObliqueMatrix(),可以直接计算斜裁剪矩阵。

手动实现斜截矩阵的核心原理:

  1. 平面变换规则:平面是共变向量,从视空间变换到裁剪空间需要用投影矩阵的逆的转置
  2. 投影矩阵修改规则:只能修改投影矩阵的第3行(第4行负责透视矫正插值,不能修改)
  3. 修改后近平面变为目标反射平面,远平面会相应调整

4.2 URP中的渲染回调

在URP中,需要使用URP的渲染事件系统来插入反射渲染逻辑。主要使用以下回调:

回调事件触发时机用途
RenderPipelineManager.beginCameraRendering每个相机开始渲染前执行反射渲染逻辑
RenderPipelineManager.endCameraRendering每个相机渲染结束后清理状态

URP 14+ 渲染API:

// 创建渲染请求
var request = new UniversalRenderPipeline.SingleCameraRequest();
if (RenderPipeline.SupportsRenderRequest(_reflectionCamera, request))
{
    // 提交反射相机渲染请求
    RenderPipeline.SubmitRenderRequest(_reflectionCamera, request);
}

五、Shader实现

5.1 基础平面反射Shader

以下是一个适用于URP的完整平面反射Shader:

Shader "Custom/PlanarReflection_URP"
{
    Properties
    {
        // 主贴图(地面/水面纹理)
        _BaseMap ("Base Map", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1,1,1,1)
        
        // 反射 RenderTexture(由 C# 脚本自动设置)
        _ReflectionTex ("Reflection Texture", 2D) = "black" {}
        // 反射强度(0=无反射,1=完全镜面)
        _ReflectionStrength ("Reflection Strength", Range(0, 1)) = 0.5
        // 反射颜色叠乘(可给倒影添加色调)
        _ReflectionTint ("Reflection Tint", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags
        {
            "RenderPipeline" = "UniversalRenderPipeline"
            "Queue" = "Geometry"
            "RenderType" = "Opaque"
        }

        Pass
        {
            Name "PlanarReflectionPass"
            Tags { "LightMode" = "UniversalForward" }
            
            Cull Back
            ZWrite On
            Blend Off

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            // 贴图声明
            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);
            TEXTURE2D(_ReflectionTex);
            SAMPLER(sampler_ReflectionTex);

            // 材质属性
            float4 _BaseMap_ST;
            float4 _BaseColor;
            float  _ReflectionStrength;
            float4 _ReflectionTint;

            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv         : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv          : TEXCOORD0;
                float4 screenPos   : TEXCOORD1;  // 屏幕空间坐标
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
            };

            Varyings vert(Attributes v)
            {
                Varyings o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

                o.positionHCS = TransformObjectToHClip(v.positionOS.xyz);
                o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
                // 计算屏幕空间坐标
                o.screenPos = ComputeScreenPos(o.positionHCS);

                return o;
            }

            half4 frag(Varyings i) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(i);

                // 1. 采样主贴图
                half4 baseCol = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv);
                baseCol *= (half4)_BaseColor;

                // 2. 采样反射RT(屏幕空间UV需做透视除法)
                float2 reflUV = i.screenPos.xy / i.screenPos.w;
                half4 reflCol = SAMPLE_TEXTURE2D(_ReflectionTex, sampler_ReflectionTex, reflUV);
                reflCol *= (half4)_ReflectionTint;

                // 3. 混合基础色和反射
                half3 finalColor = lerp(baseCol.rgb, reflCol.rgb, _ReflectionStrength);

                return half4(finalColor, baseCol.a);
            }
            ENDHLSL
        }
    }
}

5.2 高级效果扩展

5.2.1 菲涅尔控制反射强度

模拟真实世界的反射规律:正面看反射弱,掠射角看反射强。

// 在Varyings中新增世界法线和世界空间视角方向
float NdotV = saturate(dot(normalWS, viewDirWS));
float fresnel = pow(1.0 - NdotV, 3.0);
// 菲涅尔调制后的反射强度
float reflStrength = lerp(_ReflectionStrength * 0.3, _ReflectionStrength, fresnel);
half3 finalColor = lerp(baseCol.rgb, reflCol.rgb, reflStrength);
5.2.2 法线扰动倒影(水面波纹效果)

用法线贴图偏移反射UV,模拟水面波纹。

// 采样法线贴图
float3 bumpNormal = UnpackNormal(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, i.uv));
// 用法线XY分量偏移反射UV
float2 reflUV = i.screenPos.xy / i.screenPos.w;
reflUV += bumpNormal.xy * _DistortionStrength;
half4 reflCol = SAMPLE_TEXTURE2D(_ReflectionTex, sampler_ReflectionTex, reflUV);
5.2.3 模糊反射(粗糙地面效果)

对反射RT做模糊采样,模拟粗糙表面的模糊倒影。

float2 texelSize = 1.0 / float2(_ScreenParams.x, _ScreenParams.y);
half3 blur = half3(0,0,0);
// 3x3卷积模糊
for (int x = -1; x <= 1; x++)
    for (int y = -1; y <= 1; y++)
        blur += SAMPLE_TEXTURE2D(_ReflectionTex, sampler_ReflectionTex,
                reflUV + float2(x, y) * texelSize * _BlurRadius).rgb;
blur /= 9.0;

六、C# 控制脚本

以下是完整的平面反射控制器脚本,适配URP管线:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

/// <summary>
/// 平面反射控制器,挂载到反射平面对象上
/// </summary>
[ExecuteAlways]
public class PlanarReflection : MonoBehaviour
{
    [Header("===== 反射设置 =====")]
    [SerializeField] private int _textureSize = 512;          // RT分辨率
    [SerializeField] private float _clipPlaneOffset = 0.01f;  // 裁剪面偏移
    [SerializeField] private LayerMask _reflectionLayers = -1; // 反射层过滤
    [SerializeField] private bool _renderShadows = false;      // 是否渲染阴影

    private Camera _reflectionCamera;
    private RenderTexture _reflectionRT;
    private Material _material;
    private static readonly int ReflectionTexID = Shader.PropertyToID("_ReflectionTex");

    void OnEnable()
    {
        // 获取反射平面的材质
        Renderer renderer = GetComponent<Renderer>();
        if (renderer != null)
            _material = renderer.sharedMaterial;
        
        CreateReflectionCamera();
        CreateRenderTexture();

        // 注册URP渲染回调
        RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
    }

    void OnDisable()
    {
        RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
        CleanUp();
    }

    private void OnBeginCameraRendering(ScriptableRenderContext context, Camera cam)
    {
        // 仅处理主摄像机和场景视图摄像机
        if (cam.cameraType != CameraType.Game && cam.cameraType != CameraType.SceneView)
            return;
        if (cam == _reflectionCamera)
            return;

        RenderReflection(cam);
    }

    private void RenderReflection(Camera mainCamera)
    {
        if (_material == null)
            return;

        // 1. 计算反射平面参数
        Vector3 planePos = transform.position;
        Vector3 planeNormal = transform.up;

        // 2. 计算反射矩阵
        float d = -Vector3.Dot(planeNormal, planePos) - _clipPlaneOffset;
        Vector4 reflectionPlane = new Vector4(planeNormal.x, planeNormal.y, planeNormal.z, d);
        Matrix4x4 reflectionMatrix = CalculateReflectionMatrix(reflectionPlane);

        // 3. 设置镜像摄像机参数
        _reflectionCamera.cullingMask = _reflectionLayers;
        _reflectionCamera.targetTexture = _reflectionRT;
        // 镜像摄像机的观察矩阵 = 主摄像机观察矩阵 × 反射矩阵
        _reflectionCamera.worldToCameraMatrix = mainCamera.worldToCameraMatrix * reflectionMatrix;

        // 4. 设置斜裁剪面
        Vector4 clipPlane = CameraSpacePlane(_reflectionCamera, planePos, planeNormal);
        _reflectionCamera.projectionMatrix = mainCamera.CalculateObliqueMatrix(clipPlane);

        // 5. 翻转剔除方向(反射后三角形绕序反转)
        GL.invertCulling = true;

        // 6. URP 14+ 推荐渲染API
        var request = new UniversalRenderPipeline.SingleCameraRequest();
        if (RenderPipeline.SupportsRenderRequest(_reflectionCamera, request))
            RenderPipeline.SubmitRenderRequest(_reflectionCamera, request);

        GL.invertCulling = false;

        // 7. 将渲染好的RT传递给材质
        _material.SetTexture(ReflectionTexID, _reflectionRT);
        
        // 或者使用全局纹理(适用于多个反射平面共享)
        // Shader.SetGlobalTexture(ReflectionTexID, _reflectionRT);
    }

    // 计算反射矩阵
    private static Matrix4x4 CalculateReflectionMatrix(Vector4 plane)
    {
        Matrix4x4 m = Matrix4x4.identity;
        m.m00 = 1f - 2f * plane.x * plane.x;
        m.m01 = -2f * plane.x * plane.y;
        m.m02 = -2f * plane.x * plane.z;
        m.m03 = -2f * plane.x * plane.w;

        m.m10 = -2f * plane.y * plane.x;
        m.m11 = 1f - 2f * plane.y * plane.y;
        m.m12 = -2f * plane.y * plane.z;
        m.m13 = -2f * plane.y * plane.w;

        m.m20 = -2f * plane.z * plane.x;
        m.m21 = -2f * plane.z * plane.y;
        m.m22 = 1f - 2f * plane.z * plane.z;
        m.m23 = -2f * plane.z * plane.w;

        m.m30 = 0; m.m31 = 0; m.m32 = 0; m.m33 = 1;
        return m;
    }

    // 将世界空间平面转换到摄像机空间
    private Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal)
    {
        Matrix4x4 worldToCam = cam.worldToCameraMatrix;
        Vector3 camPos = worldToCam.MultiplyPoint(pos);
        Vector3 camNormal = worldToCam.MultiplyVector(normal).normalized;
        return new Vector4(camNormal.x, camNormal.y, camNormal.z, -Vector3.Dot(camPos, camNormal));
    }

    // 创建镜像摄像机
    private void CreateReflectionCamera()
    {
        if (_reflectionCamera != null) return;

        GameObject go = new GameObject("ReflectionCamera");
        go.hideFlags = HideFlags.HideAndDontSave;
        _reflectionCamera = go.AddComponent<Camera>();
        _reflectionCamera.enabled = false;  // 手动控制渲染

        // URP需要添加UniversalAdditionalCameraData组件
        var cameraData = go.AddComponent<UniversalAdditionalCameraData>();
        cameraData.requiresColorOption = CameraOverrideOption.Off;
        cameraData.requiresDepthOption = CameraOverrideOption.Off;
        cameraData.renderShadows = _renderShadows;
    }

    // 创建反射RT
    private void CreateRenderTexture()
    {
        if (_reflectionRT != null && _reflectionRT.width == _textureSize) return;

        if (_reflectionRT != null)
            _reflectionRT.Release();

        _reflectionRT = new RenderTexture(_textureSize, _textureSize, 16, RenderTextureFormat.ARGB32);
        _reflectionRT.name = "PlanarReflectionRT";
    }

    // 清理资源
    private void CleanUp()
    {
        if (_reflectionRT != null)
        {
            _reflectionRT.Release();
            _reflectionRT = null;
        }
        if (_reflectionCamera != null)
        {
            DestroyImmediate(_reflectionCamera.gameObject);
            _reflectionCamera = null;
        }
    }
}

七、Planar Reflections for Unity 插件

7.1 插件简介

Planar Reflections for Unity 是一个开源的Unity插件,提供了创建平面反射的完整解决方案。该插件支持Unity的内置渲染管线和通用渲染管线(URP)。

📦 插件信息:

  • GitHub仓库:eldskald/planar-reflections-unity
  • 支持管线:Built-in Pipeline、URP
  • 开源协议:MIT License
  • 核心功能:平面反射探针(Planar Reflections Probe)组件

7.2 安装配置

安装步骤:

  1. 从GitHub下载插件源代码
  2. 根据使用的渲染管线,将对应文件夹复制到项目中:
    • Built-in Pipeline:复制 src/built-in 文件夹
    • URP:复制 src/urp 文件夹
  3. 等待Unity编译完成
  4. 在GameObject上添加 Planar Reflections Probe 组件

7.3 组件参数说明

参数类型说明
targetTextureIDint纹理槽位ID(0-3),支持多个反射面同时使用
useCustomNormalbool是否使用自定义法线方向
customNormalVector3自定义的法线方向(当useCustomNormal开启时)
reflectionsQualityfloat反射纹理分辨率倍率(0.25, 0.5, 0.75, 1.0等)
farClipPlanefloat反射相机的远裁剪面距离
renderBackgroundbool是否渲染背景(天空盒等)
renderInEditorbool是否在Editor中实时渲染反射

7.4 使用方法

步骤1:配置反射探针
  1. 在场景中创建一个GameObject
  2. 添加 Planar Reflections Probe 组件
  3. 将GameObject放置在反射平面上(如水面)
  4. 确保Transform的Forward向量(蓝色箭头)指向平面外

✅ 技巧:将探针放在水面上,这样当移动或旋转水面时,反射会自动保持正确。注意旋转方向,探针的蓝色箭头必须垂直于水面。

步骤2:编写支持反射的Shader

在Shader中包含插件提供的cginc文件,并使用 SampleReflections(screenUV) 函数采样反射:

// URP示例Shader(部分代码)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

// 如果使用的是插件的URP版本,需要定义关键字
#pragma multi_compile _ _PRID_ONE _PRID_TWO _PRID_THREE _PRID_FOUR

// 在片元着色器中采样反射
float2 screenUV = i.screenPos.xy / i.screenPos.w;
half4 reflection = SampleReflections(screenUV);

可以参考插件Demo中的示例Shader:

  • Built-in Pipeline:demo/Assets/Shaders/Built-In/Water.shader
  • URP:demo/Assets/Shaders/URP/PlanarGroundURP.shader
步骤3:多个反射面

如果场景中有多个反射面(如多个水面),可以创建多个探针,每个探针设置不同的 targetTextureID(0-3),Shader中使用对应的关键字(_PRID_ONE, _PRID_TWO等)。

⚠️ 性能警告:每个探针都会产生一次额外的相机渲染调用,多个反射面会成倍增加GPU开销。建议实际项目中仅对主要反射面做实时反射。

公共方法

插件提供了以下公共方法用于运行时控制:

方法说明
IgnoreCamera(Camera cam)忽略指定相机的反射渲染
UnignoreCamera(Camera cam)取消忽略指定相机
IsIgnoring(Camera cam)检查是否忽略指定相机
ClearIgnoredList()清空忽略列表

八、性能优化建议

平面反射是一个性能开销较大的特效,以下是常用的优化策略:

  1. 降低RT分辨率
    • 推荐使用512×512或256×256
    • 仅在特写镜头时使用1024×1024
    • 避免使用全屏分辨率
  2. Layer过滤
    • 仅勾选需要产生倒影的物体层
    • 排除粒子、UI、小道具等无关内容
    • 排除反射面自身的层(避免无限递归)
  3. 关闭阴影
    • 反射相机不需要渲染阴影
    • 设置 renderShadows = false
  4. 距离剔除
    • 设置较小的 farClipPlane
    • 远处物体不需要产生倒影
  5. 按需渲染
    • 不需要每帧更新反射
    • 可隔2-3帧更新一次RT
    • 或仅在主摄像机移动时更新
  6. 降低渲染质量
    • 临时降低LOD Bias
    • 关闭雾效
    • 使用更简单的Shader变体

💡 优化技巧:可以使用QualitySettings.lodBias和QualitySettings.maximumLODLevel在反射渲染时临时降低模型质量,反射渲染完成后再恢复,这样可以显著提升性能。

九、常见问题与解决方案

问题原因解决方案
倒影上下颠倒反射平面法线方向错误检查transform.up是否正确指向上方
倒影中出现反射面自身(无限递归)反射面被包含在反射层中将反射面放到单独的Layer,在_reflectionLayers中排除该层
反射面边缘闪烁/锯齿斜裁剪面和反射面完全重合导致浮点精度问题调大_clipPlaneOffset(建议0.02~0.05)
性能开销过高RT分辨率过高或未过滤反射层降低RT分辨率、过滤反射层、关闭阴影、设置远裁剪面
反射纹理显示为黑色反射相机未正确渲染或RT未传递检查脚本是否正确挂载、URP回调是否注册成功
倒影位置偏移反射矩阵计算错误检查平面法线和位置的计算是否正确

 

 

URP屏幕空间反射(SSR)实现指南:从原理到性能优化 屏幕空间反射(SSR)是一种实时渲染技术,它利用当前帧已渲染的屏幕颜色和深度信息,模拟光线在表面间的反射行为。其核心原理是通过射线步进算法,在屏幕空间内追踪反射光线并与场景深度进行比较,从而动态生成反射效果。这项技术的价值在于能够以相对较低的性能开销,为水面、金属、光洁地板等表面提供动态、高精度的环境反射,显著提升场景的真实感和沉浸感。在Unity URP项目中实现SSR,需要深入理解其渲染管线架构,通过自定义Renderer Feature和全屏着色器,结合深度纹理与GBuffer数据,并针对性能优化和常 阅读详情

相关推荐

Unity Shader-反射效果(CubeMap,Reflection Probe,Planar Reflection,Screen Space Reflection)

简介 反射效果,是一个渲染中很重要的一个效果。在表现光滑表面(金属,光滑地面),水面(湖面,地面积水)等材质的时候,加上反射,都可以画面效果有很大的提升。来看几张图: 先来张最近比较火爆的国产大作《逆水寒》的镜湖,我木有钱钱进副本,只好从网上找了个截图,感觉很漂亮哈。 《罗马之子》主角的金属盔甲反射&amp;远处水面倒影反射。 《耻辱-外魔之死》地面积水的反射,只反射了静态场景...

puppet_master的专栏 5万+

Unity下平面反射实现

平面反射通常指的是在镜子或者光滑地面的反射效果上,如下图所示, 上图是一个光滑的平面,平面上的物体在平面上有对称的投影。 一、平面反射的原理 对于光照射到物体表面然后发生完美镜面反射的示意图,如下所示, 对于平面反射,假设平面上任意一点都会发生完美的镜面反射。因此,眼睛看到物体的一点的反射信息是从反射向量处得到的,这个可以用下图来表示, 这个实际上相当于,眼睛从平面的下面看向反射向量,如下图所示, 因此,如上图所示,我们可以把摄像机根据平面对称变换到A点所示的位置,然后再渲染一遍场景到RenderT

远行's Blog 7532

[Unity] ShaderGraph实现完美倒影 or 平面镜反射效果

[Unity] ShaderGraph实现完美倒影 or 平面镜反射效果

连连看爱好者 5827

Unity URP Planar reflection 平面反射

利用双休天写的,代码和shader还有不少问题 修复中。。。。

lvcoc的博客 5787

Shader实例:Planar Reflection 平面反射

目前采用比较多的反射,最终效果示例: 代码已经中文注解,有2部分需扩展:反射矩阵、歪截头体矩阵。注解中有来源链接可以去理解推导过程。 可用于镜面和水面。 咱还是直接看注解过的代码 MirrorReflection.cs using UnityEngine; using System.Collections; using UnityEditor; [ExecuteInEditMode] public class MirrorReflection : MonoBehaviour { //public Ma

fjl2007的博客 1916

unity地面反射插件

Realtime Planar Reflections 1.5是一款基于unity引擎做的地面反射插件,增强环境效果,让你的场景显得更加真实可靠。

移动端屏幕空间平面反射:高效实现水面与光滑表面动态倒影

实时反射是提升游戏与交互应用视觉沉浸感的关键技术之一,其核心原理在于模拟光线在光滑表面的物理行为,通过计算生成物体倒影。传统方案如反射探针或完整平面反射,在移动端常面临性能瓶颈。屏幕空间反射技术则另辟蹊径,它复用当前帧已渲染的深度与颜色信息,在屏幕空间内高效推算反射结果,实现了性能与效果的平衡。这一技术对于移动游戏开发尤其具有价值,能在中低端设备上,以极低开销为水面、冰面、光滑地板等场景增添动态细节,显著提升视觉品质。本文介绍的移动端优化方案,正是基于这一思路,通过Compute Shader与URP Re

dielucui7698的博客 356

Unity Planar Reflection平面反射

Unity Planar Reflection平面反射

【UnityShader】利用平面反射技术制作水面效果

咋一看好像效果挺好,但与噪声扰动一样,在地平线的接线处产生了非常生硬的过渡,为了消除这些过渡,我们采用与解决噪声图扰动瑕疵类似的方法,使用Shader入门精要当中计算线性雾的公式来消除最边缘的高光(最后还要把得到的值remap到(0,1)的范围)。但如此实现会比较困难,此时我们可以以平面为对称线,在平面对面实例化一个完全对称的相机,用于观看平面反射之后的结果,并将看到的画面打印成一张RenderTexture,就可以实现类似的效果了。我们可以通过噪声图扰动现在的反射结果,来模拟水中的波纹效果(如上图)。

2301_79973945的博客 2920

VS Code配置Java开发环境避坑指南:从JDK到Spring Boot插件全流程

本文详细介绍了在VS Code中配置Java开发环境的完整流程,涵盖JDK选择、环境变量配置、核心插件安装、构建工具优化及Spring Boot项目专项设置。特别针对常见问题提供避坑方案,帮助开发者快速搭建高效稳定的开发环境,提升Java和Spring Boot开发效率。

weixin_28839699的博客 977

DDS器件原理与应用(AD9833 AD9834)

是DDS的核心组成部分,用于实现相位的累加,并输出相应的幅值。相位累加器由M位宽加法器和M位宽寄存器组成,通过时钟控制,将上一次累加结果反馈到加法器输入端实现累加功能,从而使每个时钟周期内的相位递增数为,并取相位累加结果作为地址输出给ROM查找表部分。DDS的相位信息被存放在累加寄存器中,虽然幅值和相位不是线性关系,但寄存器累加值和相位可以是线性关系,很容易用寄存器的累加值表达相位信息。

m0_49968063的博客 6443

Unity URP 平面反射

https://www.bilibili.com/video/BV1TA4y1D7s4/?spm_id_from=333.999.0.0&vd_source=5672eeb8a9721da01495e313f0dff6c2https://zhuanlan.zhihu.com/p/493766119 PlannarReflectionTest.cs 挂载在平面对象上 // https://...

kingBook928的博客 1047

蓝桥杯FPGA赛道积分赛

代码如下: 按键驱动 代码如下 按键驱动 代码如下: 顶层文件 按键驱动 数码管驱动 声明:本代码借鉴网络资料,如有侵权和错误请联系作者删除。我是从寒假开始备赛的,由于我基础不行,备赛过程中也是混混呃呃的,备赛效率不高,总体来说备赛不认真,有点拖拉,但是最后我也坚持备赛到了今天,在备赛过程中,即复习了旧的东西,也学到了新的东西,总结起来还是有点收获的,后天北京、天津、河北地区就要进行省赛了,我会全力以赴,不管结果怎么样,尽力就好,最后祝大家都能

weixin_69804913的博客 1983

Unity3d地形反光

今天在做飞行项目的时候发现创建的地形出现光照反光情况,反光效果如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200222214002546.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Fx...

qq_20019721的博客 4986

揭秘Outlook/QQ邮箱伪造:如何利用Unicode编码绕过SPF检测

本文深入剖析了利用Unicode编码进行邮件显示名伪造的攻击手法,揭示了攻击者如何通过插入零宽字符等特殊编码绕过SPF检测,使邮件在Outlook、QQ邮箱等客户端中看似来自可信发件人。文章通过Python代码示例演示了伪造过程,并提供了从用户自查到管理员部署DMARC策略的多层次防御建议。

weixin_29063035的博客 332

Aras Innovator系统配置-01对象类(一)

对象类配置-对象类属性说明

企业信息化(PLM,ERP.MES) 2032

unity中使用反射

它允许程序在运行时获取类型信息、访问对象的属性和方法,并动态地创建对象实例、调用方法和操作属性。调用方法和访问属性:反射允许您在运行时动态调用对象的方法和访问其属性。获取类型信息:反射可以用来获取类、结构体、枚举和接口等类型的信息,包括名称、命名空间、成员变量、方法、属性等。请注意,反射调用方法和访问属性时,需要确保方法和属性是可访问的(例如,公共方法和公共属性)。请注意,使用反射创建对象实例时,需要确保类型是可实例化的,并且具有公共的构造函数。需要注意的是,在动态加载程序集时,确保程序集存在并且可访问。

麦迪儿的博客 3624

华为OD机试真题 新系统 9月16号 【园区基站节能部署规划】

华为OD机试真题 新系统【园区基站节能部署规划】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题 【园区基站节能部署规划】多语言题解。

qq_45776114的博客 352

Unity渲染菜B之 普通版平面反射

一个简单版的Unity平面反射渲染实现

qq_37373780的博客 1532

Week 9 10 Neural Networks

Week 9 10 Neural Networks

金州饿霸吃不饱的博客 403

YOLOv13零基础手把手教程:在 YOLOv13 中集成 SFSConv,YOLOv13让目标检测更上一层楼

YOLOv13本教程详细介绍了如何在YOLOv13中集成SFSConv模块以提升目标检测性能。YOLOv13 SFSConv创新性地结合了分数伽柏滤波和分数傅里叶变换,通过空间处理单元(SPU)和频率处理单元(FPU)解耦处理特征。实验表明,该模块可使准确率提升5.21%,mAP提高11.45%。教程从原理分析到代码实现,系统讲解了SFSConv的数学基础、模块设计,并提供了在YOLOv13中集成该模块的详细步骤,包括配置文件修改、核心代码实现等。

FJN110的博客 2175

Unity实时反射——AngryBots示例项目地面实时反射效果剖析

Angry Bots是Unity安装程序自带的开源示例项目。该示例项目虽然已经发布很久了,但是其很多设计和实现仍然具有参考价值。运行该项目仔细观察,可以发现其雨天地面效果是实时反射的。这里我们先阐明实时反射的原理,然后分析其绘制流程。构造反射相机视图矩阵反射相机的视图矩阵由反射矩阵变换得到,反射矩阵由反射平面确定,下面列出反射矩阵推导过程。反射位置 反射方向 M1*M2即得到示例代码所示的反射矩

bill2ccssddnn的专栏 7930

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

平面反射builltin&URP—— UnityShader学习记笔记

文章目录自言自语一、C# builltin首先声明一个枚举来设置RT尺寸然后进行场景初始化清理在OnwillRender方法中传参并调用平面反射的具体运算进行场景物件的平面反射计算 (这里我把场景角色做了区分,分别用两个反射相机来做。可以实现更多自定义。原理都一样 就只放一个场景的吧)另外Camera.main 和 Camera.current 在不同Unity版本和管线产生的观察效果不同.至于为什么不懂..可能是Unity玄学.这点在相应代码处已注释明白最后在Disable下清除反射相机和RT实时计算相机

ezcome11的博客 3513

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【Unity Shader URP】平面反射(Planar Reflection)实战教程

平面反射(Planar Reflection)是让地面、水面、镜面产生实时倒影的经典技术:用一个镜像摄像机从反射角度渲染场景,把结果投影到反射平面上。效果真实、原理直观,是中级 Shader 的标志性练习。

Fresh_Free的博客 694

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Unity URP Reflection

工程地址:https://download.youkuaiyun.com/download/May11st/22227381 Package地址:https://download.youkuaiyun.com/download/May11st/22227213 将Package解压到D盘,然后再打开工程。 效果图: 原理:创建一个反射相机,其参数和主相机相同,其位置与主相机相对于反射物体对称(只适用与反射物体和y轴垂直的情况,例如地面),反射相机的画面渲染到一个 RenderTexture上。然后在反射物体的sh.

May11st的博客 1669

探索Unity URP:移动设备上的高效屏幕空间平面反射

探索Unity URP:移动设备上的高效屏幕空间平面反射 UnityURP-MobileScreenSpacePlanarReflectionReusable RendererFeature of MobileScreenSpacePlanarReflection项目地址:https://gitcode.com/gh_mirrors/un/UnityURP-MobileScreenSpacePl...

gitblog_00079的博客 1108
上一篇: Unity Shader 使用裁减空间结合Reversed Z 实现天空盒在NDC远裁面
下一篇: Unity URP Exposure曝光原理与实战应用
mxwin
博客等级 码龄19年 22粉丝 151原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值