Learn SRP 02

3.Editor Rendering

3.1Drawing Legacy Shaders

因为我们的管线只支持无光照的着色过程,使用其他不同的着色过程的对象是不能被渲染的,他们被标记为不可见。尽管这是正确的,但是它还是隐藏了场景中一些使用错误着色器的对象。所以让我们来渲染它们吧,但是要和无光照分开。

为了能够兼容所有unity默认的着色器我们必须使用着色器标记ID(ShaderTagId),把Always,ForwardBase,PrepassBase,Vertex,VertexLMRGBM,和VertexLM放到一个静态数组里。

	static ShaderTagId[] legacyShaderTagIds = {new ShaderTagId("Always"),new ShaderTagId("ForwardBase"),new ShaderTagId("PrepassBase"),new ShaderTagId("Vertex"),new ShaderTagId("VertexLMRGBM"),new ShaderTagId("VertexLM")};

DrawVisibleGeometry函数之后我们使用一个单独的方法绘制所有不支持的着色器。因为它们是错误的着色过程所以无论如何渲染结果都是错误的,所以我们不用关心其他设置。我们可以使用默认的过滤设置FilteringSetting.defaultValue属性。

我们可以多此调用DrawingSettingSetShaderName方法,使用序列和标记作为参数。因为在构造函数中已经加入了第一个Tag,所有我们对数组的操作从第二个开始。

	void DrawUnsupportedShaders(){var drawingSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera));for (int i = 1; i < legacyShaderTagIds.Length; i++){drawingSettings.SetShaderPassName(i, legacyShaderTagIds[i]);}var filteringSettings = FilteringSettings.defaultValue;context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);}

3.2Error Material

为了明确的指明哪些对象使用了不支持的着色器我们用Unity错误的着色器来绘制它们。我们通过Shader.Find函数,使用Hidden/InternalErrorShader作为参数来构造一个全新的材质。我们将这个材质用静态字段缓存,这样我们就不用每帧都创建它了。然后将它赋值给DrawingSettingoverrideMaterial属性。

	static Material errorMaterial;…void DrawUnsupportedShaders () {if (errorMaterial == null) {errorMaterial =new Material(Shader.Find("Hidden/InternalErrorShader"));}var drawingSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera)) {overrideMaterial = errorMaterial};…}

显示结果:

现在所有使用其他着色器的都变成粉色了

3.3Partial Class 

绘制无效的对象对开发模式是有用的,但是对于正式版是没有意义的。所以我们把所有的只在编辑器模式有用的代码放在一个分开的局部类文件CameraRenderer中。首先复制原始的CameraRenderer文件,并将其命名为CamreaRenderer.Editor

然后将原始的CameraRenderer转换为局部类,并从中删除ShaderTagId数组,错误的材质,和DrawUnsupportedShaders方法。

什么是局部类?

这是一种拆分类-结构体的方法,把他们放入不同的部分,存储在不同的文件中。这样做的目的是为了更好的组织代码。典型的用例是将自动生成的代码与手动编写的代码分开。就编译器而言,它们都是同一类定义的一部分。他们在Object Management, More Complex Levels教程中有介绍。

清理另一个局部类文件只包含上个文件我们之前删除的那部分。

这个编辑器部分的内容只需要在编辑器中执行,所以我们用条件宏来标记。

但是,现在发布模式运行还是会失败,因为另一个局部类中包含DrawUnsupportedShaders函数的调用,它应该只能存在于编辑器模式。为了解决这个问题,我们需要让这个方法正常执行。为此我们需要在方法前面用partial进行声明,类似于抽象方法声明。我们可以在类定义的任何部分中执行此操作,所以让我们把它放在编辑器部分。完整的方法声明也必须标记为partial。

public  partial class CameraRenderer : MonoBehaviour
{partial void DrawUnsupportedShaders();
#if UNITY_EDITORstatic Material errorMaterial;static ShaderTagId[] legacyShaderTagIds = {new ShaderTagId("Always"),new ShaderTagId("ForwardBase"),new ShaderTagId("PrepassBase"),new ShaderTagId("Vertex"),new ShaderTagId("VertexLMRGBM"),new ShaderTagId("VertexLM")};partial void DrawUnsupportedShaders(){if (errorMaterial == null){errorMaterial =new Material(Shader.Find("Hidden/InternalErrorShader"));}var drawingSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera)){overrideMaterial = errorMaterial};for (int i = 1; i < legacyShaderTagIds.Length; i++){drawingSettings.SetShaderPassName(i, legacyShaderTagIds[i]);}var filteringSettings = FilteringSettings.defaultValue;context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);}
#endif
}

3.4Drawing Gizmos

现在我们的管线不能绘制辅助图标(Gizmos),无论是场景视图还是游戏视图激活的时候都不会显示。

我们可以检查辅助图标是否应该被绘制通过执行UnityEditor.Handles.ShouldRenderGizmos函数。如果需要显示,我们必须调用context的DrawGizmos方法,并传递camera作为第一个参数,传入第二个参数来确定辅助图标的哪些子集需要被绘制。这里有两个子集,在ImageEffects(屏幕后效)之前和之后。因为我们现在不支持ImageEffects因此两个方法我们都会调用。我们在一个只有Editor模型运行的方法DrawGizmos。

using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;partial class CameraRenderer {partial void DrawGizmos ();partial void DrawUnsupportedShaders ();#if UNITY_EDITOR…partial void DrawGizmos () {if (Handles.ShouldRenderGizmos()) {context.DrawGizmos(camera, GizmoSubset.PreImageEffects);context.DrawGizmos(camera, GizmoSubset.PostImageEffects);}}partial void DrawUnsupportedShaders () { … }#endif
}

辅助图标将被绘制在所有对象绘制之后。

3.5Drawing Unity UI

另一个需要我们注意的事情是Unity的用户界面系统。例如,我们通过GameObject/UI/Button添加一个按钮来创建一个简单的UI。它将显示在game窗口,但是不会显示在scene窗口。

帧调试器显示UI是通过新增的UGUI.Rendering.RenderOverlays绘制的,并不是通过我们的渲染管线绘制的

这是因为UI的默认绘制模式是ScreenSpace-Overlay

当我们把UI的渲染模式修改成ScreenSpace-Camera模式。使用主摄像机作为RenderCamera的参数,可以使UI的渲染成为透明几何体的一部分。

在渲染scene窗口的时候我们可以通过执行ScriptableRenderContext.EmitWorldGeometryForSceneView函数和camera参数来将UI添加到世界的几何体中。在一个只有编辑器模式允许的新函数PrepareForSceneWindow中执行这些逻辑。当CameracameraType属性是CameraType.SceneView的时候我们渲染这个场景摄像机。

	partial void PrepareForSceneWindow ();#if UNITY_EDITOR…partial void PrepareForSceneWindow () {if (camera.cameraType == CameraType.SceneView) {ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);}}

因为我们要把几何体添加到场景中,所有我们必须在Culling剔除之前执行这个函数。

执行完这一步后UI就会被绘制到场景视图中了。

4.Multiple Cameras

在场景中有可能同时存在多个已激活的摄像机,如果是这样我们必须保证他们同时工作。

4.1Two Cameras

每一个摄像机都有一个深度(Depth)值,默认的主摄像机的值为-1。摄像机按深度增加的顺序进行渲染。为了看到这些,复制主摄像机,改它改名为SecondaryCamera,并把深度值设置为0。同时我们给它另一个tag值,因为MainCamera的tag只能被一个摄像机使用。

现在场景被渲染了两次。渲染结果的表现仍然是一样的,因为渲染过程中执行了清楚操作。FrameDebugger向我们展示了这个过程,但是因为相邻的具有相同名字的采样被合并成我们最终得到的一个Render Camera列表。

如果每个摄像机都有自己的范围,就更清楚了。为了使之成为可能,添加一个只在编辑器模式运行的函数PrepareBuffer方法,使得缓冲区的名字和相机的名字一样。

partial void PrepareBuffer ();#if UNITY_EDITOR…partial void PrepareBuffer () {buffer.name = camera.name;}#endif

现在看就清晰很多了

4.2Dealing with Changing Buffer Names

尽管现在FrameDebugger能够分开显示每个相机的采样信息,但是当我们进入运行模式时Unity的控制台将充满警告并告诉我们BeginSampleEndSample的计数必须要匹配(但是这里我没有报错不知道为啥)。因为我们对采用和他们的缓冲区使用了不同的名字,所以匹配混淆了。除此之外,我们每次访问camera的name属性也会造成内存的分配,所以我们不想在创建的时候这样做。

为了解决这两个问题我们添加一个SampleName字符串属性。在编辑器模式我们应该在PrepareBuffer函数中设置它和缓冲区的名字,运行模式它就是RenderCamera类的一个字符串常量值。

#if UNITY_EDITOR…string SampleName { get; set; }…partial void PrepareBuffer () {buffer.name = SampleName = camera.name;}#elseconst string SampleName = bufferName;#endif

然后在开始采样和结束采样的时候都使用SampleName

我们可以看到不同通过查看 profiler-打开 Window/Analgsis/Profiler。切换到Hierarchy模式然后按GC数据进行排序。可以看到有一个GC.Alloc,是96B。这部分就是在编辑器模式下产生的GC,在打包以后这部分GC就会消失。教程里后面摄像机数组的48bit不知道为啥没有出现。

4.3Layers

摄像机可以被配置成只看到某些层级的物体。这是通过调整摄像机的Culling Mask实现的。为了看到这个效果我们把所有使用标准着色器的对象设置为IgnoreRaycast层级 

然后从主摄像机的Culling Mask中排除这个层级。

SecondaryCameraCulling Mask设置为只有IgnoreRaycast

因为SecondaryCamera最后渲染,所以我们只能看到无效的对象。

4.4Clear Flags

我们可以通过设置CameraClearFlags来让第二个摄像机在第一个摄像机的渲染结果之上进行渲染(在之前,渲染第二个摄像机时我们会清除所有缓冲)。

	void Setup () {context.SetupCameraProperties(camera);CameraClearFlags flags = camera.clearFlags;buffer.ClearRenderTarget(true, true, Color.clear);buffer.BeginSample(SampleName);ExecuteBuffer();}

CameraClearFlags枚举定义了Skybox,Color,Depth, andNothing四个值,除了 Nothing,其他情况都需要清理深度缓冲区。观看源代码还有一个SolidColor

我们只需要在标记设置为Color时清除颜色缓冲区,因为在Skybox中,我们必然都会替换之前所有的颜色数据。

如果想要清除为纯色,我们就必须使用摄像机的背景色。但是因为我们在线性空间进行渲染,我们必须把颜色转换为线性空间,所以我们使用camera.backgroundColor.linear。在其他情况下,颜色并不重要,所以我们可以用Color.clear。

SecondaryCamera的清理标记定义如何组合两个摄影机的渲染。在skybox或color的情况下,先前的结果将被完全替换。如果仅清除深度,则辅助摄影机将正常渲染,但不会绘制天空盒,因此以前的结果显示为背景。当什么都没有清除时,深度缓冲区将保留,因此未照亮的对象最终将遮挡无效对象,就像它们是由同一台摄像机绘制的一样。但是,前一个摄像机绘制的透明对象没有深度信息,因此像 skybox之前所做的那样被绘制。

通过调整相机的 Viewport Rect ,也可以将渲染区域缩小到整个渲染目标的一小部分。其余渲染目标保持不受影响。在这种情况下,将使用Hidden / InternalClear着色器进行清除。模板缓冲区用于将渲染限制在视口区域。这里将第二个相机渲染到右半屏幕。

请注意,如果每帧渲染一台以上的摄像机就必须同时进行多次剔除,设置,分类等操作这是很耗的。一种有效的方式是让每一个摄像机都有自己的渲染视角。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/312907.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

libftdi1学习笔记 5 - SPI Nor Flash

目录 1. 初始化 2. CS控制例子 3. 读ID 3.1 制造商 3.2 容量大小 3.3 设置IO类型 3.3.1 setQSPIWinbond 3.3.2 setQSPIMxic 3.3.3 setQSPIMicrochip 3.3.4 setQSPIMicron 4. 写保护 5. 等待空闲 6. 擦除扇区 7. 页编程 8. 页读 9. 写 10. 读 11. 验证 基于M…

Postman之版本信息查看

Postman之版本信息查看 一、为何需要查看版本信息&#xff1f;二、查看Postman的版本信息的步骤 一、为何需要查看版本信息&#xff1f; 不同的版本之间可能存在功能和界面的差异。 二、查看Postman的版本信息的步骤 1、打开 Postman 2、打开设置项 点击页面右上角的 “Set…

Xshell无法输入命令输入命令卡顿

Xshell是一款功能强大的终端模拟软件&#xff0c;可以让用户通过SSH、Telnet、Rlogin、SFTP等协议远程连接到Linux、Unix、Windows等服务器。然而&#xff0c;在使用Xshell的过程中&#xff0c;我们可能会遇到一些问题。比如输入不了命令&#xff0c;或者输入命令很卡。这些问题…

content-type对数据采集的影响,猿人学58题

在拿猿人学网站 https://www.python-spider.com/api/challenge58 练习的时候发现请求头中少了 content-type之后结果全部不对了 当我设置headers如下时 headers {# accept: application/json, text/javascript, */*; q0.01,content-type: application/x-www-form-urlencode…

445. 两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数字都不会以零开头。 示例1&#xff1a; 输入&#xff1a;l1 [7,2,4,3], l2 [5,6,4]…

2024腾讯一道笔试题--大小写字母移动

题目&#x1f357; 有一个字符数组,其中只有大写字母和小写字母,将小写字母移到前面, 大写字符移到后面,保持小写字母本身的顺序不变,大写字母本身的顺序不变, 注意,不要分配新的数组.(如:wCelOlME,变为wellCOME). 思路分析&#x1f357; 类似于冒泡排序&#xff0c;两两比较…

基于SpringBoot+Vue的疾病防控系统设计与实现(源码+文档+包运行)

一.系统概述 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对疾病防控信息管理的提升&a…

snort安装和使用

win10 x64安装snort 下载snort https://www.snort.org/downloads 下载npcap 0.9984版本 https://npcap.com/dist/ 安装npcap ,snort 安装成功 如果使用npcap版本不对或者使用winpcap会出现错误,winpcap不在win10运行。 snort.conf #-----------------------------------…

多ip证书实现多个ip地址https加密

在互联网快速发展的现在&#xff0c;很多用户会使用由正规数字证书颁发机构颁发的数字证书&#xff0c;其中IP数字证书就是只有公网IP地址网站的用户用来维护网站安全的手段。由于域名网站比较方便记忆&#xff0c;只有公网IP地址的网站是很少的&#xff0c;相应的IP数字证书产…

Python 入门指南(一)

原文&#xff1a;zh.annas-archive.org/md5/97bc15629f1b51a0671040c56db61b92 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 前言 这个学习路径帮助你在 Python 的世界中感到舒适。它从对 Python 的全面和实用的介绍开始。你将很快开始在学习路径的第一部分编写程序…

5. Mysql的binlog介绍

参考&#xff1a;InnoDB学习&#xff08;三&#xff09;之BinLog 1. BinLog介绍 BinLog又称为二进制日志&#xff0c;是MySQL服务层的数据日志&#xff0c;MySQL所有的存储引擎都支持BinLog。 BinLog记录了MySQL中的数据更新和可能导致数据更新的事件&#xff0c;可以用于主从…

逆向案例二十七——某笔网登录接口非对称加密算法RSA,涉及全扣代码,浏览器断点调试,和补环境

网址&#xff1a;aHR0cHM6Ly93d3cuZmVuYmkuY29tL3BhZ2UvaG9tZQ 点击账号密码登录&#xff0c;找到登陆的包&#xff0c;发现password进行了加密。 顿时&#xff0c;老生常谈&#xff0c;开始搜索&#xff0c;找到最有嫌疑的加密代码。进行搜索&#xff0c;进入js文件后&#x…

HarmonyOS开发实例:【任务延时调度】

介绍 本示例使用[ohos.WorkSchedulerExtensionAbility] 、[ohos.net.http]、[ohos.notification] 、[ohos.bundle]、[ohos.fileio] 等接口&#xff0c;实现了设置后台任务、下载更新包 、保存更新包、发送通知 、安装更新包实现升级的功能。 效果预览 使用说明 安装本应用之…

OpenHarmony南向开发案例【智慧中控面板(基于 Bearpi-Micro)】

1 开发环境搭建 【从0开始搭建开发环境】【快速搭建开发环境】 参考鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或复制转到。 【注意】&#xff1a;快速上手教程第六步出拉取代码时需要修改代码仓库地址 在MobaXterm中输入…

vue3 vueUse 连接蓝牙

目录 vueuse安装&#xff1a; useBluetooth: 调用蓝牙API 扫描周期设备 选择设备配对 连接成功 vue3的网页项目连接电脑或者手机上的蓝牙设备&#xff0c;使用vueUse库&#xff0c;可以快速检查连接蓝牙设备。 vueUse库使用参考&#xff1a; VueUse工具库 常用api-CSDN…

Re65:读论文 GPT-3 Language Models are Few-Shot Learners

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文全名&#xff1a;Language Models are Few-Shot Learners ArXiv网址&#xff1a;https://arxiv.org/abs/2005.14165 2020 NeurIPS&#xff1a;https://papers.nips.cc/paper/2020/hash/1457c0d6bfcb49674…

组织机构代码是哪几位?营业执照怎么看组织机构代码?

组织机构代码是哪几位? 组织机构代码通常指的是组织机构代码证上的一组特定数字&#xff0c;它用于唯一标识一个组织或机构。在中国&#xff0c;组织机构代码由9位数字组成&#xff0c;前8位是本体代码&#xff0c;最后1位是校验码。这组代码是按照国家有关标准编制的&#x…

自定义鼠标软件 SteerMouse最新完整激活版

SteerMouse是一款实用的Mac OS X系统辅助工具&#xff0c;可以帮助用户自定义鼠标和触控板的设置&#xff0c;提高使用效率。它提供了多种功能&#xff0c;如自定义按钮、滚轮和光标速度&#xff0c;以及调整灵敏度等&#xff0c;使用户能够根据自己的需求和习惯进行优化。 Ste…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第四套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第四套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;仅供参考&#xff09;&#xff08;共九套&#xff0c;每套四十个选择题&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadida…

vue2知识点1 ———— (vue指令,vue的响应式基础)

vue2的知识点&#xff0c;更多前端知识在主页&#xff0c;还有其他知识会持续更新 Vue 指令 Vue指令是Vue.js中的一个重要概念&#xff0c;用于向DOM元素添加特定行为或功能。Vue指令以v-开头&#xff0c;例如v-bind、v-if、v-for等。 v-bind 动态绑定属性 用法&#xff1a…