SRP 实现 Cook-Torrance BRDF

写的很乱!

BRDF(Bidirectional Reflectance Distribution Function)全称双向反射分布函数。辐射量单位非常多,这里为方便直观理解,会用非常不严谨的光照强度来解释说明。

BRDF光照模型,上反射率公式

\int_{\Omega }^{}f(p,w_{i},w_{o})L_{i}(p,w_{i})cos\theta dw_{i}

计算的是在法线所在半球上的所有入射光线,在出射方向光强总和,公式有俩个部分。

f(p,w_{i},w_{o})

即BRDF,从特定的入射方向到出射方向,在某个表面上,光强的衰减比率。

L_{i}(p,w_{i})cos \theta _{i}

有了比率,还需要知道在物体表面接收到的某个方向上的光强,所以前半部分是光线沿入射方向到p点发射的光线强度,后半部分用表面与入射方向的夹角计算实际接收到的光线强度(因为这里虽然是一个点,但同时也需要当做一个极小的平面区域处理)。

关于几何函数

为什么GXX有俩个?只考虑一次反射能成功的,其实就是简单的认为入射方向能不被遮挡的光线比例 × 出射方向能不被遮挡的光线比例 = 整条光路上不会被遮挡的光线比例。

Cook-Torrance BRDF

🔻如果在渲染结果中发现了类似以下的问题或变,极大概率是法线没有在片元着色器中标准化。

SRP中实现的Cook-Torrance BRDF效果(无法线贴图,未进行gamma调整):

增加支持多光源

https://zhuanlan.zhihu.com/p/163360207

关于点光源获取位置和平行光获取方向。

获取位置用VisibleLight.localToWorldMatrix.GetColumn(3);

获取方向用VisibleLight.localToWorldMatrix.GetColumn(2);

因为localToWorldMatrix是光源的模型变换矩阵M,获取点光源的位置即mul(M, float4 (0, 0, 0, 1)),即localToWorldMatrix的最后一列。同理,平行光方向朝向局部坐标z轴,mul(M, float4 (0, 0, 1, 0))故为第三列。

有很多免费的材质素材:Hundreds of 3D Texture Downloads - Free PBR Materials

这部分是没什么难度的,将相关变量设置为数组即可。

🔻但问题就出现在这,在Unity 2022.3.45f1c1中,如果先实现了.SetGlobalVector然后修改成.SetGlobalVectorArray,那么恭喜你完犊子了。修改后传入GPU的数据还是按.SetGlobalVector处理的,Dubug半天你会发现GPU就是拿不到完整的数组。

解决方法:Unity!重启!😎

🔻如果遇到CullingResults.lightIndexCount在某些视角下会返回非常奇怪的(错误)值的情况,例如明明只有2个可见光源,但返回4个。用CullingResults.visibleLights.Length来获取可见光源数组的个数,而不是CullingResults.lightIndexCount即可。

🔻Shader error in 'Custom/BRDF': Unexpected directive '';这种错多半是用了中文分号或者其他的全半角问题。

支持法线贴图,如果想要在切线空间引用法线贴图后再转到世界坐标系下,需要用TBN矩阵的逆矩阵实现。具体见:TBN矩阵的使用

🔻应用贴图实现的BRDF效果很抽象,我以为是TNB出问题了(甚至怀疑unity默认切线有问题,还从blender中导了个正确的球模型过来),整了很久发现是采样法线贴图出错了,虽然各种设置了Unity项目是线性空间,但纹理这一块疑似过于独立了,需要在贴图中应用为Normal Map才能确保纹理采样在线性空间下。

那么有朋友就要问了,unity!unity!我用Default但不勾选sRGB不就可以了吗?unity答:不行。

为什么呢?因为根据TNB矩阵的组织方式,切线空间中垂直表面的轴实际上是x轴而不是z轴,如果想直接使用原始法线贴图,需要调整颜色通道顺序。

如果只用线性空间采样,输出采样结果经过映射后其实是大红色的,即(1.0,0.0,0.0),怎么回事呢?

 映射指颜色范围0~1到法线范围-1~1,而映射前是粉红色的。据说解包出的法线纹理也是粉红色的,和这个有关系吗?

