怎么让网站能被百度到/新品上市的营销方案
一、Command Buffer
1.概念
CommandBuffer携带一系列的渲染命令,依赖相机,用来拓展渲染管线的渲染效果。而且可以指定在相机渲染的某个点执行本身的拓展渲染。Command buffers也可以结合屏幕后期效果使用。
简单来说就是可以在渲染流程中插入一些自定义操作,开发者得到了更多的权限。
2.渲染流程图
左图绿点处就是可以让开发者进行操作的地方,右图蓝色是蓝色线框部分。
3.怎么创建?如何启用?
1.在unity里首先创建一个C#脚本和一个Shader脚本还有一个默认材质球。
2.将材质赋给场景中的测试物体。
3.进行脚本编写
C#脚本
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;[ExecuteInEditMode]
public class CommandBufferTest01 : MonoBehaviour
{public Shader shader;public Renderer render;public CameraEvent cameraEvent;private void OnEnable(){CommandBuffer tBuffer = new CommandBuffer();//设置渲染tBuffer.DrawRenderer(render, new Material(shader));//不透明物体渲染完后执行Camera.main.AddCommandBuffer(cameraEvent,tBuffer);}private void OnDisable(){Camera.main.RemoveAllCommandBuffers();}
}
Shader脚本:
shader脚本只改下颜色即可,后面作比对用。
然后就可以看到效果:
相机在渲染完不透明物体后又渲染了一遍我们自己添加Buffer。导致Game窗口下物体为Shader中返回的颜色。
camera中也可以看到所添加的Command Buffer。
这样一个最简单的CommandBuffer应用就搞定了。
4.分析、实现Unity官方CommandBuffer Demo效果
官方Demo效果:
自己实现:
步骤:
1.先渲染不透明物体
2.抓取屏幕
3.渲染玻璃材质
4.合成
官方代码:
CommandBufferBlurRefraction.cs
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections.Generic;[ExecuteInEditMode]
public class CommandBufferBlurRefraction : MonoBehaviour
{public Shader m_BlurShader;private Material m_Material;private Camera m_Cam;// We'll want to add a command buffer on any camera that renders us,// so have a dictionary of them.private Dictionary<Camera,CommandBuffer> m_Cameras = new Dictionary<Camera,CommandBuffer>();// Remove command buffers from all cameras we added intoprivate 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();}// Whenever any camera will render us, add a command buffer to do the work on itpublic void OnWillRenderObject(){var act = gameObject.activeInHierarchy && enabled;if (!act){Cleanup();return;}var cam = Camera.current;if (!cam)return;CommandBuffer buf = null;// Did we already add the command buffer on this camera? Nothing to do then.if (m_Cameras.ContainsKey(cam))return;if (!m_Material){m_Material = new Material(m_BlurShader);m_Material.hideFlags = HideFlags.HideAndDontSave;}buf = new CommandBuffer();buf.name = "Grab screen and blur";m_Cameras[cam] = buf;// copy screen into temporary RT//获取渲染纹理IDint screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");//用screenCopyID标识,获取一个模板纹理。buf.GetTemporaryRT (screenCopyID, -1, -1, 0, FilterMode.Bilinear);//BuiltinRenderTextureType.CurrentActive也就是当前屏幕的纹理标识,将其赋值进screenCopyID标识的纹理。buf.Blit (BuiltinRenderTextureType.CurrentActive, screenCopyID);// get two smaller RTs//获取2个模板纹理,后面将它们2的效果轮流混合。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);// downsample screen copy into smaller RT, release screen RT//将抓屏纹理_ScreenCopyTexture采样填充到_Temp1后释放。buf.Blit (screenCopyID, blurredID);buf.ReleaseTemporaryRT (screenCopyID);// horizontal blur//修改SeparableBlur.shader的全局参数offsets,使其产生各个方向的模糊效果来叠加增强效果。//(如果着色器不在 Properties模块中暴露某个参数,将使用全局属性)buf.SetGlobalVector("offsets", new Vector4(2.0f/Screen.width,0,0,0));//使用m_Material渲染blurredID结果赋值给blurredID2。buf.Blit (blurredID, blurredID2, m_Material);// vertical blurbuf.SetGlobalVector("offsets", new Vector4(0,2.0f/Screen.height,0,0));buf.Blit (blurredID2, blurredID, m_Material);// horizontal blurbuf.SetGlobalVector("offsets", new Vector4(4.0f/Screen.width,0,0,0));buf.Blit (blurredID, blurredID2, m_Material);// vertical blurbuf.SetGlobalVector("offsets", new Vector4(0,4.0f/Screen.height,0,0));buf.Blit (blurredID2, blurredID, m_Material);//得到透明效果纹理后,赋值给GlassWithoutGrab.shader的_GrabBlurTexture混合得出模糊透明。buf.SetGlobalTexture("_GrabBlurTexture", blurredID);cam.AddCommandBuffer (CameraEvent.AfterSkybox, buf);}
}
SeparableBlur.shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Hidden/SeparableGlassBlur" {Properties {_MainTex ("Base (RGB)", 2D) = "" {}}CGINCLUDE#include "UnityCG.cginc"struct v2f {float4 pos : POSITION;float2 uv : TEXCOORD0;float4 uv01 : TEXCOORD1;float4 uv23 : TEXCOORD2;float4 uv45 : TEXCOORD3;};float4 offsets;sampler2D _MainTex;//偏移定点uv,使其读取到周围颜色值进行混合。v2f vert (appdata_img v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = 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;}//混合颜色值。half4 frag (v2f i) : COLOR {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#pragma fragmentoption ARB_precision_hint_fastest#pragma vertex vert#pragma fragment fragENDCG}
}Fallback off
GlassWithoutGrab.shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'// Similar to regular FX/Glass/Stained BumpDistort shader
// from standard Effects package, just without grab pass,
// and samples a texture with a different name.Shader "FX/Glass/Stained BumpDistort (no grab)" {
Properties {_BumpAmt ("Distortion", range (0,64)) = 10_TintAmt ("Tint Amount", Range(0,1)) = 0.1_MainTex ("Tint Color (RGB)", 2D) = "white" {}_BumpMap ("Normalmap", 2D) = "bump" {}
}Category {// We must be transparent, so other objects are drawn before this one.Tags { "Queue"="Transparent" "RenderType"="Opaque" }SubShader {Pass {Name "BASE"Tags { "LightMode" = "Always" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fog#include "UnityCG.cginc"struct appdata_t {float4 vertex : POSITION;float2 texcoord: TEXCOORD0;};struct v2f {float4 vertex : POSITION;float4 uvgrab : TEXCOORD0;float2 uvbump : TEXCOORD1;float2 uvmain : TEXCOORD2;UNITY_FOG_COORDS(3)};float _BumpAmt;half _TintAmt;float4 _BumpMap_ST;float4 _MainTex_ST;v2f vert (appdata_t v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);#if UNITY_UV_STARTS_AT_TOPfloat scale = -1.0;#elsefloat scale = 1.0;#endif//将顶点裁剪空间下的坐标,计算NDC空间上的位置后,映射到模糊纹理的uv。o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;o.uvgrab.zw = o.vertex.zw;o.uvbump = TRANSFORM_TEX( v.texcoord, _BumpMap );o.uvmain = TRANSFORM_TEX( v.texcoord, _MainTex );UNITY_TRANSFER_FOG(o,o.vertex);return o;}//抓屏得到的模糊纹理会赋值到此。(因为Properties没有定义_GrabBlurTexture,所以默认使用全局的参数)sampler2D _GrabBlurTexture;float4 _GrabBlurTexture_TexelSize;sampler2D _BumpMap;sampler2D _MainTex;half4 frag (v2f i) : SV_Target{// calculate perturbed coordinates// we could optimize this by just reading the x & y without reconstructing the Zhalf2 bump = UnpackNormal(tex2D( _BumpMap, i.uvbump )).rg;float2 offset = bump * _BumpAmt * _GrabBlurTexture_TexelSize.xy;i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;//对模糊纹理采样half4 col = tex2Dproj (_GrabBlurTexture, UNITY_PROJ_COORD(i.uvgrab));half4 tint = tex2D(_MainTex, i.uvmain);//模糊纹理与主纹理混合得出模糊透明效果col = lerp (col, tint, _TintAmt);UNITY_APPLY_FOG(i.fogCoord, col);return col;}ENDCG}}}}
注意点:
虽然Shader.PropertyToID返回的是一个int类型,但是Blit操作用到的ID会强转成RenderTargetIdentifier,以供Blit需要。
在其源码中可以看到
5.Command Buffer相关代码结构图梳理
经过1、2、3步的操作后就应该对Command Buffer有个大致的了解,下面对Comman Buffer相关的代码进行一个梳理,只列举一些关键、常用的变量和函数。
关系图
5.1一些概念补充
先知道一些基础的概念,然后再继续深入。
- RenderTarget
-
- 在3D计算机图形领域,渲染目标是现代图形处理单元(GPU)的一个特征,它允许将3D场景渲染到中间存储缓冲区或渲染目标纹理(RTT),而不是帧缓冲区或后缓冲区。然后可以通过像素着色器操纵此RTT ,以便在显示最终图像之前将其他效果应用于最终图像。
- 渲染目标就是一个缓冲区,(除了back frame buffer 和screen frame buffer之外的缓冲区)用来记录渲染后的输出的结果,而不直接将帧缓冲绘制到屏幕。而是将其应用到别处。
离屏渲染,就可以通过渲染目标实现的。
- RenderTexture
-
- 渲染纹理是指可以被渲染的纹理。
- RT(RenderTarget)可以用来实现基于图像的渲染效果,动态阴影,反射,监控相机【cs1.6里的assault仓库】。
- 渲染纹理的经典用法是将RenderTexture设置为相机的“TargetTexture”(Camera.targetTexture),这将会使得相机渲染的结果渲染到RenderTexture上而不是直接渲染到屏幕上。
- 需要记住的是,渲染纹理的像素内容可能会在某些事件中丢失,比如:加载新关卡,屏幕进入保护模式,全屏进入,当这种情况发生时,你的RenderTexture将会再次变成“尚未创建”,遇到这种情况需要用IsCreate函数进行检测。
- 和其他“原生引擎对象”的类型一样,需要关注RenderTexture的生命周期,并在使用完成之后使用Release函数进行释放,因为RenderTexture不会像普通托管类型那样会被GC(垃圾回收)。
- RenderTargetIdentifiler
-
- 这个结构体主要描述,绑定的RenderTexture如何应用到RenderTarget上,使用哪个Mip,使用哪个CubeMap的Face。
- 对于Texture3D/Texture2DArray,还能够指定使用哪个depthSlice进行写入。
5.2Command Buffer 常用函数
变量、函数名 | 作用 | 示例图 |
CommandBuffer.BeginSample CommandBuffer.EndSample | 将对应的Pass框选出来,方便在Profile里进行分析。但是在URP的源码里经常会出现其他的写法,使用using(newProfilingScope(CommandBuffer cmd,ProfilingSampler sampler)) | |
CommandBuffer.GetTemporayRT | 申请一张临时的RT,配合RenderIdentifier使用 | |
CommandBuffer.SetRenderTarget | 设置渲染目标,添加一个激活渲染目标的指令到CommandBuffer中。 指定一张RenderTexture作为RenderTarget可以使用好几种方法: 1.直接使用RenderTexture 2.GetTemporaryRT申请的RT的Id(int)类型 3.在渲染周期内生成的内置(Built-In)RenderTexture[BuiltinRenderTextureType] 这些全部都会被隐式转换成RenderTargetIdentifier这个结构体。 | |
RenderBufferLoadAction | Load:当RenderBuffer被激活时,载入原本已保存的内容,这个加载读取的操作对Tile base架构的GPU比较占用带宽。 Clear:当RenderBuffer被激活时,会清理掉原本Buffer里的内容。目前不能直接使用,需要使用CommandBuffer.CleanRenderTarget作为代替。 DontCare:当RenderBuffer被激活时,GPU不会把RenderBuffer的内容加载进内存,从而减少带宽传输压力。 unity CommandBuffer.SetTarget()几个重载都是用的Load | |
RenderBufferStoreAction | 跟RenderBufferLoadAction类似,但这个枚举类型参数主要是控制RenderBuffer存储时的策略。 Store:RenderBuffer的内容需要存储到RAM中。如果启用了MSAA,这是就会存储未Resolve(non-resolved)的着色结果。 Resolve:GPU将多重采样数据(Multisampled data)重新解析(resolve)为每像素一个采样点,并将数据存储到RenderTexture中,丢弃了多采样数据)。目前不能直接设置,只能调用API进行Resolve StoreAndResolve: 将多重采样数据(Multisampled data)重新解析(resolve)为每像素一个采样点,并将数据存储到RenderTexture中,并且存储多重采样数据。目前不能直接使用,只能调用API进行Resolve。 DontCare:RenderBuffer的内容是不需要的,可以被丢弃。Tile-base架构的GPU将完全跳过存储阶段,有次减少带宽压力,提高性能。[RenderTextureMemoryless需要设置对象的模式] unity CommandBuffer.SetTarget()几个重载都是用的Resolve | |
RenderTargetBinding | 把一个或者多个ColorBuffer以及一个深度/模板缓冲[8/16/24/32bit]如何绑定到RenderTarget上,并且他们各自Load和Store的策略。 | |
CommandBuffer.DrawMesh | mesh:绘制使用的网格 matrix:绘制时使用的模型空间矩阵(M) material:绘制时使用的材质 submeshindex:绘制的子网格的索引值 shaderPass:Material对应的shader使用Pass的索引值,默认为-1,渲染所有Pass properties:MaterialPropertyBlock不需要额外创建材质实例就可以覆写当前绘制时的材质属性值。 | |
CommandBuffer.DrawMeshInstanced | 使用实例化绘制多个相同Mesh,看到matrices和count这两个参数,说明绘制时需要提供模型空间矩阵(M)数组,以及绘制的数量。 需要注意的是:绘制时的Material对应的shader一定得是支持Instance绘制。 | |
CommandBuffer. DrawMeshInstanceProcedural | 绘制Instance时的InstancePath是Instance Procedural。 跟之前的DrawMeshInstanced相比,区别就是,不支持LightMap和LightProbe需要手动在Procedural的函数实现,从Instance和CBuffer中通过InstanceID获取每个实例所对应的的LightMapST,LightMapIndex,LightProbe的SH,Occlusion数值。 | |
CommandBuffer. DrawMeshInstanceIndirect | 绘制Instance时,除了需要提供绘制Instance的Mesh之外,还需要通过MaterialPropertyBlock设置绘制时所需要用到的Compute Shader计算的数据。 另外需要用BufferArgs控制绘制的顶点数以及实例数量,绘制时开始的Index位置,开始绘制时的Instance位置。 可以看到BufferArgs的可控性更强了,但是一般而言是会配合着Compute Shader进行控制BufferArgs的数值,然后再通过BufferArgs绘制Instance。 一般来说,DrawMeshInstanceIndirect会用来制作视锥裁剪的四叉树地形,草地等等。 | |
CommandBuffer.DrawProcedural | 选择绘制的拓扑结构进行绘制Mesh,不需要用vertex/index buffer,用Compute shader生成顶点数据,然后再调用DrawProcedural的时候用Vertex Shader对顶点数据进行描绘。 需要注意的是Compute Shader的计算不属于图元装配阶段。 Compute Shader - OpenGL Wiki Compute Shader介绍(一) | |
CommandBuffer. DrawProceduralIndirect | 不需要用vertex/index buffer,同时也和 DrawMeshInstanceIndirect一样,需要提供BufferArgs控制实例化的过程参数。 在Shader里也同样能够使用InstanceID。 | |
CommandBuffer.DrawRenderer | 最为常用的用法还是写在Gameloop里用脚本获取常经理的Renderer,在管线里new一个Renderer来渲染貌似不是一个好主意。 | |
CommandBuffer.Blit | 在实际使用的时候,为了以防万一尽量使用CommandBuffer.SetGlobalTexture配合Shader.PropertyToID设置参数。 另外,最好还是得手动SetRenderTarget设置下LoadAction以及StoreAction节省带宽 | |
5.3代码结构图
--------待补充--------
二、自定义渲染管线(Scriptobject Renderer Pipeline)
此处开始全是在URP下进行(我用的版本Unity2020.3f1c1 URP Linear空间)
1.Unity URP自带的渲染管线
1.1流程梳理
Edit->Project Setting->Quality
这个UniversalRP-HighQuality就是我们以后要替换的URPAsset。
点击这个Asset可以在Inspector面板上看到RendererList。
点击ForwardRenderer(Forward Renderer Data)。
Renderer Feature就是后面我们自定义的东西,上面的Post Process Data也是可以自定义的,先不管。
1.2关系图
1.3代码结构图
--------待补充--------
2.自定义渲染管线
Unity自带的渲染管线创建如下图。
点击Pipeine Asset(Forward Renderer),会创建两个默认的配置文件,就是上面流程梳理里面的两个文件。
不管这两个文件,下面开始创建自己的渲染管线。
2.1创建渲染管线实例
首先创建两个脚本分别叫做CustomRenderPipline和CustomRenderPiplineAsset。
分别继承RenderPipeline和RenderPipelineAsset如下。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;public class CustomRenderPipeline : RenderPipeline
{protected override void Render(ScriptableRenderContext context, Camera[] cameras){}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;[CreateAssetMenu(menuName = "Rendering/Custom Render Pipeline")]
public class CustomRenderPipelineAsset : RenderPipelineAsset
{protected override RenderPipeline CreatePipeline(){return new CustomRenderPipeline();}
}
然后右键创建对应的RP Asset,将原本的Asset替换成我们自己创建的RP Asset,发现窗口什么都渲染不出。
因为还没有指定渲染相机。
2.2创建渲染相机脚本
创建一个新的自定义相机渲染脚本CustomCameraRenderer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;public class CustomCameraRenderer
{private Camera _camera;private ScriptableRenderContext _context;public void Render(ScriptableRenderContext sContext, Camera rCamera){this._camera = rCamera;this._context = sContext;}
}
然后将CustomRenderPipeline设置返回值。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;public class CustomRenderPipeline : RenderPipeline
{private CustomCameraRenderer _renderer = new CustomCameraRenderer();protected override void Render(ScriptableRenderContext context, Camera[] cameras){foreach (Camera camera in cameras){_renderer.Render(context,camera); } }
}
camera renderer 大致相当于通用RP的scriptable renderer。
这种方法能让每个相机在未来更容易支持不同的渲染方法。例如一个渲染第一人称视图,一个渲染三维地图,或前向和延迟渲染的区别。但现在我们会用同样的方式渲染所有的摄像机。
ScriptableRenderContext包含了一些渲染相关的数据,具体可以查看源码。
--------------------------------后续借用Catlike里面的截图----------------------------------
(_camera->camera 、_context->context)
2.3渲染天空盒
在CustomCameraRenderer中对可见物体进行绘制Context.DrawSkybox(camera);
将缓存中的命令提交到执行队列里。
需要提前计算VP矩阵,使最终得到的图像正常。
2.4 Command Buffer
上下文会延迟实际的渲染,直到我们提交它为止。在此之前,我们对其进行配置并向其添加命令以供后续的执行。某些任务(例如绘制天空盒)提供了专属方法,但其他命令则必须通过单独的命令缓冲区(command buffer)间接执行。我们需要用这样的缓冲区来绘制场景中的其他几何图形。
为了获得缓冲区,我们必须创建一个新的CommandBuffer对象实例。一般只需要一个缓冲区,因此默认情况下为CameraRenderer创建一个缓冲区,并将对它的引用存储在字段中。给缓冲区起一个名字,以便我们在frame debugger中识别它。就叫Render Camera好了。
CustomCameraRenderer里添加CommandBuffer,如下图所示。
我们可以使用命令缓冲区注入给Profiler样本,这些样本将同时显示在Profiler和frame debugger中。通过在适当的位置插入BeginSample和EndSample就可以完成。在本例中,在Setup和Submit的开头添加。注意两个方法必须提供相同的样本名称,为此我们直接使用缓冲区的名称。
要执行缓冲区,在上下文中调用ExecuteCommandBuffer,并把缓冲区作为一个参数。这是从缓冲区中复制命令,但并不清除它,如果我们想重新使用它,我们必须在事后明确地这样做。因为执行和清除总是一起进行的,所以添加一个方法来做这两件事是很方便的。
简单来说就是我们可以手动控制渲染顺序,并且在Profiler和Frame Debug上面进行单独框选命名(方便查看)。
2.5 清除渲染目标
我们画的东西最终会被渲染到摄像机的渲染目标上,默认情况下是帧缓冲区,但也可以是渲染纹理。之前绘制到该目标上的东西仍然存在,这可能会干扰我们现在正在渲染的图像。为了保证正常的渲染,我们必须清除渲染目标,以摆脱它的旧内容。这可以通过在命令缓冲区上调用ClearRenderTarget来实现,它属于Setup方法。
帧调试器现在显示了清除的Draw GL条目,它显示嵌套在Render Camera的一个额外层次中。这是因为ClearRenderTarget用命令缓冲区的名字将清除动作包裹在一个样本中。我们可以通过在开始我们自己的样本之前进行清除来摆脱多余的嵌套。这导致了两个相邻的Render Camera样本范围,它们被合并了。
Draw GL条目表示用Hidden/InternalClear着色器绘制全屏四边形,该着色器会写入渲染目标,这并不是最有效的清除方式。使用这种方法是因为我们是在设置摄像机属性之前进行清除。如果我们把这两个步骤的顺序对调一下,就可以得到快速的清除方式。
现在我们看到Clear(color+Z+stencil),这表明颜色和深度缓冲区都被清除了。Z(深度缓冲区)和模版数据是整个缓冲区的一部分。
2.5 Culling
剔除这部分就是要剔除相机看不到的地方,为此我们可以使用ScriptableCullingParameters结构。
我们可以在摄像机上调用TryGetCullingParameters,用它来返回一个bool值用作后续的渲染。
实际的剔除是通过在上下文中调用Cull来完成的,它会产生一个CullingResults结构。如果成功的话就在Cull中进行,并将结果存储在一个字段中。在这种情况下,我们必须把剔除参数作为一个引用参数来传递,在它前面写上ref。
2.6 Drawing Geometry
一旦我们知道什么是可见的,我们就可以继续渲染这些东西了。这可以通过在上下文中调用DrawRenderers来完成,并将剔除结果作为一个参数,告诉它要使用哪些渲染器。
除此之外,我们还必须提供绘制设置和过滤设置。两者都是结构体--绘图设置(DrawingSettings)和过滤设置(FilteringSettings),我们最初会使用它们的默认构造函数。两者都必须通过引用来传递。
在绘制天空盒之前,在DrawVisibleGeometry中这样做。
我们还没有看到任何东西,因为我们还必须指出哪种着色器通道是允许的。由于我们在本教程中只支持非亮光着色器,我们必须为SRPDefaultUnlit通道获取着色器标签ID,我们可以做一次并将其缓存在一个静态字段中。
将其作为DrawingSettings构造函数的第一个参数,同时提供一个新的SortingSettings结构值。将相机传递给排序设置的构造函数,因为它被用来确定是否适用正交或基于距离的排序。
除此之外,我们还必须指出哪些渲染队列是允许的。将RenderQueueRange.all传递给FilteringSettings构造函数,这样我们就包括了所有的东西。
可以看到现在透明与不透明物体的渲染顺序杂乱无章,下面要再对排序进行处理。
此处为语雀视频卡片,点击链接查看:bandicam 2022-01-25 14-00-57-377.mp4
这样渲染顺序就是正常的。
此处为语雀视频卡片,点击链接查看:bandicam 2022-01-25 14-10-58-873.mp4
2.7 分别单独绘制不透明物体和透明物体
目前天空盒会遮挡住透明物体,因此我们需要调整不透明物体与天空盒绘制的顺序。
我们可以通过切换到RenderQueueRange.opaque来消除初始DrawRenderers调用中的透明对象。
然后重新设置下绘制相关参数,重新进行绘制。
相关文章:

3.72 Command Buffer及URP概述
一、Command Buffer 1.概念 CommandBuffer携带一系列的渲染命令,依赖相机,用来拓展渲染管线的渲染效果。而且可以指定在相机渲染的某个点执行本身的拓展渲染。Command buffers也可以结合屏幕后期效果使用。 简单来说就是可以在渲染流程中插入一些自定…...

分布式理论和分布式锁知识点总结
文章目录 (一) 分布式理论算法和协议1)CAP理论总结 2)BASE理论BASE 理论的核心思想基本可用软状态最终一致性 3)Paxos算法Basic Paxos 算法4) Raft算法1 拜占庭将军 5)Gossip协议 (二) 分布式锁分布式锁应该具备哪些条…...

IOC课程整理-17 Spring事件
1. Java 事件/监听器编程模型 2. 面向接口的事件/监听器设计模式 3. 面向注解的事件/监听器设计模式 4. Spring 标准事件-ApplicationEvent 5. 基于接口的 Spring 事件监听器 6. 基于注解的 Spring 事件监听器 7. 注册 Spring ApplicationListener 8. Spring 事件发布器 9. Spr…...

大数据Flink(一百零五):SQL性能调优
文章目录 SQL性能调优 一、 MiniBatch 聚合...

ESP8266,手机与电脑之间的TCP通讯
电脑端运行通讯猫调试助手,作为服务端: 电脑端 电脑的IP地址是: 192.168.2.232 手机与电脑之间的TCP通讯 手机端运行网络调试精灵,作为客户端: 手机端 如果从手机端点击"发送"按钮,则也会将"ghhh东方红广场"几个字发送到电脑上(服务端). ESP8266作为客户…...

vue的数据监听是如何实现的?
Vue的数据监听是通过数据劫持和发布订阅模式来实现的。 数据劫持:Vue通过使用Object.defineProperty()方法来劫持数据对象的属性,并使用getter和setter来监听属性的变化。当属性被修改时,setter方法会被调用,从而触发相应的监听函…...

埋点日志解决方案——Golang+Gin+Sarama VS Java+SpringCloudGateway+ReactorKafka
埋点日志解决方案——GolangGinSarama VS JavaSpringCloudGatewayReactorKafka 之前我就写过几篇OpenRestylua-kafka-client将埋点数据写入Kafka的文章,如下: Lua将Nginx请求数据写入Kafka——埋点日志解决方案 python定时任务执行shell脚本切割Nginx…...

