Unity Shader-Command Buffer的使用(景深与描边效果重置版)
Unity Shader-Command Buffer的使用(景深与描边效果重置版)
https://blog.csdn.net/puppet_master/article/details/72669977
Unity Shader-后处理:时空扭曲效果
https://blog.csdn.net/puppet_master/article/details/71437031
UnityShader实例15:屏幕特效之Bloom
https://blog.csdn.net/u011047171/article/details/48522073
Unity3D Shdaer 实现镜头模糊效果[Shader]
https://blog.csdn.net/qq_28221881/article/details/54618798
unity3d 带缓冲的镜头拉近效果
https://blog.csdn.net/fzhlee/article/details/8667251
版权声明:欢迎转载,共同进步。请注明出处:http://blog.csdn.net/puppet_master https://blog.csdn.net/puppet_master/article/details/72669977
简介
Command Buffer是Unity5新增的一个灰常灰常强大的功能。先祭出官方介绍和文档。我们在渲染的时候,给OpenGL或者DX的就是一系列的指令,比如glDrawElement,glClear等等,这些东西目前是引擎去调用的,而Unity也为我们封装了更高一级的API,也就是CommandBuffer,可以让我们更加方便灵活地实现一些效果。CommandBuffer最主要的功能是可以预定义一些列的渲染指令,然后将这些指令在我们想要的时机进行执行。本篇文章简单介绍一下CommandBuffer的使用,首先实现一个简单的摄像机效果,然后通过Command Buffer重置一下之前实现过的两个效果:景深和描边效果。
CommandBuffer的基本用法
我们先来看一个最简单的例子,直接在一张RT上画个人,其实类似于摄影机效果,我们用当前的相机看见正常要看见的对象,然后在一张幕布(简单的来说,就是一个。。额,面片)再渲染一次这个人物(也可以直接渲染到UI上)。
-
//Command Buffer测试
-
//by: puppet_master
-
//2017.5.26
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
using UnityEngine.Rendering;
-
public class CommandBufferTest : MonoBehaviour {
-
private CommandBuffer commandBuffer = null;
-
private RenderTexture renderTexture = null;
-
private Renderer targetRenderer = null;
-
public GameObject targetObject = null;
-
public Material replaceMaterial = null;
-
void OnEnable()
-
{
-
targetRenderer = targetObject.GetComponentInChildren<Renderer>();
-
//申请RT
-
renderTexture = RenderTexture.GetTemporary(512, 512, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 4);
-
commandBuffer = new CommandBuffer();
-
//设置Command Buffer渲染目标为申请的RT
-
commandBuffer.SetRenderTarget(renderTexture);
-
//初始颜色设置为灰色
-
commandBuffer.ClearRenderTarget(true, true, Color.gray);
-
//绘制目标对象,如果没有替换材质,就用自己的材质
-
Material mat = replaceMaterial == null ? targetRenderer.sharedMaterial : replaceMaterial;
-
commandBuffer.DrawRenderer(targetRenderer, mat);
-
//然后接受物体的材质使用这张RT作为主纹理
-
this.GetComponent<Renderer>().sharedMaterial.mainTexture = renderTexture;
-
//直接加入相机的CommandBuffer事件队列中
-
Camera.main.AddCommandBuffer(CameraEvent.AfterForwardOpaque, commandBuffer);
-
}
-
void OnDisable()
-
{
-
//移除事件,清理资源
-
Camera.main.RemoveCommandBuffer(CameraEvent.AfterForwardOpaque, commandBuffer);
-
commandBuffer.Clear();
-
renderTexture.Release();
-
}
-
//也可以在OnPreRender中直接通过Graphics执行Command Buffer,不过OnPreRender和OnPostRender只在挂在相机的脚本上才有作用!!!
-
//void OnPreRender()
-
//{
-
// //在正式渲染前执行Command Buffer
-
// Graphics.ExecuteCommandBuffer(commandBuffer);
-
//}
-
}
然后,我们可以把这个脚本挂在一个对象上,将要渲染的目标拖入就可以了。我们测试一下:
Command Buffer在渲染目标的时候,是支持我们使用自定义材质的,我们可以换一个材质,如果我们做了个摄像机,还不带美颜功能的话,肯定是要得差评的,所以,我们给渲染的对象换一个自定义的材质,比如边缘光效果,直接将调整好的边缘光材质球赋给Replace Material即可:
通过Command Buffer对RT进行后处理
如果感觉只是换一个材质球不够过瘾的话,我们就再发掘一下Command Buffer更深层次的功能吧!下面放大招啦!又是后处理,不过我们后处理的对象改了一下,不是基于屏幕,而是基于Command Buffer输出的那张Render Texture。比如我们稍微修改一下上面的代码,增加一个最简单的屏幕较色后处理(其实就是我比较懒罢了>_<)
-
//Command Buffer测试
-
//by: puppet_master
-
//2017.5.26
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
using UnityEngine.Rendering;
-
public class CommandBufferTest : PostEffectBase {
-
private CommandBuffer commandBuffer = null;
-
private RenderTexture renderTexture = null;
-
private Renderer targetRenderer = null;
-
public GameObject targetObject = null;
-
public Material replaceMaterial = null;
-
[Range(0.0f, 3.0f)]
-
public float brightness = 1.0f;//亮度
-
[Range(0.0f, 3.0f)]
-
public float contrast = 1.0f; //对比度
-
[Range(0.0f, 3.0f)]
-
public float saturation = 1.0f;//饱和度
-
void OnEnable()
-
{
-
targetRenderer = targetObject.GetComponentInChildren<Renderer>();
-
//申请RT
-
renderTexture = RenderTexture.GetTemporary(512, 512, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 4);
-
commandBuffer = new CommandBuffer();
-
//设置Command Buffer渲染目标为申请的RT
-
commandBuffer.SetRenderTarget(renderTexture);
-
//初始颜色设置为灰色
-
commandBuffer.ClearRenderTarget(true, true, Color.gray);
-
//绘制目标对象,如果没有替换材质,就用自己的材质
-
Material mat = replaceMaterial == null ? targetRenderer.sharedMaterial : replaceMaterial;
-
commandBuffer.DrawRenderer(targetRenderer, mat);
-
//然后接受物体的材质使用这张RT作为主纹理
-
this.GetComponent<Renderer>().sharedMaterial.mainTexture = renderTexture;
-
if (_Material)
-
{
-
//这是个比较危险的写法,一张RT即作为输入又作为输出,在某些显卡上可能不支持,如果不像我这么懒的话...还是额外申请一张RT
-
commandBuffer.Blit(renderTexture, renderTexture, _Material);
-
}
-
//直接加入相机的CommandBuffer事件队列中
-
Camera.main.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);
-
}
-
void OnDisable()
-
{
-
//移除事件,清理资源
-
Camera.main.RemoveCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);
-
commandBuffer.Clear();
-
renderTexture.Release();
-
}
-
//为方便调整,放在update里面了
-
void Update()
-
{
-
_Material.SetFloat("_Brightness", brightness);
-
_Material.SetFloat("_Saturation", saturation);
-
_Material.SetFloat("_Contrast", contrast);
-
}
-
}
好了,我们美颜相机第二版本就完成了,增加了后处理之后的效果,调整了一下饱和度,亮度,对比度之后的效果如下:
动态效果:
通过上面的几个例子,我们大概了解了Command Buffer能干的事情。首先,Command Buffer可以让我们定义一连串的渲染指令,我们可以直接在需要的时候通过Graphics.ExecuteCommandBuffer执行也可以通过Camera.AddCommandBuffer函数根据不同的CameraEvent来控制CommandBuffer执行的时间。其次,Command Buffer的效果大致等同于新建一个和主相机参数大致相同的摄像机,并且可以附加一些额外的渲染效果支持,比如替换材质渲染,对渲染的RT进行后处理等等。
不过这里我也遇到了一个问题,当使用Command Buffer渲染时,对象的shader使用diffuse等自定义shader的话,Command Buffer渲染出来的结果有时会不对,通过Frame Debuger看的时候发现Command Buffer渲染的流程是Deffer Path的,而不是我们正常的Forward Path,而工程设置以及相机设置都为Forward Path。将shader换为自己写的就木有这个问题。不知道是我哪里姿势不对还是Unity的bug。。。
“假”景深效果
所谓假景深,叫做背景虚化更加贴切一些。其实所有的渲染效果都是假的,都是是忽悠我们的眼睛,就比谁忽悠得又好又省。正常的景深效果,一般是基于深度计算,根据焦距将模糊图与原图插值控制焦点距离清晰,原理焦点距离模糊。but,这个效果虽然很好,但是需要深度信息,如果是deffer或者开了实时阴影,深度自然就有了,也就无所谓了,但是一般手游的基本这两种都是开不得的,那么开了深度,就会DC翻倍,再加上模糊至少十次全屏采样(降采样也许会好些)。个人感觉景深应该最昂贵的后处理效果之一了。而背景虚化的效果,简单来说就是只让人物(或者我们需要突出的部分)清晰,其他所有部分全都模糊。这种效果不需要深度图,可以在DC上省下很多消耗,而且有时候这种效果会比真正的景深更好,但还是需要看需求。我们如果实现这种效果,最简单的并且容易想到的就是新建一个相机,然后将需要突出的部分放在另一个相机渲染,在场景相机上增加一个模糊的后处理,这样,突出部分渲染后的相机叠加到场景相机的结果上,就可以只让场景模糊而人物不模糊了。不过在有了Command Buffer之后,就不需要这么麻烦了,我们可以直接通过Command Buffer控制模型的渲染时机,首先将正常的Renderer组件disable,然后强行通过Command Buffer让其在后处理之后渲染:
-
//在后处理之后渲染
-
//by: puppet_master
-
//2017.6.5
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
using UnityEngine.Rendering;
-
[ExecuteInEditMode]
-
public class RenderAfterPostEffect : MonoBehaviour
-
{
-
private CommandBuffer commandBuffer = null;
-
private Renderer targetRenderer = null;
-
void OnEnable()
-
{
-
targetRenderer = this.GetComponentInChildren<Renderer>();
-
if (targetRenderer)
-
{
-
commandBuffer = new CommandBuffer();
-
commandBuffer.DrawRenderer(targetRenderer, targetRenderer.sharedMaterial);
-
//直接加入相机的CommandBuffer事件队列中,
-
Camera.main.AddCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer);
-
targetRenderer.enabled = false;
-
}
-
}
-
void OnDisable()
-
{
-
if (targetRenderer)
-
{
-
//移除事件,清理资源
-
Camera.main.RemoveCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer);
-
commandBuffer.Clear();
-
targetRenderer.enabled = true;
-
}
-
}
-
}
上面的脚本只是控制修改模型渲染时机的,然后,我们可以在主相机上挂一个高斯模糊的后处理,调整参数后就可以得到背景虚化的效果了:
当然,不仅仅是模糊效果,挂了该脚本的对象会被所有后处理所“抛弃”,我们也可以放一些其他的后处理效果,比如漩涡扭曲:
Command Buffer的这个功能是个人感觉最有用的一个功能,可以进一步地控制某个对象的渲染序列,让我们更加方便地实现一些效果。
描边效果Command Buffer实现
描边效果(后处理版本)首先将要描边的对象用描边色渲染到一张RT上,然后将RT进行模糊操作,使对象外扩,再用外扩的RT减去原始RT就得到了轮廓部分,最后再将轮廓部分与原图混合就得到了最终的描边效果。描边效果将对象渲染到RT上之前通过额外创建一个摄像机实现的,有了Command Buffer,我们就可以直接在原始相机上进行这个操作,大大简化了程序的复杂度。关于描边效果的具体原理,可以参考本人之前的文章,这里就不多说了,直接上代码。补充说明:PostEffectBase类是所有本人之前做的后处理效果的基类。
C#脚本部分:
-
/********************************************************************
-
FileName: OutlinePostEffectCmdBuffer.cs
-
Description: 后处理描边效果CommandBuffer版本
-
Created: 2017/06/07
-
by puppet_master
-
*********************************************************************/
-
using UnityEngine;
-
using System.Collections;
-
using UnityEngine.Rendering;
-
public class OutlinePostEffectCmdBuffer : PostEffectBase
-
{
-
private RenderTexture renderTexture = null;
-
private CommandBuffer commandBuffer = null;
-
private Material outlineMaterial = null;
-
//描边prepass shader(渲染纯色贴图的shader)
-
public Shader outlineShader = null;
-
//采样率
-
public float samplerScale = 1;
-
//降采样
-
public int downSample = 1;
-
//迭代次数
-
public int iteration = 2;
-
//描边颜色
-
public Color outLineColor = Color.green;
-
//描边强度
-
[Range(0.0f, 10.0f)]
-
public float outLineStrength = 3.0f;
-
//目标对象
-
public GameObject targetObject = null;
-
void OnEnable()
-
{
-
if (outlineShader == null)
-
return;
-
if (outlineMaterial == null)
-
outlineMaterial = new Material(outlineShader);
-
Renderer[] renderers = targetObject.GetComponentsInChildren<Renderer>();
-
if (renderTexture == null)
-
renderTexture = RenderTexture.GetTemporary(Screen.width >> downSample, Screen.height >> downSample, 0);
-
//创建描边prepass的command buffer
-
commandBuffer = new CommandBuffer();
-
commandBuffer.SetRenderTarget(renderTexture);
-
commandBuffer.ClearRenderTarget(true, true, Color.black);
-
foreach (Renderer r in renderers)
-
commandBuffer.DrawRenderer(r, outlineMaterial);
-
}
-
void OnDisable()
-
{
-
if (renderTexture)
-
{
-
RenderTexture.ReleaseTemporary(renderTexture);
-
renderTexture = null;
-
}
-
if (outlineMaterial)
-
{
-
DestroyImmediate(outlineMaterial);
-
outlineMaterial = null;
-
}
-
if (commandBuffer != null)
-
{
-
commandBuffer.Release();
-
commandBuffer = null;
-
}
-
}
-
void OnRenderImage(RenderTexture source, RenderTexture destination)
-
{
-
if (_Material && renderTexture && outlineMaterial && commandBuffer != null)
-
{
-
//通过Command Buffer可以设置自定义材质的颜色
-
outlineMaterial.SetColor("_OutlineCol", outLineColor);
-
//直接通过Graphic执行Command Buffer
-
Graphics.ExecuteCommandBuffer(commandBuffer);
-
//对RT进行Blur处理
-
RenderTexture temp1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);
-
RenderTexture temp2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);
-
//高斯模糊,两次模糊,横向纵向,使用pass0进行高斯模糊
-
_Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));
-
Graphics.Blit(renderTexture, temp1, _Material, 0);
-
_Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));
-
Graphics.Blit(temp1, temp2, _Material, 0);
-
//如果有叠加再进行迭代模糊处理
-
for(int i = 0; i < iteration; i++)
-
{
-
_Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));
-
Graphics.Blit(temp2, temp1, _Material, 0);
-
_Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));
-
Graphics.Blit(temp1, temp2, _Material, 0);
-
}
-
//用模糊图和原始图计算出轮廓图
-
_Material.SetTexture("_BlurTex", temp2);
-
Graphics.Blit(renderTexture, temp1, _Material, 1);
-
//轮廓图和场景图叠加
-
_Material.SetTexture("_BlurTex", temp1);
-
_Material.SetFloat("_OutlineStrength", outLineStrength);
-
Graphics.Blit(source, destination, _Material, 2);
-
RenderTexture.ReleaseTemporary(temp1);
-
RenderTexture.ReleaseTemporary(temp2);
-
}
-
else
-
{
-
Graphics.Blit(source, destination);
-
}
-
}
-
}
描边后处理部分shader:
-
//后处理描边Shader
-
//by:puppet_master
-
//2017.6.7
-
Shader "Custom/OutLinePostEffect" {
-
Properties{
-
_MainTex("Base (RGB)", 2D) = "white" {}
-
_BlurTex("Blur", 2D) = "white"{}
-
}
-
CGINCLUDE
-
#include "UnityCG.cginc"
-
//用于剔除中心留下轮廓
-
struct v2f_cull
-
{
-
float4 pos : SV_POSITION;
-
float2 uv : TEXCOORD0;
-
};
-
//用于模糊
-
struct v2f_blur
-
{
-
float4 pos : SV_POSITION;
-
float2 uv : TEXCOORD0;
-
float4 uv01 : TEXCOORD1;
-
float4 uv23 : TEXCOORD2;
-
float4 uv45 : TEXCOORD3;
-
};
-
//用于最后叠加
-
struct v2f_add
-
{
-
float4 pos : SV_POSITION;
-
float2 uv : TEXCOORD0;
-
float2 uv1 : TEXCOORD1;
-
};
-
sampler2D _MainTex;
-
float4 _MainTex_TexelSize;
-
sampler2D _BlurTex;
-
float4 _BlurTex_TexelSize;
-
float4 _offsets;
-
float _OutlineStrength;
-
//Blur图和原图进行相减获得轮廓
-
v2f_cull vert_cull(appdata_img v)
-
{
-
v2f_cull o;
-
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
-
o.uv = v.texcoord.xy;
-
//dx中纹理从左上角为初始坐标,需要反向
-
#if UNITY_UV_STARTS_AT_TOP
-
if (_MainTex_TexelSize.y < 0)
-
o.uv.y = 1 - o.uv.y;
-
#endif
-
return o;
-
}
-
fixed4 frag_cull(v2f_cull i) : SV_Target
-
{
-
fixed4 colorMain = tex2D(_MainTex, i.uv);
-
fixed4 colorBlur = tex2D(_BlurTex, i.uv);
-
//最后的颜色是_BlurTex - _MainTex,周围0-0=0,黑色;边框部分为描边颜色-0=描边颜色;中间部分为描边颜色-描边颜色=0。最终输出只有边框
-
//return fixed4((colorBlur - colorMain).rgb, 1);
-
return colorBlur - colorMain;
-
}
-
//高斯模糊 vert shader(之前的文章有详细注释,此处也可以用BoxBlur,更省一点)
-
v2f_blur vert_blur(appdata_img v)
-
{
-
v2f_blur o;
-
_offsets *= _MainTex_TexelSize.xyxy;
-
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
-
o.uv = v.texcoord.xy;
-
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;
-
}
-
//高斯模糊 pixel shader
-
fixed4 frag_blur(v2f_blur i) : SV_Target
-
{
-
fixed4 color = fixed4(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;
-
}
-
//最终叠加 vertex shader
-
v2f_add vert_add(appdata_img v)
-
{
-
v2f_add o;
-
//mvp矩阵变换
-
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
-
//uv坐标传递
-
o.uv.xy = v.texcoord.xy;
-
o.uv1.xy = o.uv.xy;
-
#if UNITY_UV_STARTS_AT_TOP
-
if (_MainTex_TexelSize.y < 0)
-
o.uv.y = 1 - o.uv.y;
-
#endif
-
return o;
-
}
-
fixed4 frag_add(v2f_add i) : SV_Target
-
{
-
//取原始场景图片进行采样
-
fixed4 ori = tex2D(_MainTex, i.uv1);
-
//取得到的轮廓图片进行采样
-
fixed4 blur = tex2D(_BlurTex, i.uv);
-
fixed4 final = ori + blur * _OutlineStrength;
-
return final;
-
}
-
ENDCG
-
SubShader
-
{
-
//pass 0: 高斯模糊
-
Pass
-
{
-
ZTest Off
-
Cull Off
-
ZWrite Off
-
Fog{ Mode Off }
-
CGPROGRAM
-
#pragma vertex vert_blur
-
#pragma fragment frag_blur
-
ENDCG
-
}
-
//pass 1: 剔除中心部分
-
Pass
-
{
-
ZTest Off
-
Cull Off
-
ZWrite Off
-
Fog{ Mode Off }
-
CGPROGRAM
-
#pragma vertex vert_cull
-
#pragma fragment frag_cull
-
ENDCG
-
}
-
//pass 2: 最终叠加
-
Pass
-
{
-
ZTest Off
-
Cull Off
-
ZWrite Off
-
Fog{ Mode Off }
-
CGPROGRAM
-
#pragma vertex vert_add
-
#pragma fragment frag_add
-
ENDCG
-
}
-
}
-
}
描边PrePass部分shader:
-
//描边Shader
-
//by:puppet_master
-
//2017.6.7
-
Shader "ApcShader/OutlinePrePass"
-
{
-
//子着色器
-
SubShader
-
{
-
//描边使用两个Pass,第一个pass沿法线挤出一点,只输出描边的颜色
-
Pass
-
{
-
CGPROGRAM
-
#include "UnityCG.cginc"
-
fixed4 _OutlineCol;
-
struct v2f
-
{
-
float4 pos : SV_POSITION;
-
};
-
v2f vert(appdata_full v)
-
{
-
v2f o;
-
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
-
return o;
-
}
-
fixed4 frag(v2f i) : SV_Target
-
{
-
//这个Pass直接输出描边颜色
-
return _OutlineCol;
-
}
-
//使用vert函数和frag函数
-
#pragma vertex vert
-
#pragma fragment frag
-
ENDCG
-
}
-
}
-
}
将描边prepass和后处理shader赋给脚本,并将需要描边的对象赋给targetObject,就可以看到描边效果了:
与之前的描边效果一致,但是代码更简洁。并且描边颜色可以直接在脚本中设置。顺便来一发好玩的效果,调整Sampler Scale以及OutLineStrength:
-
Ron_Tang: 看了你一系列的文章,受益匪浅,谢谢分享,已赞。之前做背景虚化使用额外摄像机来的,使用Command Buffer确实方便很多。 现在Unity2018 发布SRP了。期待你更多的文章,加油~~~~(04-20 16:57#8楼)查看回复(1)
-
ipud2: 感谢你的细心分享,唯一不太明白的是为什么,进行blur时一定要分horizontal与vertical,而不是一次全部处理, 比如最简单的模糊处理: fixed4 blurColor = fixed4(0,0,0,0); //blurColor += tex2D(_MainTex, i.uv); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(-1,1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(0,1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(1,1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(-1,0)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(0,0)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(1,0)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(-1,-1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(0,-1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(1,-1)); blurColor /= 9;(01-10 21:19#7楼)查看回复(3)
-
wzm19941229: 想请教一下对于UI(UGUI)要如何抓取呢?这里抓取依靠Renderer,但是CanvasRenderer和Renderer不同源。。很苦恼。不知道有没有研究过抓取UI?(08-28 16:57#6楼)查看回复(1)