法线贴图And图像压缩

贴图设置为Normal Map就可以了吗?换个法线变换明显材质试试看看😕。

输出法线,很明显少了一部分。

怎么回事呢,采访一下纹理压缩格式。

DXT5|BC3:“我不到啊。”

Unity:“他说(DXT5|BC3)他的alpha和green通道最好用,我就按他说的来了。”

言归正传,BC3是DXT5在DirectX 10中的别称,以下都以将以BC3称呼,BC是怎么压缩图像的这里就不过多解释了,直接看BC3压缩后的格式。

BC3 格式使用 5:6:5 颜色(5 位红色、6 位绿色、5 位蓝色)存储颜色数据,使用一个字节存储 alpha 数据。 更多的位数意味着更大的颜色深度,即更好的颜色表现。对法线来说,其归一化后长度为1,知道x,y即可计算z,所以当选择Texture为NormalMap时,Unity会自动处理成alpha和green通道以帮助我们得到最佳的图像效果。

在压缩大多数 RGBA 纹理时最好使用此格式。对于 RGB(无 Alpha)纹理,DXT1 更适合。当针对 DX11 类硬件(新版 PC、PS4、XboxOne)时,使用 BC7 可能很有用,因为压缩品质通常更好。

拓展一下,Unity中RGBA默认用BC3或BC7,BC7有八种模式,但RGBA支持模式下位数最多(之一)的还是alpha通道,颜色三通道则相同,所以用alpha加green通道也是最优解。

虽然法线贴图是RGB图,但还是用了RGBA的处理方式。

此外,Unity法线贴图也支持用BC5进行压缩,不过对应的采样代码就要修改了,反正怎么压缩怎么采样即可。

所以如果想得到正确的法线贴图采样结果,就需要手动提取alpha和green通道作为yz,再求解出x,这里的对应关系很重要。

通过UV检查图确定UV坐标原点为面左下角,然后只输出法线贴图上采样green通道的颜色。

可以确定green通道对应副切线,输出alpha通道。

可知alpha通道对应切线,那么法线方向的值就是要算的了,计算出法线方向输出值输出结果如下。

说明前面的推测是正确的,又由于TNB矩阵的组织方式是world normal,world tangent,world bitangent,所以alpha和green通道作为yz,再求解出最后一个值作为x。

float3x3 TNB = float3x3(normalize(v2p.normal), normalize(v2p.tangent), normalize(v2p.bitangent));

处理一下就能够将原法线贴图绘制出来,右图颜色更深是由于右图在线性颜色空间下+显示屏Gamma2.2调整,左图在线性空间下+Unity自动Gamma0.45调整+显示屏Gamma2.2调整。

修正后效果:

🔻Gamma问题,光照对了但球的颜色很淡很淡。原因是Color Space选择Linear时,Unity会自动对渲染窗口做一次Gamma0.45。而我参考LearnOpen GL在Shader中也实现了一次Gamma 0.45,所以结果是两次Gamma0.45,加上显示器的一次Gamma2.2,最终输出颜色还是Gamma 0.45,所以会感觉很淡(如果Color Space选Gamma,就需要手动校正)。

参考:Gamma 和 Linear Space的设置 Unity

然后终终终终于实现成功了“网图”的效果!

Unity中显示法线,切线,副切线(附代码)

先前为了查看切线是否有问题,写了个非常简单的脚本显示各顶点的切线坐标轴(使用前要reset对象的transform),结果显示模型非常健康。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ShowNormalsAndTangents : MonoBehaviour
{[SerializeField]float normalLength = 0.03f;// Update is called once per framevoid OnDrawGizmosSelected(){Mesh mesh = GetComponent<MeshFilter>().sharedMesh;Vector3[] v = mesh.vertices;Vector3[] n = mesh.normals;Vector4[] t = mesh.tangents;for (int i = 0; i < v.Length; i++) {Gizmos.color = Color.red;Gizmos.DrawRay(v[i], n[i] * normalLength);Gizmos.color = Color.green;Gizmos.DrawRay(v[i], new Vector3(t[i].x, t[i].y, t[i].z) * normalLength);Vector3 bitangent = Vector3.Normalize(Vector3.Cross(n[i], new Vector3(t[i].x, t[i].y, t[i].z)) * t[i].w);Gizmos.color = Color.blue;Gizmos.DrawRay(v[i], bitangent * normalLength);}}
}

