【Unity URP】Rendering Debugger和可视化MipMap方案

news2024/11/25 22:34:48

写在前面

最近开始学习Unity性能优化,是结合了《Unity游戏优化》这本书和教程《Unity性能优化》第叁节——静态资源优化(3)——纹理的基础概念一起学习。在学习纹理优化部分时候遇到了问题,固定管线下Unity的Scene窗口有一个可视化Mipmap的渲染模式:

而这批Miscellaneous模式的选项在URP下相同位置没了:

又比较需要这个便捷的查看方法!于是搜一下想看看有没有出一些插件之类的,突然搜到了大概20年也有小伙伴提出这个问题:

Missing Scene view Draw Modes (Mipmaps, Overdraw, etc.) - Unity Forum

底下Unity技术人员回复了,大概意思就是会加入Rendering Debugger来实现之前固定管线下的D

rawMode的一些功能: 

于是就发现了Rnedering Debugger功能,What's new in URP 12 (Unity 2021.2) | Universal RP | 12.0.0

之前URP下做东西的时候完全没有注意和使用过!一起来简单看看:

Rendering Debugger

非常方便了!比如Material的一些查看,可以单独看albedo的效果:

比如OverDraw:

曾经固定管线下的级联阴影、Alpha通道等的一键预览都有了!但是还是没有Mipmap。

其他版本的URP该怎么办?

小插曲,在Rendering Debugger没出来前,这位大佬Scene View Debug Modes in the Unity URP — John Austin甚至自己做了个插件:

虽然后续URP已经提供了rendering debugger,但是这个把shader添加进debug里的整个框架我们是可以参考过来的。 

讨论Build-in下Scene视图的Mipmaps

其实Mipmap可视化已经有人总结过了:Re0-TA成长笔记 01关于Mipmap问题

而且asset store有免费的类似插件:Colored Mipmap Texture - Visualized Checker

还有其他的方法,要么方法我看不太懂,,要么颜色太多我感觉也不需要那么多颜色,只是想把Mipmap视图作为优化纹理的小工具。我希望在URP下也能实现固定管线那种简单的蓝/红色的Mipmap显示效果,实现方法尽量的简单一点,固定管线下就这样简单:

场景很简陋(之前学习入门精要的build-in项目~),也算体现了大概吧,当纹理大小刚刚好的时候展示的就是纹理的样子,纹理太小了精度不够就会是蓝色,纹理太大精度过大就会是红色!

因为比较好奇,build-in下的Scene视图的Mipmap到底是怎么运行的?物体shader里的贴图一定不只有一张主纹理,他的法线纹理、金属度等纹理都会参与Mipmap,这个大小是综合所有贴图判断的吗?还是只关注主要的albedo贴图?

我们测试一下,拿之前学习法线映射的shader为例,shader有两张纹理,albedo和normal,大小均为2048,显然都过大了,所以Mipmap视图下整体是红色:

现在把albedo贴图改为32,变成蓝色了!:

如果我们只改normal的大小为32,albedo那张不变呢?没有变化!还是红色:

这就初步说明,固定管线下这个Mipmap level判断依据,是根据shader中的MainTex(主纹理)来判断的,而且物体shader的SubShader的RenderType一定要有,才能参与这个Scene视图下Mipmap的红蓝判断:

还需要确定一点,就是这个Mipmap渲染的shader到底怎么获取纹理的?我们再测试一下,如果shader里如果主纹理命名不是默认的_MainTex,而是_BaseTex的话:

场景中之前的那个物体又变蓝了!

好了,到这里我们可以初步推断:

Build-in管线下,Scene View里的Mipmaps可视化,只针对shader主纹理命名为_MainTex的物体有效,且只关注_MainTex一张贴图的大小是否合适,其余的法线纹理等其他贴图不受关注

探讨URP下Mipmap可视化方案

初步猜测:如果我只想要简单的红蓝检测效果,且实践方法尽量简单,我必须要在URP下能够访问所有项目的主纹理,然后单独做一个ViewDebug_Mipmaps的shader,挂在View视图窗口。

紧接着,找资料突然就看到了11年的时候就有人提出了一种可视化Mipmap方案:

A way to visualize mip levels · Aras' website (aras-p.info)

有意思的是在查看Build-in的Debug.hlsl文件时,发现Unity的可视化方案也是参考了之前的那个文章(Unity的Debug.hlsl文件):

上面那个人的主要shader如下:

struct v2f {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
    float2 mipuv : TEXCOORD1;
};
float2 mainTextureSize;
v2f vert (float4 vertex : POSITION, float2 uv : TEXCOORD0)
{
    v2f o;
    o.pos = mul (matrix_mvp, vertex);
    o.uv = uv;
    o.mipuv = uv * mainTextureSize / 8.0;
    return o;
}
half4 frag (v2f i) : COLOR0
{
    half4 col = tex2D (mainTexture, i.uv);
    half4 mip = tex2D (mipColorsTexture, i.mipuv);
    half4 res;
    res.rgb = lerp (col.rgb, mip.rgb, mip.a);
    res.a = col.a;
    return res;    
}

OHHHH,他的实现思路差不多就是我的意思!shader里的mainTextureSize,实际上就是URP下shader里我们能默认获取得到的BaseMap_TextureSize,其余的操作只是为了能根据距离动态判断纹理大小是否合适,根据判断结果给上红蓝色。

那我们就开始吧!首先是确定,怎么获取纹理?想起来了,可以从URP下自带的Rendering Debugger入手:

看看Rendering Debugger的逻辑

简单一点,我们打开URP的文件夹,搜索Debug

成功定位到Debugging3d.hlsl:

Debugging3D.hlsl

具体内容就不一句一句来了,单独挑一个,Material的:

你会发现!原来Debugger的逻辑并不是重新自己有一套shader,而是直接拿SurfaceData的东西用,输出想要的项就行了。

SurfaceData

之前扒URP的PBR Shader的时候就已经见过他了,SurfaceData是在SurfaceData.hlsl定义的结构体:

然后在LitInput.hlsl中定义了一个InitializeStandardLitSurfaceData()函数,去初始化SurfaceData:

尝试输出Surface.albedo

刚好我作为联系我有想要优化的项目,那就直接在项目中写个shader看看能不能成功提取SurfaceData.albedo吧!写个shader:

Shader "Debug/Debug Albedo"
{
    SubShader
    {
        Tags{"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}

        Pass
        {
            HLSLPROGRAM
            
            #pragma vertex LitPassVertex
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/Shaders/LitForwardPass.hlsl"

            float4 frag(Varyings input) : SV_TARGET {

                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

                #if defined(_PARALLAXMAP)
                #if defined(REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR)
                    half3 viewDirTS = input.viewDirTS;
                #else
                    half3 viewDirTS = GetViewDirectionTangentSpace(input.tangentWS, input.normalWS, input.viewDirWS);
                #endif
                    ApplyPerPixelDisplacement(viewDirTS, input.uv);
                #endif

                SurfaceData surfaceData;
                InitializeStandardLitSurfaceData(input.uv, surfaceData);
                
                return float4(surfaceData.albedo, 1);
                
            }
          
            ENDHLSL
        }
    }

}

参考上面自己Debug的框架,给他做成开关放在Scene下的DrawMode里:

结果,,,Scene是全黑的,并没有单独展示Albedo:

哪里出错了?想起来,不会是因为BaseMap命名和采样的问题吧。为了测试我的想法是否正确,场景中拖个正方体,给他一个简单的shader,shader严格按照BaseMap来:

同样的DrawMode选择Albedo,居然出现了!

果然,验证了我的猜想。检查一下项目里的shader,发现shader都是拿ASE实现的,,,转化的命名什么的都有点混乱,,,

再拿个之前搭的模型为例吧:

同样的Shader:

成功了!调出了albedo,啊,可视化的途径我们算是找到了,接下来就是实现了!

URP下实现Mipmap可视化

给texture每个mip层赋值

这其实是最关键的一步——我们需要有图可采样成颜色。

Tutorial: Creating and modifying custom mipmaps - Texture Tools - NVIDIA Developer Forums

我尝试过Unity创建纹理,也尝试过PS、GIMP生成dds图,但是这俩好像只能打开dds却不能编辑每一个Mip层的颜色!!!

于是另寻他路:dds的目的是给每个mipLevel给一个颜色值,那我们直接获取mipmap的level,根据这个level值输出对应的颜色不就好了,也就是shader里实现这行采样代码:

half4 mip = tex2D (mipColorsTexture, i.mipuv);

这里注意一下,tex2D的本质是什么?这是Unity提供的一个采样器,输入需要采样的纹理及对应的uv值,会进行采样,并根据纹理的设置生成mipmap。这里要关注另一个采样函数:tex2Dlod,这个是可以根据传入uv的.w分量信息指定mipmap层的。随便搜一下tex2Dlod的原理,就能明白了,比如这篇文章:MipMap的LOD实现原理 - 知乎里写的:

float mipmapLevel(float2 uv, float2 textureSize) 
{    
 float dx = ddx(uv * textureSize.x);    
 float dy = ddy(uv * textureSize.y);   
 float d = max(dot(dx, dx), dot(dy, dy));
 return 0.5 * log2(d);//0.5是技巧,本来是d的平方。
} 

我直接在fragment shader里计算:

// 直接自己计算lod,参考tex2DLod
                float2 mipUV = o.uv * o.mainTextureSize/ 8; // 参考文章的方案
                float dx = ddx(mipUV); // 
                float dy = ddy(mipUV);
                float px = 32 * dx;
                float py = 32 * dy;
                float lod = 0.5 * log2(max(dot(px, px), dot(py, py)));

再写个函数,根据传入的lod值lerp我的颜色,颜色取值来自上面的那篇文章:

// 根据当前纹理的Mip层值返回给定颜色
            float4 GetCurMipColorByManualColor(float mipLevel)
            {

                if(mipLevel==0) // 纹理压根没有开启mipmap
                {
                    return real4(0.0,0.0,1.0,1); // 给.a为0,即baseMap
                }
                else
                {
                    if(mipLevel < 1 ) // 代表着纹理太小了,给个蓝色
                    {
                        return lerp(real4(0.0,0.0,1.0,1),real4(0.0,0.0,1.0,0.8),mipLevel);
                    }
                    else if (mipLevel <2)
                    {
                        return lerp(real4(0.0,0.0,1.0,0.8),real4(1,1,1,0), mipLevel-1);
                    }
                    else if(mipLevel <3) // mip的正正好,于是.a值给0,意味着纹理此时恰到好处
                    {
                        return lerp(real4(1,1,1,0),real4(1.0,0.7,0.0,0.2),mipLevel-2);
                    }
                    else if(mipLevel <4)
                    {
                        return lerp(real4(1.0,0.7,0.0,0.2),real4(1.0,0.3,0.0,0.6),mipLevel-3);
                    }
                    else if(mipLevel <5)  // mip太多了吧,意味着纹理太大了!因此给个更红的颜色
                    {
                        return lerp(real4(1.0,0.3,0.0,0.6),real4(1.0,0.0,0.0,0.8),mipLevel-4);
                    }
                    else
                    {
                        return real4(1.0,0.0,0.0,0.8); // mip了超大,直接给正红色,.a直接点满,完全为debug的颜色
                    }
                }
            }

接着fragment shader里:

float3 baseColor = surfaceData.albedo;
                float4 debugColor = GetCurMipColorByManualColor(lod);
                float4 res;
                
                res.rgb =lerp(baseColor.rgb, debugColor.rgb, debugColor.a); //由debugColor.a控制插值
                res.a = 1;
                return res;

就是说,到这里就已经实现了!具体怎么把他搬进Scene视图下,前面列举了一个URP下别人实现Albedo可视化的框架,我是直接拿过来用了,他给了源码,所以脚本这里就不过多的介绍。

效果展示

放上一个跟固定管线里的相同模型、贴图的场景的mipmap可视化对比,左边是固定管线下,右边是我实现的:

可以看出在显示上是有一定偏差的,因为Unity内部到底是怎么做mipmap可视化,颜色如何规定的?颜色和mip层的关系是怎样的?没在源码中找到太多的依据。

但基本上算是实现了!虽然shader用了很多个if,但是只是一个debug环节,不用太考虑效率问题。总的来说这个方案学习过程中自己使用起来还是足够的!

文章写的很潦草,涉及到的内容太扩散了,其实也是我实现过程中的心路历程,希望看到这里的你能看懂!!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT实现数据结构转换

数据结构转换 在应用系统开发和维护中&#xff0c;经常会有配置数据或客户数据需要在不同的序列化结构中相互转换的需求。不同编程语言之前&#xff0c;对数据结构的偏好也不一样&#xff0c;比如 JavaScript 一般使用 JSON、Java 一般使用 XML、Ruby 一般使用 YAML、Golang 一…

搞懂 API , API 这些特点要记住

API 是现代软件开发和应用程序中的必要组成部分&#xff0c;它为企业和开发者提供了极大的便利和工作效率。不过&#xff0c;API 也有其不足之处。下面将在这篇文章中详细探讨 API 的优点和缺点。 优点&#xff1a; 简化数据访问和交互 API 消除了传统的数据集成方法&#x…

使用chatGPT开发获取格点天气数据

1. 格点天气 1.1. 格点天气 以经纬度为基准的全球高精度、公里级、格点化天气预报产品&#xff0c;包括任意经纬度的实时天气和天气预报。其中&#xff0c;任意坐标的高精度天气&#xff0c;精确到3-5公里范围&#xff0c;包括&#xff1a;温度、湿度、大气压、天气状况、风力…

nvidia-smi命令解析

桌面端 服务器端 Fan:风扇转速&#xff08;0%-100%&#xff09;&#xff0c;N/A表示没有风扇 Temp&#xff1a;GPU温度&#xff08;GPU温度过高会导致GPU频率下降&#xff09; Perf&#xff1a;性能状态&#xff0c;从P0&#xff08;最大性能&#xff09;到P12&#xff08;最…

zookeeper 安装下载与集群

一、单机部署 1、安装包下载 https://archive.apache.org/dist/zookeeper 2、上传并解压 tar -zvxf zookeeper-3.4.14.tar.gz3、配置环境变量 my_env.sh是自己创建的环境变量文件&#xff0c;你也可以自己创建 vim /etc/profile.d/my_env.sh#ZOOKEEPER_HOME export ZOOKE…

什么是分布式任务调度?怎样实现任务调度

通常任务调度的程序是集成在应用中的&#xff0c;比如&#xff1a;优惠卷服务中包括了定时发放优惠卷的的调度程序&#xff0c;结算服务中包括了定期生成报表的任务调度程序&#xff0c;由于采用分布式架构&#xff0c;一个服务往往会部署多个冗余实例来运行我们的业务&#xf…

1.3 防火墙通过TELNET登录设备

防火墙通过TELNET登录设备 需求&#xff1a;使远程管理员能够通过telnet方式登录到设备上进行管理 序号任务任务说明备注1物理连接略2登录设备略3配置设备telnet设备默认不支持telnet功能&#xff0c;必须开启telnet功能&#xff0c;以及用于远程登录设备的账号密码等。重点4测…

【hello Linux】进程间通信——共享内存

目录 前言&#xff1a; 1. System V共享内存 1. 共享内存的理解 2. 共享内存的使用步骤 3. 共享内存的使用 1. 共享内存的创建 查看共享内存 2. 共享内存的释放 3. 共享内存的挂接 4. 共享内存的去挂接 4. 共享内存的使用示例 1. 两进程挂接与去挂接演示&#xff1a; 2. 两进程…

基于eNSP的IPv4加IPv6的企业/校园网络规划设计(综合实验/大作业)

作者&#xff1a;BSXY_19计科_陈永跃 BSXY_信息学院_名片v位于结尾处 注&#xff1a;未经允许禁止转发任何内容 基于eNSP的IPv4加IPv6的企业/校园网络规划设计_综合实验/大作业 前言及技术/资源下载说明&#xff08; **未经允许禁止转发任何内容** &#xff09;一、设计topo图与…

Postgresql逻辑优化学习

张树杰优化器原理学习 0 用例 drop table student; create table student(sno int primary key, sname varchar(10), ssex int); insert into student values(1, stu1, 0); insert into student values(2, stu2, 1); insert into student values(3, stu3, 1); insert into stu…

SPSS岭回归报错问题 第 8 列中的 错误号 34+乱码问题

1首先第一个问题&#xff0c;先找到Ridge Regression.sps文件 注意各国语言都有这个文件&#xff0c;选择English下的 得到位置&#xff0c;一般是安装路径\Samples\English\Ridge Regression.sps 仍然报错&#xff0c;将第二行变成大写&#xff1a;RIDGEREG ENTER&#xff0…

笔记本电脑没有声音了怎么恢复

笔记本电脑 在使用的过程中&#xff0c;突然没有声音的话&#xff0c;对于人们来说会很麻烦。那么笔记本电脑没有声音了怎么恢复呢?下面小编为大家整理了笔记本电脑没有声音的恢复方法&#xff0c;一起来看看吧。 方法/步骤&#xff1a; 方法一&#xff1a;网络适配器检查音频…

物联网工程有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是一些物联网工程领域的SCI期刊推荐&#xff1a; IEEE Internet of Things Journal&#xff1a; 该期刊由IEEE出版&#xff0c;致力于物联网技术领域的研究&#xff0c;包括物联网的基础理论、通信、算法、应用、系统等方面。 Sensors&#xff1a; 该期刊由MDPI出版&…

基于el-input的数字范围输入框

数字范围组件 在做筛选时可能会出现数字范围的筛选&#xff0c;例如&#xff1a;价格、面积&#xff0c;但是elementUI本身没有自带的数字范围组件&#xff0c;于是进行了简单的封装&#xff0c;不足可自行进行优化 满足功能&#xff1a; 最小值与最大值的相关约束&#xff0…

C++默认成员函数 日期类运算符重载

赋值重载 赋值重载&#xff0c;首先我们先说一个运算符重载&#xff0c;什么是运算符重载呢&#xff1f; 当我们有一个日期类的话&#xff0c;我们想要对&#xff0c; 一个日期类进行比较&#xff0c;那么我们怎么比较呢&#xff1f; 我们是不是先得比较年的大小&#xff0c;…

day6 socket套接字及TCP的实现框架

socket套接字 Berkeley UNIX 操作系统定义了一种API它又称为套接字接口&#xff08;socket interface); socket作用&#xff1a; socket常见API介绍 /*创建套接字*/ int socket(int domain, int type, int protocol); /*绑定通信结构体*/ int bind(int sockfd, const, struc…

【数据库】MVCC原理详解

文章目录 前言1. 相关数据库知识点回顾1.1 什么是数据库事务&#xff0c;为什么要有事务1.2 事务包括哪几个特性&#xff1f;1.3 事务并发存在的问题1.3.1 脏读1.3.2 不可重复读1.3.3 幻读 1.4 四大隔离级别1.4.1 读未提交1.4.2 读已提交1.4 3 可重复读1.4.4 串行化1.4.5 四大隔…

chatgpt模拟机器人软件开发

ChatGPT的参数取决于具体的模型和实现方式&#xff0c;但以下是一些常见的ChatGPT参数&#xff1a; 模型深度&#xff1a;指模型中神经网络的层数。通常情况下&#xff0c;层数越多&#xff0c;模型的表达能力也就越强。 隐藏单元大小&#xff1a;指在模型中每个隐藏层…

局域网 - CSMA/CD(载波侦听多路访问 / 冲突检测)

文章目录 1 概述1.1 局域网的拓扑结构 2 CSMA/CD2.1 三种监听算法2.2 冲突检测原理2.3 二进制指数后退算法 3 扩展3.1 网工软考真题 1 概述 1.1 局域网的拓扑结构 2 CSMA/CD CSMA/CD&#xff1a;Carrier Sense Multiple Access/ Collision Detection&#xff0c;载波侦听多路…

从功能测试转型测试开发,薪资涨了20K,1000字讲述转型必经之路...

身处职场之中&#xff0c;犹如逆水行舟不进则退&#xff0c;想要不被后浪拍死在沙滩上&#xff0c;就要不断学习新知识&#xff0c;接受新事物。 要得到更好的发展&#xff0c;就要紧跟发展趋势&#xff0c;不断转型才能保持竞争力&#xff0c;在职场中占有一席之地。 转型不…