接上文:UnityShader20:CommandBuffer初见(上)

四、复杂一点的例子……

CommandBuffer代码参考如下:

using UnityEngine;
using UnityEngine.Rendering;
using System.Collections.Generic;[ExecuteInEditMode]
//加上ExecuteInEditMode后,下面的代码在编辑模式中就会运行,无需每次测试都要play了
public class CommandBufferBlurRefraction: MonoBehaviour
{public Shader m_BlurShader;private Material m_Material;private Camera m_Cam;private Dictionary<Camera,CommandBuffer> m_Cameras = new Dictionary<Camera, CommandBuffer>();private void Cleanup(){foreach(var cam in m_Cameras){if (cam.Key){cam.Key.RemoveCommandBuffer(CameraEvent.AfterSkybox, cam.Value);}}m_Cameras.Clear();Object.DestroyImmediate(m_Material);}public void OnEnable(){Cleanup();}public void OnDisable(){Cleanup();}public void OnWillRenderObject(){var act = gameObject.activeInHierarchy && enabled;if (!act){Cleanup();return;}var cam = Camera.current;if (!cam)return;CommandBuffer buf = null;if (m_Cameras.ContainsKey(cam))return;if (!m_Material){m_Material = new Material(m_BlurShader);m_Material.hideFlags = HideFlags.HideAndDontSave;}//创建一个CommandBufferbuf = new CommandBuffer();buf.name = "Grab screen and blur";m_Cameras[cam] = buf;//新建一张纹理,得到对应的纹理IDint screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");//初始化这张纹理,其中纹理的大小为摄像机视野大小buf.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear);//将当前的渲染目标纹理拷贝到你的纹理"_ScreenCopyTexture"上buf.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);//再新建两张纹理int blurredID = Shader.PropertyToID("_Temp1");int blurredID2 = Shader.PropertyToID("_Temp2");//初始化这两张纹理,其中纹理的大小为摄像机视野大小的一半buf.GetTemporaryRT(blurredID, -2, -2, 0, FilterMode.Bilinear);buf.GetTemporaryRT(blurredID2, -2, -2, 0, FilterMode.Bilinear);//开始表演buf.Blit(screenCopyID, blurredID);buf.ReleaseTemporaryRT(screenCopyID); //进行多次的高斯模糊,一次横向,一次纵向,纹理相互拷贝buf.SetGlobalVector("offsets", new Vector4(2.0f/Screen.width, 0, 0, 0));buf.Blit(blurredID, blurredID2, m_Material);buf.SetGlobalVector("offsets", new Vector4(0, 2.0f/Screen.height, 0, 0));buf.Blit(blurredID2, blurredID, m_Material);buf.SetGlobalVector("offsets", new Vector4(4.0f/Screen.width, 0, 0, 0));buf.Blit(blurredID, blurredID2, m_Material);buf.SetGlobalVector("offsets", new Vector4(0, 4.0f/Screen.height, 0, 0));buf.Blit(blurredID2, blurredID, m_Material);//到这里,纹理blurredID已经就是最终我们要的:进行过高斯模糊的结果,将它赋到对应着色器中的 _RefractionTex 属性上buf.SetGlobalTexture("_RefractionTex", blurredID);cam.AddCommandBuffer(CameraEvent.AfterSkybox, buf);}//是的,这整个过程就是为了得到一张你想要的纹理,并传递给Shader
}
  1. CommandBuffer.GetTemporaryRT:获取一张临时的 RenderTexture,第1个参数为纹理主键,由 Shader.PropertyToID 创建;第2, 3个参数为纹理长宽,传负数  表示取相机像素的  ;第4个参数为深度缓冲位宽(0, 16, 24);第5个参数位纹理过滤模式。这个纹理可以由 ReleaseTemporaryRT 释放,也会由 Unity 在摄像机完成渲染后自动释放
  2. CommandBuffer.ReleaseTemporaryRT:释放指定的的临时渲染纹理

  3. Shader.PropertyToID:获得着色器属性名对应的唯一ID,这个属性名随意
  4. BuiltinRenderTextureType.CurrentActive:获取当前激活的渲染目标
  5. CommandBuffer.Blit:将一个纹理复制到另一个纹理,可使用自定义着色器,第1个参数为源纹理 src;第2个参数为目标纹理 target;第三个参数为材质 mat,其内部使用 mat 材质用 src 做 mainTex,clear 为 black 后渲染到 target 上,mat 留空可以理解为直接拷贝纹理。执行这个操作后,target 将会成为新的渲染目标
  6. CommandBuffer.SetGlobalVector:全局设置着色器向量属性
  7. CommandBuffer.SetGlobalTexture:全局设置着色器纹理属性

五、更好的玻璃效果(官网案例)

1):着色器代码部分:这个着色器实现了最简单的高斯模糊

  • 关于高斯模糊:OpenGL基础51:泛光(文章中的第三节)
Shader "Jaihk662/GaussBlurred1"
{Properties{_MainTex ("Base(RGB)", 2D) = "" {}}CGINCLUDE#include "UnityCG.cginc"float4 offsets;sampler2D _MainTex;/*可以直接用appdata_img代替struct _2vert{float4 vertex: POSITION;half2 texcoord: TEXCOORD0;};*/struct vert2frag {float4 pos: SV_POSITION;float2 uv: TEXCOORD0;float4 uv01: TEXCOORD1;float4 uv23: TEXCOORD2;float4 uv45: TEXCOORD3;};vert2frag vert(appdata_img v){vert2frag o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = v.texcoord.xy;//采样范围为7x7(周围3圈),offests的值在.cs中设置o.uv01 =  v.texcoord.xyxy + offsets.xyxy * float4(1, 1, -1, -1);o.uv23 =  v.texcoord.xyxy + offsets.xyxy * float4(1, 1, -1, -1) * 2.0;o.uv45 =  v.texcoord.xyxy + offsets.xyxy * float4(1, 1, -1, -1) * 3.0;return o;}half4 frag(vert2frag i): SV_Target{//高斯模糊half4 color = float4 (0, 0, 0, 0);color += 0.40 * tex2D (_MainTex, i.uv);color += 0.15 * tex2D (_MainTex, i.uv01.xy);color += 0.15 * tex2D (_MainTex, i.uv01.zw);color += 0.10 * tex2D (_MainTex, i.uv23.xy);color += 0.10 * tex2D (_MainTex, i.uv23.zw);color += 0.05 * tex2D (_MainTex, i.uv45.xy);color += 0.05 * tex2D (_MainTex, i.uv45.zw);return color;}ENDCGSubshader{Pass{ZTest Always Cull Off ZWrite OffFog { Mode off }        //设置雾模式:关闭CGPROGRAM//使用低精度(FP16)以提升fragment着色器的运行速度,减少时间#pragma fragmentoption ARB_precision_hint_fastest#pragma vertex vert#pragma fragment fragENDCG}}
}

CGINCLUDE 关键字:和之前常用的 CGPROGRAM 不同,在 CGINCLUDE 和 ENDCG 范围内插入的 shader 代码会被插入到所有 Pass 中

  • #pragma fragmentoption ARB_precision_hint_fastest:使用低精度(FP16)以提升fragment着色器的运行速度,减少时间
  • #pragma fragmentoption ARB_precision_hint_nicest:使用高精度(FP32)

代码中还设置了 Fog { Mode off }:这是为了关闭雾效,暂时可以不去了解

2):然后对于玻璃本身材质的着色器如下:

Shader "Jaihk662/Glass2"
{Properties{_MainTex ("Main Tex", 2D) = "white" {}                          //玻璃材质纹理_NormalMap ("Normal Map", 2D) = "white" {}                      //玻璃法线_Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}           //模拟环境映射_Distortion ("Distortion", Range(0, 100)) = 10                  //模拟折射时,图像扭曲程度_RefractAmount ("Refract Amount", Range(0.0, 1.0)) = 1.0        //折射程度,为0只反射,为1只折射}SubShader{Tags { "Queue" = "Transparent" "RenderType" = "Opaque" }//Queue设置为Transparent可以保证该物体渲染时,所有的不透明物体都已经被渲染到屏幕上了LOD 200PASS {CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"sampler2D _MainTex;sampler2D _NormalMap;samplerCUBE _Cubemap;float _Distortion;fixed _RefractAmount;sampler2D _RefractionTex;           //来自CommandBufferfloat4 _RefractionTex_TexelSize;    //对应纹理每一像素的大小float4 _NormalMap_ST;float4 _MainTex_ST;struct _2vert{float4 vertex: POSITION;float3 normal: NORMAL;float4 tangent: TANGENT; float2 texcoord: TEXCOORD0;};struct vert2frag {float4 pos: SV_POSITION;float4 scrPos: TEXCOORD0;float4 uv: TEXCOORD1;float4 TtoW1: TEXCOORD2;  float4 TtoW2: TEXCOORD3;  float4 TtoW3: TEXCOORD4; };vert2frag vert(_2vert v) {vert2frag o;o.pos = UnityObjectToClipPos(v.vertex);o.scrPos = ComputeGrabScreenPos(o.pos);         //获得屏幕图像的采样坐标,考虑过平台差异,输入裁剪空间坐标,输出齐次坐标系下的屏幕坐标值(就是屏幕坐标乘上w,只计算xy,zw不变)o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);o.uv.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);float3 wPos = mul(unity_ObjectToWorld, v.vertex).xyz;float3 wNormal = UnityObjectToWorldNormal(v.normal);float3 wTangent = UnityObjectToWorldDir(v.tangent);float3 wBinormal = cross(wNormal, wTangent) * v.tangent.w;o.TtoW1 = float4(wTangent.x, wBinormal.x, wNormal.x, wPos.x);o.TtoW2 = float4(wTangent.y, wBinormal.y, wNormal.y, wPos.y);o.TtoW3 = float4(wTangent.z, wBinormal.z, wNormal.z, wPos.z);return o;}fixed4 frag(vert2frag i): SV_Target{float3 wPos = float3(i.TtoW1.w, i.TtoW2.w, i.TtoW3.w);fixed3 wViewDir = normalize(UnityWorldSpaceViewDir(wPos));fixed3 normal = UnpackNormal(tex2D(_NormalMap, i.uv.zw));  //计算折射,考虑玻璃材质float2 offest = normal.xy * _Distortion * _RefractionTex_TexelSize.xy;i.scrPos.xy = i.scrPos.xy + offest * i.scrPos.z;fixed3 refractCol = tex2D(_RefractionTex, i.scrPos.xy / i.scrPos.w).rgb;      //根据偏移后的坐标进行采样,得到折射颜色//不再计算反射//normal = normalize(half3(dot(i.TtoW1.xyz, normal), dot(i.TtoW2.xyz, normal), dot(i.TtoW3.xyz, normal)));fixed4 texColor = tex2D(_MainTex, i.uv.xy);//fixed3 reflectionDir = reflect(-wViewDir, normal);//fixed3 reflectionCol = texCUBE(_Cubemap, reflectionDir).rgb * texColor.rgb;fixed3 finalColor = texColor * (1 - _RefractAmount) + refractCol * _RefractAmount;return fixed4(finalColor, 1);} ENDCG}}FallBack "Diffuse"
}

这个代码就是《UnityShader19.1:渲染纹理(下)之 GrabPass》中代码的改版,原先 GrabPass 的纹理现在由 CommandBuffer 提供,并且不再计算反射

3):最后 CommandBuffer 部分代码就是上一章中的代码

效果如下:

参考资料:

  • https://blog.csdn.net/biezhihua/article/details/79141924

UnityShader20.1:CommandBuffer初见(下)相关推荐

  1. UnityShader20:CommandBuffer初见(上)

    一.命令缓冲区 CommandBuffer 根据渲染模式的不同,Unity的渲染流水线如下: 其中蓝色的部分就是 CommandBuffer 可插入的部分,CommandBuffer 本质上就是做一个 ...

  2. UnityShader24:最简单的屏幕后处理例子

    一.需要提前了解的 其实关于屏幕后处理(Screen Post-processing Effects)相关的知识,前面已经提过了不少: 这些是 OpenGL 渲染部分: OpenGL基础35:帧缓冲( ...

  3. UnityShader25:在Unity中实现泛光

    一.需要提前了解的 这一章的例子非常的综合,可以说是知识点广而全,如果能独立在 Unity 中实现一个不错的泛光效果,那么 UnityShader 就算作入门成功!本章没有新的东西 曾经在 OpenG ...

  4. 以Blog.Core的方式来打开Abp.vNext

    (发现Abp这个logo真像佐助写轮眼) 最近自己的框架已经基本的成型了,当然还有很多质疑的地方,比如这些人是这么说的,基本都是原文: 你的教程太乱了,和框架代码都不一样(???) 文章还行,代码规范 ...

  5. 数据库(DataBase)

    MySQL 简介 数据库 数据库:DataBase,简称 DB,存储和管理数据的仓库 数据库的优势: 可以持久化存储数据 方便存储和管理数据 使用了统一的方式操作数据库 SQL 数据库.数据表.数据的 ...

  6. 寂寥的雨花,打在你的遮阳伞上,回忆,是那样刻骨铭心,若如初见。你,与我相爱了半生,却让我下半生寂寞地守候你,你的离开,是为了自己翱翔天空的梦想,是为了在天空,也能种下我们相思相爱的杜鹃雨。 而我,只

    寂寥的雨花,打在你的遮阳伞上,回忆,是那样刻骨铭心,若如初见.你,与我相爱了半生,却让我下半生寂寞地守候你,你的离开,是为了自己翱翔天空的梦想,是为了在天空,也能种下我们相思相爱的杜鹃雨. 而我,只能 ...

  7. 要点初见:双硬盘下的Win10+Ubuntu16.04双系统安装

    按照网上博客的安装教程安装的Win10+Ubuntu16.04双系统安装了好几遍都不成功?启动Ubuntu左上一直有个光标在闪?如果你的电脑也是双硬盘(装Windows系统的固态硬盘+机械硬盘),在安 ...

  8. Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析(完)...

    原文 http://www.cnblogs.com/mayswind/archive/2013/04/01/2991271.html [题外话] 这是这个系列的最后一篇文章了,为了不让自己觉得少点什么 ...

  9. elasticsearch-5.0.0初见

    elasticsearch-5.0.0初见 基础概念 Elasticsearch有几个核心概念.从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT) Elasticsearch是一个 ...

最新文章

  1. ERROR: Unable to load class 'org.gradle.api.internal.component.Usage'.
  2. canvas动画特效 之 星空
  3. 有时间看下这个,分布式缓存,提高并发的
  4. 【18】让接口容易被正确使用,不易被误用
  5. Web Worker的最好文章
  6. 恕我直言,有了这款 IDEA 插件,你可能只需要写 30% 的代码。。。
  7. 第十节(this关键字 static关键字)
  8. sql select 抛异常_mysql数据库及sql注入
  9. windows php fastcgi,windows下FastCGI(php-cgi)的工作原理和配置
  10. 60. MySQLi 扩展拾遗
  11. 网页素材精品:一组五彩缤纷的免费矢量背景素材
  12. JS中的冒泡排序代码实现(超详细)
  13. 计算机solidwork实训报告,solid works学习心得范文
  14. 三星电视机dns服务器维护,4招解救三星智能电视看视频卡顿问题
  15. wan端口未连接怎么弄_路由器WAN口未连接解决方法,WAN口未连接怎么办
  16. 2022年G2电站锅炉司炉操作证考试题库及答案
  17. strace praticle
  18. 我的雷电游戏(重力感应控制)
  19. 使用WireShark你需要知道的技巧(新手向)
  20. java 农历_JAVA工具例大全--阴历(农历)信息 源代码

热门文章

  1. 从零开始学习python编程-从零开始学Python程序设计 PDF 完整影印版
  2. 学python需要什么软件-学python需要什么软件
  3. python软件下载对电脑配置要求-python3批量统计用户电脑配置
  4. 科大讯飞免切换语音输入,留住更美乡音!
  5. linux下mysql连接_Linux下MySQL C++连接操作
  6. 【深度优先搜索/树】计蒜客:族谱
  7. JAVA编写的一个简单的Socket实现的HTTP响应服务器
  8. jQuery 学习-DOM篇(六):jQuery 替换 DOM 元素
  9. Linux下rpm安装软件
  10. windows上telnet用法 测试端口号