Unity Shader-Command Buffer的使用(景深与描边效果重置版)

Unity中的CommandBuffer 上一篇讲了Unity中的RenderTexture,提到了FrameBuffer,unity中可以通过FrameDebugger来查看FrameBuffer的内容,CommandBuffer通过字面意思 就是一条命令 ,unity提供给开发者的一个自定义的渲染命令,依赖相机,用来拓展渲染管线的渲染效果,我们可以根据参数指定CommandBuffer在绿色的点上添加执行命令: unity中调用... 阅读详情

简介


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:





魔幻连接世界的大师级炼金术:MMORPG游戏网络通信模块高级优化秘籍 MMORPG网络通信模块高级优化是构建流畅大规模游戏体验的核心技术。本文系统剖析了MMORPG网络通信的复杂挑战与解决方案,包括:采用TCP/UDP混合协议实现可靠性与低延迟的平衡;通过客户端预测、帧同步和区域分频优化状态同步;设计多线程异步IO和分布式架构支撑高并发;利用AOI分区和分级广播减少消息风暴;实现智能丢包检测和快速重传机制;加强数据校验和防外挂安全防护。文章通过生动类比和典型案例,揭示了如何让数千玩家在虚拟世界中实现稳定、实时互动的技术奥秘,为游戏开发者提供了一套完整的网络通信优化方法论。 阅读详情

相关推荐

Commandbuffe使用最详细Demo

Commandbuffe使用最详细Demo,一个demo让你学会使用commandbufffer

unity的CommandBuffer介绍

之前介绍过使用PostProcessing来做屏幕后处理效果。这次来介绍一下CommandBuffer

阿赵的博客 3450

onnx入门教程(一):解决模型部署中的难题

直接使用 PyTorch 模型的话,我们修改几行代码就能实现模型输入的动态化。但在模型部署中,我们要花数倍的时间来设法解决这一问题。现在,让我们顺着解决问题的思路,体验一下模型部署的困难,并学习使用自定义算子的方式,解决超分辨率模型的动态化问题。刚刚的报错是因为 PyTorch 模型在导出到 ONNX 模型时,模型的输入参数的类型必须全部是 torch.Tensor。而实际上我们传入的第二个参数" 3 "是一个整形变量。这不符合 PyTorch 转 ONNX 的规定。我们必须要修改一下原来的模型的输入。

图像学习之旅 1127

3.72 Command Buffer及URP概述

3.72 Command Buffer及URP概述

s178435865的专栏 1977

校招总结—FPGA从入门到放弃

校招总结—FPGA从入门到放弃 感谢咸鱼FPGA的授权转发,原文地址为https://www.cnblogs.com/xianyufpga/ 其实 offer 早就定下来了,最近忙着入党考试,现在才腾出时间来写个总结。我校招开始于 7 月底,算是比较晚了,后面加了各大校招交流群,发现很多同学都是过完年后就开始打磨项目、复习基础、寻找实习。对比之下我这准备确实仓促,不过结果还算满意。 ...

qq_31515205的博客 8604

FPGA网络调试实战:基于88E1111和DP83867两款PHY芯片的SGMII-UDP数据回环对比与避坑指南

本文深入对比了88E1111与DP83867两款PHY芯片在SGMII-UDP数据回环中的性能差异,涵盖硬件设计、Vivado工程配置及调试技巧。通过实测数据揭示DP83867在吞吐量、延迟和功耗方面的优势,并提供FPGA网络调试中的常见问题解决方案,助力工程师高效完成项目开发。

weixin_31682031的博客 383

技术美术百人计划 | 《3.72 Command Buffer》笔记

Command Buffer出现的目的是为了扩展Unity的渲染管线(Rendering Pipeline) ,一个Command Buffer 中存储很多绘制命令(Rendering Command),这些 Rendering Command 其实就是OpenGL或者DirectX 中的一些列指令,比如glClear等。Command Buffer 扩展渲染管线的方法是:预定义一系列的渲染指令,然后在特定的时机去执行这些指令。

qq_53352162的博客 1487

无人机通信电台--XBee-PRO 900HP (S3B)

XBee PRO S3B也称为XBee-900HP无线模块,它是一款工作在频段900~928MHz之间,基于FHSS跳频技术的远距离无线数传电台核心模块。常用型号如下: 类别 型号 开发套件 XKB9-DMT-UHP XBee-PRO 900HP (S3B) DigiMesh模块,200Kbps,软天线 XBP9B-DMWT-002 XBee-PRO 900HP (S3B)...

low米的博客 4505

Unity后处理特效库X-PostProcessing-Library:架构解析与性能优化实战

在实时渲染领域,后处理(Post-Processing)是提升视觉表现力的关键技术,它通过在最终渲染图像上应用一系列屏幕空间算法,实现从色彩校正、景深模拟到艺术风格化等丰富效果。其核心原理在于利用渲染管线中的特定注入点,通过着色器(Shader)对全屏纹理进行像素级操作。这项技术的价值在于能以较低成本显著增强画面质感,广泛应用于游戏、影视、虚拟现实等场景,以实现电影级色调、动态模糊、故障艺术等视觉需求。本文聚焦于Unity生态中的开源后处理特效库X-PostProcessing-Library,深入剖析其基

342

GAN网络详解析

介绍目前常见的GAN网络,以及GAN网络的基本组成

wm199的博客 6504

37.华为路由器:loopback(本地回环)接口的作用

本地环回接口(或地址),亦称回送地址(loopback address)。 此类接口是应用最为广泛的一种虚接口,几乎在每台路由器上都会使用。常见于如下用途: 1 作为一台路由器的管理地址 系统管理员完成网络规划之后,为了方便管理,会为每一台路由器创建一个loopback 接口,并在该接口上单独指定一个IP 地址作为管理地址 ,管理员会使用该地址对路由器远程登录(telnet ),该地址实际上起到了类似设备名称一类的功能。 但是通常每台路由器上存在众多接口和地址,为何不从当中随便挑选一个呢 ? 原因如下:由于

迷逝 3万+

Unity 的CommandBuffer基础

CommandBuffer,上 官方文档。 依照官方解释: CommandBuffer携带一系列的渲染命令,依赖相机,用来拓展渲染管线的渲染效果。 而且可以指定在相机渲染的某个点执行本身的拓展渲染。 如下图,我们可以根据参数指定CommandBuffer在绿色的点上添加执行命令。 Command buffers也可以结合屏幕后期效果使用。 那CommandBuffer是个什么鬼,先来实现一个最简...

u012740992的专栏 2万+

MALTAB程序利用质心法去寻峰

质心法的优点是简单易实现且计算速度快,适用于数据点较少或峰值较明显的情况。然而,对于复杂的数据或多峰曲线,质心法可能无法准确识别所有峰值,因此在这些情况下可能需要使用更复杂的峰值检测算法。质心法(Centroid Method)是一种寻找峰值的方法,其基本原理是通过计算数据窗口内的质心位置来确定峰值的位置。质心是指在一维数据中,按照数据的幅值对位置进行加权平均的结果,即质心位置为数据幅值加权平均值的位置。变量定义了计算质心的窗口大小。最后,绘制了找到的峰值位置和幅值点,并显示了找到的峰值位置和幅值的结果。

走向CTO的路上... 1345

Unity 特效扭曲效果(使用command buffer实现)

了解command buffer CommandBuffer携带一系列的渲染命令,可以指定在相机渲染的某个点执行本身命令(包括特殊渲染,保存当前rendertexture等) CommandBuffer可以使用的点看这里(官网文档) 具体渲染流程和触发点如下 特效扭曲的实现原理以及方案 原理:就是抓取特效后面渲染的纹理进行扰动 方案1:抓取特效后面渲染的纹理一般用grabpass,根据grabpass进行扰动 方案2:利用command buffer在渲染天空盒之后保存一张屏幕纹理(.

SnoopyNa2Co3的博客 3573

多后端系统统一聚合与智能分流:用 Multi Origin Composition 与 Routing 打造一套可扩展的 SAP Gateway 架构

本文针对企业级SAP集成场景,详细介绍了如何利用SAP Gateway的MOC(多源组合)和Routing功能实现多后端系统的智能路由与数据聚合。通过系统别名配置、用户角色绑定和主机名分流等机制,可实现按用户、按域名的精确路由。文章还提供了配置清单、性能优化建议和常见问题解决方案,帮助工程师落地多后端OData服务的最佳实践。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 185

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

unity中使用commandbuffer将自定义画面渲染到主相机上

保存渲染命令列表(例如设置渲染目标或绘制给定网格)。您可以指示 Unity 在内置渲染管线中的各个点安排和执行这些命令,因此,您可以自定义和扩展 Unity 的渲染功能。这句话意味着你可以通过command buffer让相机渲染自己想要的画面,而不是像以前一样搞个画布搞张RawImage贴在相机前全屏,然后为了能看到模型再搞个相机去单独渲染模型画面贴在前面。

qq_35064654的博客 2232

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

使用commandbuffer绘制并且blit到屏幕上

master_commandbuffer分支 f3608cd94cc9302a12c272496408a439b6001c3c using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using SRP; public class SRPRenderPipeline : RenderPipeline { private ForwardRen

小孔明的专栏 2495

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

CommandBuffer应用例子——模型局部发光

之前介绍了CommandBuffer的用法。这里来举一个实际应用的例子——模型局部发光

阿赵的博客 787

入门图形学:CommandBuffer

unity提供给我们的commandbuffer可是个好东西,最近我正好用上了,所以来学习理解一下。 unity commandbuffer manual 按惯例先上官方介绍。 command buffer包含一系列渲染命令,类似于opengl的gl.xxx渲染命令函数但也不尽相同,最重要可以渲染开发者指定的object到延迟渲染的gbuffer中,在场景渲染后进行渲染。 那么我们就可以通过command buffer去特定渲染一些物体,特别是在延迟渲染等后处理中操作。...

羊羊的博客 6661

(五)CommandBuffer基本应用

文章目录1.前言2.基本方法2.1 DrawRenderer2.1.1 ToScreen2.1.2 ToTarget2.2 DrawMesh2.2.1 ToScreen2.2.2 ToTarget3.使用方法4.完整代码4.1 使用代码4.2 Mesh代码 1.前言 CommandBuffer为渲染命令缓冲区,我们将一些列渲染指令添加到CommandBuffer中,在需要执行时通过Camera或者...

qq_37833413的博客 1880

Unity CommandBuffer

一、介绍 CommandBuffer是Unity提供用于扩展内置渲染管线的,Unity可以让我们扩展性地在一些指定的渲染节点上做一些自定义的操作,这些自定义的操作命令就是放置在CommandBuffer中的,而这些特殊的渲染节点放置在CameraEvent.enum中进行,这些可扩展的节点主要就是各个渲染过程的衔接点; 二、抓取屏幕内容 GetTemporaryRT/ReleaseTempo...

mozhi 1032

Unity commandbuffer

在渲染不透明物体和天空盒之后,当前图像被复制到一个临时渲染目标中,模糊并设置为全局着色器属性。然后在玻璃物体上的着色器对模糊的图像进行采样,基于法线贴图的UV坐标偏移来模拟折射。这类似于shader GrabPass所做的,除了你可以做更多自定义的事情(在这种情况下,模糊)。

DXT的博客 491

渲染命令与批处理

底层命令缓冲区,支持批量录制和提交渲染命令,减少CPU-GPU同步。:自动分组、合并绘制请求,极大提升渲染效率。这些机制是现代渲染管线高性能的基础,开发者应充分利用并结合实际场景优化。下面继续深入讲解渲染命令与批处理,包括CommandBuffer的底层细节、SRP Batcher的工作机制、批处理的局限性与调试方法,以及实际开发中的优化建议。:底层命令录制与批量提交,提升CPU-GPU协作效率。批处理技术。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 782

Scriptable Render Pipeline (SRP) 之 CommandBuffer

///////////////////////////////////////////////////// CommandBuffer Description List of graphics commands to execute. Command buffers hold list of rendering commands ("set render target, draw mesh, ..."). They can be set to execute at various points ..

蛰伏--当你不够强大时,就不要放弃努力 985
上一篇: Unity Shader-死亡溶解效果
下一篇: Unity Shader-遮挡处理(X-Ray,遮挡描边,遮挡半透,遮挡溶解)
puppet_master
puppet_master 领域专家: C/C++技术领域 领域专家: C/C++技术领域
博客等级 码龄12年 2695粉丝 161原创
评论 35
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值