Unity中显示法线,切线,副切线(几何着色器实现代码)

这里再补充一个用几何着色器实现的法线,切线和副切线显示。完全重叠的线只会显示一条,所以有可能会看到缺少了某条线,其实是被覆盖掉了。

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Custom/ShowNormals"
{Properties{_LineLength("LineLength", float) = 0.03_NormalLineColor("NormalLineColor", Color) = (1.0, 0.0, 0.0, 1.0)_TangentLineColor("TangentLineColor", Color) = (0.0, 1.0, 0.0, 1.0)_BitangentLineColor("BitangentLineColor", Color) = (0.0, 0.0, 1.0, 1.0)}SubShader{Pass{HLSLPROGRAM#pragma vertex VS_Main#pragma fragment FS_Main#pragma geometry GS_Mainfloat4x4 unity_MatrixVP;float4x4 unity_ObjectToWorld;float4x4 unity_WorldToObject;float _LineLength;float4 _NormalLineColor;float4 _TangentLineColor;float4 _BitangentLineColor;struct VS_INPUT{float3 m_pos:POSITION;float3 normal:NORMAL;float4 tangent:TANGENT;};struct GS_INPUT{float4 pos:POSITION;float3 w_normal:NORMAL;float3 w_tangent:TANGENT;float3 w_bitangent:TEXCOORD0;};struct FS_INPUT{float4 pos:POSITION;float4 lineColor:TEXCOORD0;};//step1GS_INPUT VS_Main(VS_INPUT input){GS_INPUT output;output.pos = mul(unity_ObjectToWorld, float4(input.m_pos, 1.0));output.w_normal = mul(transpose((float3x3)unity_WorldToObject), input.normal);output.w_tangent = mul((float3x3)unity_ObjectToWorld, input.tangent.xyz);output.w_bitangent = cross(output.w_normal, output.w_tangent) * input.tangent.w;return output;}[maxvertexcount(18)] //GS单次调用可以输出的最大顶点数量,这里每个顶点会变成俩顶点所以是3*2;void GS_Main(triangle GS_INPUT gsIn[3], inout LineStream<FS_INPUT> triStream){for(uint i = 0; i < 3; ++i){FS_INPUT pIn;pIn.pos = mul(unity_MatrixVP, gsIn[i].pos);FS_INPUT pIn1;float4 pos= gsIn[i].pos + float4(normalize(gsIn[i].w_normal), 0.0) * _LineLength;pIn1.pos = mul(unity_MatrixVP, pos);pIn.lineColor = _NormalLineColor;pIn1.lineColor = _NormalLineColor;triStream.Append(pIn);triStream.Append(pIn1);triStream.RestartStrip();FS_INPUT pIn2;pos = gsIn[i].pos + float4(normalize(gsIn[i].w_tangent), 0.0) *_LineLength;pIn2.pos = mul(unity_MatrixVP, pos);pIn.lineColor = _TangentLineColor;pIn2.lineColor = _TangentLineColor;triStream.Append(pIn);triStream.Append(pIn2);triStream.RestartStrip();FS_INPUT pIn3;pos = gsIn[i].pos + float4(normalize(gsIn[i].w_bitangent), 0.0) *_LineLength;pIn3.pos = mul(unity_MatrixVP, pos);pIn.lineColor = _BitangentLineColor;pIn3.lineColor = _BitangentLineColor;triStream.Append(pIn);triStream.Append(pIn3);triStream.RestartStrip();}}//step3float4 FS_Main(FS_INPUT input) : SV_TARGET0{return input.lineColor;}ENDHLSL}}
}

手动计算TNB

当然也可以手动计算切线空间的坐标系,但这样计算就会使得每个三角形面片都有自己独立的切线空间。例如,左图是模型默认切线空间,法线和切线由该顶点所参与的6个片元的法线和切线平均得到(平滑着色),右图是只根据法线在各片元内重新计算的切线和副切线(如果法线也各片元重新计算,就是平直着色)。【学习TNB矩阵过程中写的意义不明的Shader,而且法线用平均的但切线又重新算这是什么迷惑操作啊】

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Custom/ShowNormals"
{Properties{_LineLength("LineLength", float) = 0.03_NormalLineColor("NormalLineColor", Color) = (1.0, 0.0, 0.0, 1.0)_TangentLineColor("TangentLineColor", Color) = (0.0, 1.0, 0.0, 1.0)_BitangentLineColor("BitangentLineColor", Color) = (0.0, 0.0, 1.0, 1.0)}SubShader{Pass{HLSLPROGRAM#pragma vertex VS_Main#pragma fragment FS_Main#pragma geometry GS_Mainfloat4x4 unity_MatrixVP;float4x4 unity_ObjectToWorld;float4x4 unity_WorldToObject;float _LineLength;float4 _NormalLineColor;float4 _TangentLineColor;float4 _BitangentLineColor;struct VS_INPUT{float3 m_pos:POSITION;float2 uv:TEXCOORD;float3 normal:NORMAL;};struct GS_INPUT{float4 pos:POSITION;float2 uv:TEXCOORD0;float3 normal:NORMAL;};struct FS_INPUT{float4 pos:POSITION;float4 lineColor:TEXCOORD0;};GS_INPUT VS_Main(VS_INPUT input){GS_INPUT output;output.pos = mul(unity_ObjectToWorld, float4(input.m_pos, 1.0));output.normal = normalize(mul(transpose((float3x3)unity_WorldToObject), input.normal));output.uv = input.uv;return output;}[maxvertexcount(18)] //GS单次调用可以输出的最大顶点数量,这里每个顶点会变成俩顶点所以是3*2;void GS_Main(triangle GS_INPUT gsIn[3], inout LineStream<FS_INPUT> triStream){float3 edge1 = gsIn[1].pos - gsIn[0].pos; float3 edge2 = gsIn[2].pos - gsIn[0].pos;float2 deltaUV1 = gsIn[1].uv - gsIn[0].uv; float2 deltaUV2 = gsIn[2].uv - gsIn[0].uv; float f = 1.0 / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);float3 tangent;tangent.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);tangent.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);tangent.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);float3 bitangent;bitangent.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);bitangent.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);bitangent.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);for(uint i = 0; i < 3; ++i){float3 m_tangent = normalize(tangent - gsIn[i].normal * dot(gsIn[i].normal, tangent));float3 m_bitangent = normalize(cross(tangent, gsIn[i].normal)); FS_INPUT pIn;pIn.pos = mul(unity_MatrixVP, gsIn[i].pos);FS_INPUT pIn1;float4 pos= gsIn[i].pos + float4(gsIn[i].normal, 0) *_LineLength;pIn1.pos = mul(unity_MatrixVP, pos);pIn.lineColor = _NormalLineColor;pIn1.lineColor = _NormalLineColor;triStream.Append(pIn);triStream.Append(pIn1);triStream.RestartStrip();FS_INPUT pIn2;pos = gsIn[i].pos + float4(m_tangent, 0) *_LineLength;pIn2.pos = mul(unity_MatrixVP, pos);pIn.lineColor = _TangentLineColor;pIn2.lineColor = _TangentLineColor;triStream.Append(pIn);triStream.Append(pIn2);triStream.RestartStrip();FS_INPUT pIn3;pos = gsIn[i].pos + float4(m_bitangent, 0) *_LineLength;pIn3.pos = mul(unity_MatrixVP, pos);pIn.lineColor = _BitangentLineColor;pIn3.lineColor = _BitangentLineColor;triStream.Append(pIn);triStream.Append(pIn3);triStream.RestartStrip();}}float4 FS_Main(FS_INPUT input) : SV_TARGET0{return input.lineColor;}ENDHLSL}}
}

TNB矩阵和UV坐标关系

(不确定!)使用默认切线,在网格形变时可能会有问题?

把平面网格左下角的顶点移动到平面中心,世界空间下的法线出现了大问题(如下),左图的斜边应该是同样的颜色才对(即法线方向相同)。

梳理梳理TNB和法线贴图采样的过程导致问题的原因其实很明确,个人感觉对于会产生形变的网格,需要手动计算TBN矩阵时,考虑到TNB正交化对UV采样法线贴图的影响,需要对采样后的法线再增加一个和TNB正交化有关系的变换,可能后面会补充一下这部分的实现。

几何着色器:

https://zhuanlan.zhihu.com/p/585436751

DirectX11 With Windows SDK--15 几何着色器初探 - X_Jun - 博客园

渲染管线(主要是重新了解几何着色器):

一文读懂什么是渲染管线(7k字) - 天份& - 博客园

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

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

相关文章

[代码随想录Day16打卡] 找树左下角的值 路径总和 从中序与后序遍历序列构造二叉树

找树左下角的值 定义&#xff1a;二叉树中最后一行最靠左侧的值。 前序&#xff0c;中序&#xff0c;后序遍历都是先遍历左然后遍历右。 因为优先遍历左节点&#xff0c;所以递归中因为深度增加更新result的时候&#xff0c;更新的值是当前深度最左侧的值&#xff0c;到最后就…

【第七节】在RadAsm中使用OllyDBG调试器

前言 接着本专栏上一节&#xff0c;我们虽然已经用上RadAsm进行编写x86汇编代码并编译运行&#xff0c;但是想进行断点调试怎么办。RadAsm里面找不到断点调试&#xff0c;下面我们来介绍如何在RadAsm上联合调试器OllyDBG进行调试代码。 OllyDBG的介绍与下载 OllyDBG 是一款功能…

WPF MVVM框架

一、MVVM简介 MVC Model View Control MVP MVVM即Model-View-ViewModel&#xff0c;MVVM模式与MVP&#xff08;Model-View-Presenter&#xff09;模式相似&#xff0c;主要目的是分离视图&#xff08;View&#xff09;和模型&#xff08;Model&#xff09;&#xff0c;具有低…

PH热榜 | 2024-11-19

DevNow 是一个精简的开源技术博客项目模版&#xff0c;支持 Vercel 一键部署&#xff0c;支持评论、搜索等功能&#xff0c;欢迎大家体验。 在线预览 1. Layer 标语&#xff1a;受大脑启发的规划器 介绍&#xff1a;体验一下这款新一代的任务和项目管理系统吧&#xff01;它…

【ArcGISPro】使用AI模型提取要素-提取车辆(目标识别)

示例数据下载 栅格数据从网上随便找一个带有车辆的栅格数据 f094a6b1e205cd4d30a2e0f816f0c6af.jpg (1200799) (588ku.com) 添加数据

联通光猫(烽火通信设备)改桥接教程

一、获得超级密码 1.打开telnet连接权限 http://192.168.1.1/telnet?enable1&key9070D3BECD70&#xff08;MAC地址&#xff09;2.连接光猫获取密码 telnet 192.168.1.1 用户名&#xff1a;admin 密码&#xff1a;Fh9070D3BECD70连接成功后 load_cli factory show admin_…

掌握SEO提升网站流量的关键在于长尾关键词的有效运用

内容概要 在现代数字营销中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;被广泛视为提升网站流量的核心策略之一&#xff0c;而其中长尾关键词的运用显得尤为重要。长尾关键词通常由三个或更多个词组成&#xff0c;具有更高的针对性和精确度&#xff0c;可以更好地满足…

【期权懂|个股期权中的备兑开仓策略是如何进行的?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 个股期权中的备兑开仓策略是如何进行的&#xff1f; 个股期权备兑开仓的优点和风险‌&#xff1a; ‌&#xff08;1&#xff09;优点‌&#xff1a;备兑开仓可以增强持股收益&…

汽车安全再进化 - SemiDrive X9HP 与环景影像系统 AVM 的系统整合

当今汽车工业正面临著前所未有的挑战与机遇&#xff0c;随著自动驾驶技术的迅速发展&#xff0c;汽车的安全性与性能需求日益提高。在这样的背景下&#xff0c;汽车 AVM&#xff08;Automotive Visual Monitoring&#xff09;标准应运而生&#xff0c;成为促进汽车智能化和安全…

MongoDB聚合操作

管道的聚合 管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。 MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。 表达式&#xff1a;处理输入文档并输出。表达式是无状态的&#xff0c;只能用…

向量数据库FAISS之五:原理(LSH、PQ、HNSW、IVF)

1.Locality Sensitive Hashing (LSH) 使用 Shingling MinHashing 进行查找 左侧是字典&#xff0c;右侧是 LSH。目的是把足够相似的索引放在同一个桶内。 LSH 有很多的版本&#xff0c;很灵活&#xff0c;这里先介绍第一个版本&#xff0c;也是原始版本 Shingling one-hot …

https(day30)

1.配置需要配置端口为443 2.配置需要配置证书 ssl_certificate /path/to/your/fullchain.pem; # 证书文件 ssl_certificate_key /path/to/your/private.key; # 私钥文件 3.其他优化

【WPF】Prism学习(七)

Prism Dependency Injection 1.注册类型&#xff08;Registering Types&#xff09; 1.1. Prism中的服务生命周期&#xff1a; Transient&#xff08;瞬态&#xff09;&#xff1a;每次请求服务或类型时&#xff0c;都会获得一个新的实例。Singleton&#xff08;单例&#xf…

服务器数据恢复—热备盘未激活导致硬盘掉线的raid5阵列崩溃的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌X3850服务器中有一组由数块SAS硬盘组建的RAID5阵列&#xff0c;该阵列中有一块盘是热备盘。操作系统为linux redhat&#xff0c;上面跑着一个基于oracle数据库的oa。 服务器故障&#xff1a; 服务器raid5阵列中有一块硬盘离线&#xff0…

ADS 2022软件下载与安装教程

“ 本文以最新的Advanced Design System 2022为例介绍ADS软件的安装及crack教程 ” ADS 简介 先进设计系统 Advanced Design system&#xff08;ADS&#xff09;Agilent Technologies 是领先的电子设计自动化软件&#xff0c;适用于射频、微波和信号完整性应用。ADS 是获得商…

Chrome 浏览器 131 版本新特性

Chrome 浏览器 131 版本新特性 一、Chrome 浏览器 131 版本更新 1. 在 iOS 上使用 Google Lens 搜索 自 Chrome 126 版本以来&#xff0c;用户可以通过 Google Lens 搜索屏幕上看到的任何图片或文字。 要使用此功能&#xff0c;请访问网站&#xff0c;并点击聚焦时出现在地…

Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失

Unity 编辑器下 Android 平台 Addressable 加载模型粉红色&#xff0c;类似材质丢失 Addressable Play Mode Script加载模式 选择 Use Existiing Build 1.Unity 切换到 PC 平台&#xff0c;执行 Addressable Build 运行&#xff0c;加载 bundle 内的预制体 显示正常 2.Unit…

独立站干货:WordPress主机推荐

WordPress作为全球最受欢迎的独立站建设平台&#xff0c;提供了灵活性和强大的功能&#xff0c;使得建站变得简单而高效。本文将为您详细介绍WordPress建站的流程&#xff0c;并推荐几款实测后觉得好用的主机商。 WordPress建站流程 域名注册 首先需要注册一个域名&#xff0c…

每日OJ题_牛客_天使果冻_递推_C++_Java

目录 牛客_天使果冻_递推 题目解析 C代码 Java代码 牛客_天使果冻_递推 天使果冻 描述&#xff1a; 有 n 个果冻排成一排。第 i 个果冻的美味度是 ai。 天使非常喜欢吃果冻&#xff0c;但她想把最好吃的果冻留到最后收藏。天使想知道前 x个果冻中&#xff0c;美味…

C++AVL平衡树

1.AVL平衡树节点定义 每一个节点都配左右孩子和父节点&#xff0c;以及平衡因子和其所对应的值。 template<class K, class V> struct AVLTreeNode {// 需要parent指针&#xff0c;后续更新平衡因子可以看到pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTr…