shader实例(五)GrabPass捕捉屏幕纹理

本文介绍了在Unity中使用Shader通过GrabPass及顶点、片段着色器来抓取屏幕纹理的方法,并对比了不同方法抓取到的屏幕纹理的区别。同时,提供了使用摄像机将渲染内容写入RenderTexture的替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  shader实例(五)GrabPass捕捉屏幕纹理 

1.固定管线版本:

Shader "Custom/Grab" {
 Properties {
  //_MainTex ("Base (RGB)", 2D) = "white" {}
 }
 SubShader {
  // 在所有不透明对象之后绘制自己,更加靠近屏幕
  Tags { "Queue" = "Transparent" }
  // 通道1:捕捉对象之后的屏幕内容放到_GrabTexture纹理中
  GrabPass{}
  // 通道2:设置材质
  Pass{
   // 使用上面产生的纹理,进行颜色反相(1-原材质色)
   SetTexture[_GrabTexture]{combine one-texture}
  }
 }
 FallBack "Diffuse"
}
效果如下,它是取模型背后的屏幕纹理:
shader实例(十六)GrabPass捕捉屏幕纹理

2.顶点,片段版本:

Shader "Custom/GrabAllVF" {
 Properties {
  //_MainTex ("Base (RGB)", 2D) = "white" {}
 }
 SubShader {
  // 在所有不透明对象之后绘制自己,更加靠近屏幕
  Tags{"Queue"="Transparent"}
  // 通道1:捕捉屏幕内容放到_GrabTexture纹理中
  GrabPass{} 
  // 通道2:设置材质
  Pass{
   Name "pass2"
   CGPROGRAM
   #pragma vertex vert
            #pragma fragment frag
   #include "UnityCG.cginc"
   sampler2D _GrabTexture;
   float4 _GrabTexture_ST;
   // 片段程序的输入
   struct v2f {
                float4  pos : POSITION;
                float2  uv : TEXCOORD0;
            };
   v2f vert (appdata_base v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _GrabTexture);
                return o;
            }
   float4 frag (v2f i) : COLOR
            {
            half4 texCol = tex2D(_GrabTexture, float2(1-i.uv.x , 1-i.uv.y));
             // 颜色反相,便于观察效果
                return 1 - texCol;
            }
   ENDCG
  }
 }
 FallBack "Diffuse"
}
效果如下:取到的是全屏的纹理:
shader实例(十六)GrabPass捕捉屏幕纹理
1和2为什么取到的屏幕纹理不一样呢?

3.使用vf的方式,只获取物体后面的屏幕纹理,后面的扭曲效果会用到此方式,代码如下:

Shader "Custom/GrabVF" {
 Properties {
  //_MainTex ("Base (RGB)", 2D) = "white" {}
 }
 SubShader {
  // 在所有不透明对象之后绘制自己,更加靠近屏幕
  Tags{"Queue"="Transparent"}
  // 通道1:捕捉对象之后的屏幕内容放到_GrabTexture纹理中
  GrabPass{} 
  // 通道2:设置材质
  Pass{
   Name "pass2"
   CGPROGRAM
   #pragma vertex vert
   #pragma fragment frag
   #include "UnityCG.cginc"
   sampler2D _GrabTexture;
   float4 _GrabTexture_ST;
   struct v2f {
                float4  pos : POSITION; // 输入的模型空间中,顶点坐标信息
                float4  uv : TEXCOORD0; // 材质信息也包含了xyzw,通常只用xy,但是这里由顶点生成
            };
   v2f vert (appdata_base v)
            {
                v2f o;
               // 从模型坐标-世界坐标-视坐标-(视觉平截体乘以投影矩阵并进行透视除法)-剪裁坐标
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
               // 【自动生成纹理】通过输出的pos计算的纹理信息
               // 【解决平台差异】D3D原点在顶部(本机需要让y缩放乘以-1),openGL在底部
                #if UNITY_UV_STARTS_AT_TOP
                float scale = -1.0;
                #else
                float scale = 1.0;
                #endif
               // pos的范围是【-1,1】+1为【0,2】,乘以0.5变成uv的范围【0,1】
               // 不清楚为什么这样写,但是标准的写法就是这样
               o.uv.xy = (float2(o.pos.x, o.pos.y*scale) + o.pos.w) * 0.5;
               o.uv.zw = o.pos.zw;  
                return o;
            }
   float4 frag (v2f i) : COLOR
     {
          // 对_GrabTexture纹理进行取样,进行2D纹理映射查找,后面传入的一定要四元纹理坐标。
         // UNITY_PROJ_COORD传入四元纹理坐标用于给tex2Dproj读取,但是多数平台上,返回一样的值。
         // 【自动生成的纹理UV】类型是float4,使用如下方式进行2D纹理映射查找
        //half4 texCol = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uv));
         // 也可以使用tex2D进行采样,但是【自动生成的纹理UV】时必须要除以w转为齐次坐标
        float last_x = i.uv.x / i.uv.w;
        float last_y = i.uv.y / i.uv.w; 
        half4 texCol = tex2D(_GrabTexture, float2(last_x, last_y));
       // 颜色反相,便于观察效果
                return 1 - texCol;
         }
   ENDCG
  }
 }
 FallBack "Diffuse"
}

注:
2中的确是将屏幕的纹理赋值到样本对象GrabTexture上,所以前面的模型显示整个屏幕的纹理是正常现象。
3中是计算该模型顶点在屏幕坐标的纹理信息,unity封装的UnityCG.cginc代码中有:

inline float4 ComputeGrabScreenPos (float4 pos) {
      #if UNITY_UV_STARTS_AT_TOP
      float scale = -1.0;
      #else
      float scale = 1.0;
      #endif
      float4 o = pos * 0.5f;
      o.xy = float2(o.x, o.y*scale) + o.w;
      o.zw = pos.zw;
      return o;
    }

    与3中给o.uv赋值的代码是一样的。所以在顶点程序中可以这样写:
    v2f vert (appdata_base v)
    {
     v2f o;
     // 从模型坐标-世界坐标-视坐标-(视觉平截体乘以投影矩阵并进行透视除法)-剪裁坐标
     o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
     //o.uv = TRANSFORM_TEX(v.texcoord, _GrabTexture);// UV纹理坐标集信息来自屏幕样本对象
     float4 screenUV = ComputeGrabScreenPos(o.pos);//计算该模型顶点在屏幕坐标的纹理信息
     o.uv = screenUV.xy/screenUV.w;
     return o;
    }

以后我们就可以不用再写这段代码了,直接用unity提供的函数ComputeGrabScreenPos,方便!   
获取屏幕的纹理,还可以通过摄像机,将渲染的内容写到RenderTexture中,这样就可以不使用grabpass,
一样达到获取屏幕纹理的目标,grabpass比较耗(官方说的,不过我在pc上创建了5000个对象进行测试,没发现太大差异,手机上没测过),
在手机上比较适合这种方式。实现代码如下:
public class ScreenTexture : MonoBehaviour
{
    public Camera m_camera;          // 和主摄像机参数一样的拍照摄像机
    private RenderTexture m_tex;    // 摄像机渲染的材质
    public Material mat;            // 要控制的材质
    void Start()
    {
        m_tex = new RenderTexture(Screen.width, Screen.height, 16);
        m_camera.targetTexture = m_tex;
    }
    void OnPreCull()
    {
        mat.SetTexture("_MainTex", m_tex);   // 给shader的主材质赋值,为屏幕纹理
    }
    void OnPostRender()
    {
        mat.SetTexture("_MainTex", null);
    }
}



<think>嗯,用户想寻找推荐的shader效果,尤其是在图形编程或游戏开发中的应用参考。从引用资料来看,用户应该是有一定shader开发基础,正在寻找进阶的实用效果参考。引用提到Nvidia的ShaderLibrary(引用2)、ShaderX书籍,以及ShaderReference项目(引用3、4),这些都是专业开发者常用的资源。用户提到“推荐效果”,但没限定具体领域。根据引用3和4提到的应用场景,我可以从游戏开发中几个核心视觉效果切入:光照材质类(如PBR)、环境交互类(水面/天气)、风格化渲染(卡通/像素风)、后处理特效(景深/运动模糊)这四个方向推荐,基本覆盖主流需求。每个方向需要说明技术原理和实现资源。注意到引用1和2特别强调实战性,用户可能更关注可直接落地的案例。Nvidia的ShaderLibrary有现成代码(引用2),ShaderReference有跨平台实例(引用4),应该作为重点推荐。对于学术性资源,只提《Real-TimeRendering》这种经典即可,避免信息过载。用户身份可能是游戏程序员或技术美术。考虑到国内开发者习惯(引用1提到早年资料匮乏),推荐资源时要兼顾中文友好性:ShaderReference有中文社区支持(引用4的GitHub讨论),《UnityShader入门精要》是国内作者,比纯英文资源更易上手。上次对话中用户要求过“保证回答可靠”,推荐效果时需要标注哪些是行业验证的主流方案(如PBR引用3提到水面反射)、哪些是前沿技术(如PathTracing)。避免推荐实验性过强或性能代价高的效果。</think> 根据游戏开发与图形编程的实际需求,以下推荐6类实用且视觉效果出众的Shader效果及其实现资源,涵盖从基础到进阶的全方位应用: --- ### 一、**物理光照模型(PBR)** **应用场景**:写实风格游戏的角色/场景材质 **核心效果**: - 金属度/粗糙度参数控制材质反光特性 - 环境光遮蔽(AO)增强立体感 - HDR环境贴图反射 **学习资源**: - Nvidia Shader Library的`GGX Specular`模型 [[引用2]](http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html) - 《Unity Shader入门精要》第12章PBR实现 --- ### 二、**动态环境交互效果** 1. **水体着色器** - 实时折射/反射(使用GrabPass) - 法线贴图模拟波浪 - 焦散(Caustics)光斑 > *示例代码:UV扰动实现波纹* ```glsl float wave = sin(_Time.y * speed + uv.x * frequency) * amplitude; uv.xy += wave * normalDir.xy; ``` 2. **天气系统Shader** - 雨滴屏幕特效(屏幕空间UV动画) - 雪地动态积累(高度图混合) - 体积云雾(Ray Marching算法) --- ### 三、**风格化渲染(非真实感)** | 效果类型 | 技术要点 | 应用案例 | |----------------|---------------------------|------------------| | 卡通渲染 | 阶跃函数硬阴影 | 《原神》角色 | | 像素风 | 色彩量化+抖动(Dithering) | 独立游戏 | | 水墨风格 | 边缘检测+宣纸纹理混合 | 国风美术项目 | **开源资源**: - GitHub项目`Unity-URP-CelShading`(17k+ stars) - ShaderReference中的`Ink Wash Rendering`教程 [[引用3]] --- ### 四、**高级后处理特效** 1. **次世代画面增强** - 屏幕空间反射(SSR) - 胶片颗粒(Film Grain)+ 色差(Chromatic Aberration) - 动态景深(Depth of Field) 2. **性能优化方案** - 分块渲染(Tile-Based Rendering) - 动态分辨率(Dynamic Resolution) --- ### 、**几何着色器创新应用** 1. **植被动态** - GPU实例化(Instancing)绘制草地 - 顶点着色器模拟树木摇摆 2. **破碎效果** - 几何着色器生成碎片网格 - SDF(有向距离场)控制裂痕形状 --- ### 六、**前沿技术探索** - **实时光追(Ray Tracing)**: Unreal Engine的`Lumen`全局光照方案 - **神经网络着色器**: 使用AI生成材质(如NVIDIA RTX Remix) --- ### 📚 终极学习路径 1. **基础巩固**: 《ShaderX》系列书籍中的像素着色技巧 [[引用2]] 2. **实战进阶**: - ShaderReference的社区案例库(GitHub持续更新)[[引用3][引用4]] - Unity Asset Store的`Keijiro Takahashi`开源项目 3. **前沿跟进**: SIGGRAPH历年Real-Time Live! 技术分享 > 提示:调试工具推荐`RenderDoc`分析绘制流程,配合NVIDIA Nsight图形调试器可深度优化性能瓶颈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值