LeetCode 541 反转字符串 II 简单
题目 - 点击直达 1. 541 反转字符串 II 简单1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 解题思路1. 思路分析2. 时间复杂度3. 代码实现 1. 541 反转字符串 II 简单 1. 题目详情 给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个…...

从入门到精通:深入了解CSS中的Grid网格布局技巧和应用!
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一…...

Android Studio Giraffe 添加 maven { url “https://jitpack.io“ }报错
Android Studio Giraffe 添加 maven { url “https://jitpack.io” }报错 settings.gradle.kts:13:21: Unexpected tokens (use ; to separate expressions on the same line)解决方法 新版maven写法发生了改变: maven { url uri("https://jitpack.io"…...

Linux C/C++ 实现网络流量分析(性能工具)
网络流量分析的原理基于对数据包的捕获、解析和统计分析,通过对网络流量的细致观察和分析,帮助管理员了解和优化网络的性能、提高网络安全性,并快速排查和解决网络故障和问题。 Linux中的网络流量常见类型 在Linux中,网络流量可以…...

python门牌制作,统计某个数字出现的次数
题目: 小蓝要为一条街的住户制作门牌号。 这条街一共有 2022位住户,门牌号从 1 到 2022 编号。 小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、…...

轻量封装WebGPU渲染系统示例<7>-材质多pass(源码)
当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/version-1.01/src/voxgpu/sample/MultiMaterialPass.ts 此示例渲染系统实现的特性: 1. 用户态与系统态隔离。 2. 高频调用与低频调用隔离。 3. 面向用户的易用性封装。 4. 渲染数据和渲染机制分离。 …...

0030Java程序设计-积分管理系统论文
文章目录 摘 要**目 录**系统实现系统功能需求3.2.1 管理员功能3.2.2 柜员功能 开发环境 摘 要 随着计算机和网络的不断革新,世界已经进入了前所未有的电子时代。作为实用性强、应用范围广泛的会员管理系统也正在被越来越多的各类企业用于消费管理领域。然…...

H5游戏源码分享-考眼力游戏猜猜金币在哪
H5游戏源码分享-考眼力游戏猜猜金币在哪 <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><meta charset"UTF-8"><meta name"apple-mobile-web-app-capa…...

2023 年值得关注的国外网络安全初创公司
网络安全初创公司试图解决的问题往往有点超前于主流。他们可以比大多数老牌公司更快地填补空白或新兴需求。初创公司通常可以更快地创新,因为它们不受安装基础的限制。 当然,缺点是初创公司往往缺乏资源和成熟度。公司致力于初创公司的产品或平台是有风…...

搞定蓝牙-第六篇(HID
搞定蓝牙-第六篇(HID) ble与HIDHOGPGAPP与HID ESP32程序分析 ble与HID HOGP 我们发现,电脑连接了蓝牙键盘就可以直接使用了,不需要配置任何东西,那么,这两者是怎么通讯的呢。我们使用的电脑windows系统内…...

Open3D(C++) 最小二乘拟合平面(直接求解法)
目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。 一、算法原理 平面方程的一般表达式为: A x + B y + C...

lua移植及使用
编译环境:Ubuntu16.04 64位 交叉编译工具:arm-hisiv500-linux-gcc 文章目录 1. 项目背景2. lua开源版本选择3. 封装代码3.1 源码简介3.2 封装类3.2.1 头文件3.2.2 类的实现3.3.3 sample代码 1. 项目背景 使用lua脚本,读取key对应的值&#x…...

【鸿蒙软件开发】ArkTS基础组件之Select(下拉菜单)、Slider(滑动条)
文章目录 前言一、Select下拉菜单1.1 子组件1.2 接口参数 1.3 属性1.4 事件1.5 示例代码 二、Slider2.1 子组件2.2 接口参数:SliderStyle枚举说明 2.3 属性2.4 事件SliderChangeMode枚举说明 2.5 示例代码 总结 前言 Select组件:提供下拉选择菜单&#…...

linux ssh 免密登录
概述 在大数据测试环境搭建时,经常会用到 ssh 免密登录 ,方便机器之间分发文件,从一个机器上登录至其它机器也方便 如何配置 linux 的 ssh 免密登录? 非免密登录 端口是22 [rootKS8P-Test-K8S06 ~]# ssh KS8P-Test-K8S06端口非22 [roo…...

秒级启动的集成测试框架
本文介绍了一种秒级启动的集成测试框架,使用该框架可以方便的修改和完善测试用例,使得测试用例成为测试过程的产物。 背景 传统的单元测试,测试的范围往往非常有限,常常覆盖的是一些工具类、静态方法或者较为底层纯粹的类实现&…...

Redux 数据仓库
Redux 数据仓库 解决React 数据管理(状态管理) ,用于中大型,数据比较庞大,组件之间数据交互多的情况下使用。 作者:如果你不知道是否需要使用Redux,那么你就不需要它! 解决组件的数据通信。 …...

[毕设记录]@开题调研:一些产品
我感觉产品能代表落地的一些实际应用,会和研究的角度有些差别,但是需求和兴趣往往是从现实中来的,在上一篇blog里面看外国blog的时候顺着搜搜到了很多国外的智慧校园chatbot解决方案 文章目录 Comm100streebomodern campusUniBuddy Comm100 …...

CSS3中的字体和文本样式
CSS3优化了CSS 2.1的字体和文本属性,同时新增了各种文字特效,使网页文字更具表现力和感染力,丰富了网页设计效果,如自定义字体类型、更多的色彩模式、文本阴影、生态生成内容、各种特殊值、函数等。 1、字体样式 字体样式包括类…...

LVS集群-DR模式【部署高可用LVS-DR集群】
文章目录 2.2 实战:配置LVS-DR集群2.2.1 配置IP(Director Server的部署配置)2.2.2 生成ens33:1配置文件 (Director Server的部署配置)2.2.3 配置LVS-DR规则(Director Server的部署配置)2.2.4 两…...

银河麒麟服务器版v4安装程序缺少依赖包,改为利用手机联网在线安装
1 将安卓手机连接使用usb转typec线连接到服务器的usb口。(linux桌面版)也可以类似的方法手机联网。 2 在手机热点中打开usb共享 3 使用ifconfig命令找到手机被服务器识别成的网卡名 4 使用dhclient “手机网卡名”命令,使服务器能上网。 5 变…...

Maven第一章:Maven安装、验证、使用
Maven第一章:Maven安装、验证、使用 前言 谁适合阅读本教程? Java开发人员:Maven是Java项目管理和构建工具,因此对Java开发人员来说是一个重要的工具。阅读Maven知识可以帮助他们更好地理解如何使用Maven来管理Java项目,包括依赖管理、构建自动化、项目构建和部署等。项目…...

ios 代码上下文截屏之后导致的图片异常问题
业务场景,之前是直接将当前的collectionview截长屏操作,第一次截图会出现黑色部分原因是视图未完全布局,原因是第一次使用了Masonry约束然后再截图的时候进行了frame赋值,可以查看下Masonry约束和frame的冲突,全部修改…...

《嵌入式软\硬件开发难点-2023-10-29》
一、《嵌入式软件开发难点》 内存有限、螺蛳壳里做道肠;处理能力有限,必须做好规划,榨取系统每一份处理能力;现代开发工具和实际工具难实施,资源问题:C/Python/Java;调试跟踪问题较困难&#x…...