当前位置: 首页 > news >正文

自由学习记录(96)

毛茸茸,摇动的草地,反射探针,体积雾,手机端材质

NDC(归一化设备坐标)的差异

差异出现在 投影变换之后

API / 平台NDC XNDC YNDC Z 范围
OpenGL-1→1-1→1-1→1
DirectX / Vulkan-1→1-1→10→1
  • OpenGL:近平面投影后 Z = -1,远平面 Z = +1。

  • DirectX/Vulkan/Metal:近平面投影后 Z = 0,远平面 Z = 1。


3. Unity 的处理

Unity 会屏蔽这些差异:

  • 在 Shader 宏里通过 UNITY_UV_STARTS_AT_TOP、平台宏和 _ProjectionParams 做适配。

  • 所以写 Unity Shader 时你只需要记住:

    • 相机空间 forward = –Z

    • 投影后 Z 的范围 Unity 会替你处理(除非你在做跨平台深度贴图手动解码)。

Unity 的坐标系:一路左手制

  • 世界空间
    Unity 使用左手坐标系,X 轴指右,Y 轴指上,Z 轴指前(远离摄像机方向)。Unity Documentationtecharthub.com

  • 相机空间(View Space):
    本质也是左手坐标系。只是相机被设定在原点,并且朝向是 –Z(摄像机前方),但 X 和 Y 方向的定义保持不变。Game Development Stack ExchangeUnity Discussions

总结:两个空间的坐标系是一致的,差异只在于转换方式和空间的定义点不同。

https://stackoverflow.com/questions/4124041/is-opengl-coordinate-system-left-handed-or-right-handed

The F0 range for most common dielectrics will be from 0.02-0.05 (linear values). For conductors, the F0 range will be 0.5-1.0. The reflectivity of a surface is therefore determined by the refractive index as shown in the equation below (Lagarde 2011).F0范围对于大多数常见电介质将从0.02-0.05(线性值)。对于导体,F0范围将是0.5-1.0。因此,表面的反射率由下述方程中的折射率决定

Refracted light is absorbed, and the color tint of metals comes from the reflected light, so in our maps, we don’t give metals a diffuse color.

  • 金属贴图 (metallic map) 里:

    • 黑色 = 非金属

    • 白色 = 金属

  • 漫反射贴图 (diffuse map) 里:

    • 金属区域 = 黑色(因为金属几乎没有漫反射)

    • 非金属区域 = 有颜色(木头、塑料的颜色)。

  • 金属一旦生锈,表面就变成了“非金属物质”(比如氧化铁)。

  • 所以在贴图里,锈掉的部分应该当 非金属 (dielectric) 来处理,F0 = 0.04。

  • 渲染时就会显示那种暗红色的锈迹。

https://www.adobe.com/learn/substance-3d-designer/web/the-pbr-guide-part-1?learnIn=1&locale=en

我正在尝试理解OpenGL坐标系统。然而,一些教程说默认坐标系统是左手系(参见http://www.c-sharpcorner.com/UploadFile/jeradus/OpenGLBasics11172005014307AM/OpenGLBasics.aspx)而另一些教程说它是右手系(参见http://www.falloutsoftware.com/tutorials/gl/gl0.htm)。哪个是正确的?我明白我们可以通过镜像将一个转换为另一个,但我想知道默认坐标。

  • OpenGL 并没有硬性规定你一定要用左手系还是右手系来组织你的物体。

  • 你在 CPU 端定义的顶点数据,可以是任何坐标系。最终都会被变换成裁剪空间。

为什么 OpenGL 不硬性规定世界/对象坐标系?

因为 OpenGL 是一个“状态机 + 矩阵流水线”,它的职责是:
👉 把你提供的顶点,经过一系列矩阵变换,最后映射到 裁剪空间 / NDC

  • 你在 CPU 端组织顶点的方式(左手/右手)是完全自由的

  • 只要你提供相应的 Model / View / Projection 矩阵,就能把数据变换到 OpenGL 规定的 裁剪空间 (Clip Space)

  • 所以 OpenGL 不需要知道“你原来是左手还是右手”,它只要求最后进入裁剪阶段的数据符合它的规则。

什么是由我来提供,具体举几个实际中的情况

好问题 👍,我前面说“由你来提供”,意思是:OpenGL 本身不自动生成这些变换矩阵,而是由开发者在程序里传入(作为 Uniform 或常量缓冲区),再由顶点着色器使用

我给你几个具体实际中的情况,帮你感受“你需要提供”的意思:

glm::mat4 model = glm::mat4(1.0f);  
model = glm::translate(model, glm::vec3(3.0f, 0.0f, -5.0f));  // 平移到场景某处
model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0.0, 1.0, 0.0)); // 绕 Y 旋转
model = glm::scale(model, glm::vec3(2.0f)); // 放大 2 倍


这就是你 提供给着色器 的 model 矩阵。

OpenGL 不知道相机在哪,所以你要自己算这个矩阵。

这里就是通过世界坐标下的相机坐标,通过投影到相机空间的三个基向量方向,确定每个点在位置上要往哪个方向移动多少的值,

先旋转再平移,

  • OpenGL 的本质:它只是一个 图形状态机 + 渲染流水线,负责把你提交的顶点、纹理、状态数据,经过矩阵运算、光栅化,最后变成像素。

  • 它内部没有“场景”或“相机”的概念,更不会记住“世界里有个摄像机在 (0,0,3),看向 (0,0,0)”这种信息。

什么叫“状态机”?

状态机 (State Machine) = 系统内部保存一组“状态”,之后所有操作都会受到这些状态的影响。

  • 你设置一次状态,它就会一直保持,直到你显式修改。

  • 你再发的绘制命令,都会在这个“当前状态”下执行。

OpenGL 就是一个 图形状态机

  • 它内部维护很多“状态”,比如:

    • 当前使用的着色器程序 (glUseProgram)

    • 当前绑定的纹理 (glBindTexture)

    • 当前的顶点数组对象 VAO (glBindVertexArray)

    • 深度测试开关 (glEnable(GL_DEPTH_TEST))

    • 混合模式、剔除模式、缓冲区绑定……

一旦你设置了这些,OpenGL 就会记住。
然后当你调用:glDrawArrays(GL_TRIANGLES, 0, 36);
它就会在 当前所有状态的组合下,去执行渲染。

  • 状态机 = OpenGL 内部保存的开关/配置/绑定资源。

  • 渲染流水线 = 当你发出绘制命令时,GPU 按照固定流程(顶点处理 → 裁剪 → 光栅化 → 片段处理 → 混合)处理数据。

👉 所以说 OpenGL 是“图形状态机 + 渲染流水线”:

  • 状态机部分决定了“怎么处理”(开了哪些功能,绑定了哪些资源)。

  • 流水线部分决定了“按什么顺序处理数据”。

渲染状态机指的是渲染过程中那些“一旦设置就持续生效”的状态选项,比如:

  • 开启/关闭某些功能:深度测试、混合、剔除、MSAA、动态分辨率等。

  • 资源绑定:当前使用的着色器、材质、纹理、渲染目标、后处理效果等。

  • 渲染阶段控制:哪些 Pass 会执行、顺序如何、何时做阴影或透明物体渲染。

  • 灯光/阴影配置、剔除规则、光照类型、多摄像头设置等。

https://stackoverflow.com/questions/33407209/why-does-the-camera-face-the-negative-end-of-the-z-axis-by-default

1. 在 Object / World / Eye(视图)空间上,OpenGL 默认是右手坐标系

如 Stack Overflow 所说:

"OpenGL is right handed in object space and world space."
Stack Overflow

2. 而到了裁剪空间(Clip Space)与 NDC(Normalized Device Coordinates),坐标系会被**“翻转”**,也就是变成 左手坐标系:
  • 这是因为 OpenGL 的标准投影矩阵(如 glOrtho/glFrustum)对 Z 轴做了 -1 倍缩放,使得 +Z 轴变向屏幕内,变成左手感知方向 Stack Overflow。

  • 结果是:虽然前面阶段是右手系,但输出到屏幕时已经变成左手系了。

3. Redit 上也有开发者解释:

“当抛弃固定管线后,进入裁剪空间(Clip Space)的坐标系是左手的... +Z 方向指向屏幕内 → 是左手系统。”
Reddit

4. 现代观点也认同这一点:

文章标题直接说明**“OpenGL is NOT right-handed”**。
它指出:现代 OpenGL 只认识 NDC 坐标,而它本身是左手系。
GingerBill

对比表格 (OpenGL vs DirectX)

渲染阶段 / 坐标空间OpenGL 默认DirectX 通常方式
Object / World / View 空间右手坐标系也可以是右手或左手,自由选择
Clip Space / NDC默认左手:+Z 朝屏幕内常见为右手:+Z 朝屏幕外

🟡 方法 2:直接画一个坐标轴 Gizmo

写一个简单的 Mesh(或者在 Unity 里用 Gizmos.DrawLine):

  • 画一条红色线条: (0,0,0) → (1,0,0) (+X)

  • 画一条绿色线条: (0,0,0) → (0,1,0) (+Y)

  • 画一条蓝色线条: (0,0,0) → (0,0,1) (+Z)

然后在场景里观察:

  • 如果蓝轴朝向屏幕外(远离你),那是右手系。

  • 如果蓝轴朝向屏幕内(指向你),那是左手系。

Unity 的 Scene 视图里默认就有这种小坐标轴,你可以验证一下。

🔵 方法 3:NDC 检查

你可以直接把一个点 (0,0,1) 送进 gl_Position

gl_Position = vec4(0,0,1,1);

  • 如果这个点通过投影后在屏幕 前面可见,说明 +Z 朝向相机(左手)。

  • 如果不可见或被裁掉,说明 +Z 是远离相机的(右手)。

https://www.reddit.com/r/GraphicsProgramming/comments/1amkqk6/left_vs_right_handed_systems_which_part_of_the/?utm_source=chatgpt.com

Unity 的 Shader(无论是 ShaderLab、HLSL 还是 Shader Graph)最终都会被编译成对应平台的着色器代码,比如 OpenGL 的 GLSL 或 DirectX 的 HLSL。
这意味着你在 Unity 里用的 Shader,底层实际上是运行在那些 API 上的渲染流水线中。

软件 vs 硬件的渲染“管线”层级区别

  • 硬件层:如 GPU 和图形 API(OpenGL、Direct3D),定义顶点着色器、光栅化、片段着色器等低级阶段。The Khronos GroupWikipedia

  • 引擎层(软件层):如 Unity,引擎定义的是更高层次的“渲染管线”:如何处理材质、光照、摄像机等。它们最终会调用底层管线执行。Game Development Stack Exchange

Unity 特有的“可编程渲染管线”(Scriptable Render Pipeline,SRP)系统就是一种更面向内容、可定制的高层封装。Unity Documentation张卫的博客

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.1/manual/universalrp-builtin-feature-comparison.html

平台兼容性第一,这样的出发角度的确一般不会去用hdrp了

而且builtin没有想象的那么老要被舍弃,依然有优秀的兼容性的

_ProjectionParams 是 Unity 内置的一个 Shader uniform,由引擎在渲染时自动传入,主要提供相机投影相关的 4 个参数。它的定义(在 UnityCG.cginc)

float4 _ProjectionParams;

四个分量含义如下:

  1. x = 1.0 或 -1.0

    • 区分深度缓冲的 y 方向是否翻转。

    • +1 表示正常的透视投影,-1 通常表示渲染到纹理时做了垂直翻转。

    • 用来处理平台差异(如 D3D vs OpenGL)和摄像机渲染到 RT 时的坐标反转问题。

  2. y = near plane (相机近裁剪面距离)

  3. z = far plane (相机远裁剪面距离)

  4. w = 1.0 + 1.0 / far plane

    • 用在深度相关的计算里(比如线性化深度)。

    • 便于从深度缓冲值恢复到视空间深度。

https://gamedev.stackexchange.com/questions/183048/differences-between-unity-ue-shaders-and-opengl-shaders?newreg=681ea5a01949431f8d8f3050dfb1690f

_ProjectionParams.x 所指的“渲染到纹理时”的“那个纹理”是指 Unity 渲染过程中使用的 Render Texture(渲染纹理)。它在以下情景中至关重要:

  • Unity 会将场景渲染到一个 Render Texture,尤其是在做后处理特效(Image Effects)、深度纹理生成或自定义渲染流程时,这种纹理是 camera 渲染的“中间结果” Unity Documentationdocs.unity.cn。

  • 不同平台(如 Direct3D vs OpenGL)在渲染到 Render Texture 时,Y 方向可能被 Unity “内部翻转”,以保持主屏幕渲染的一致性 Unity Documentation+1。

你看到的 UnityObjectToClipPos()LinearEyeDepth() 不是 GLSL/HLSL 本身的内建函数,而是 Unity 的预处理宏/辅助函数

  • 它们写在 Unity 自带的 CGInclude 文件里(比如 UnityCG.cgincHLSLSupport.cginc)。

  • 当你写 Shader 的时候,Unity 的 shader compiler 会根据目标平台(OpenGL、DirectX、Metal、Vulkan…)把这些宏展开成对应的底层代码

innerSpotAngle 是 Unity 中专用于 Spot Light(聚光灯) 的一个属性,表示灯光射锥中 完全发光区域的角度。它属于 Scriptable Render Pipeline(如 URP/HDRP)时有效,不适用于 Built-in 渲染管线。Unity DocumentationUnity Learn


用途说明

  • innerSpotAngle 定义了从聚光灯中心向外,灯光保持最大亮度的范围。

  • 超出这个角度但仍在 outerSpotAngle 内部时,光强会 逐渐衰减,形成柔和过渡的边缘效果(penumbra)。Unity LearnPerso ESIEE

举例:若设置 inner = 30°outer = 60°

  • ≤ 30° 范围内:亮度最大。

  • 30° ~ 60°:光强线性衰减。

  • 60°:无光照。

Culling Per TileNoNoYes
Culling Per LayerYes

Based on GameObject layers
Yes

Based on dedicated Light layers
Yes

Based on dedicated Light layers
Multiple directional lightsYesYes

Supports shadowing for one directional light at a time.
Yes

Supports shadowing for one directional light at a time. To simulate more, use Spot light with a Box shape.
Number of real-time lights per objectUnlimitedIn Deferred: unlimited.

In Forward: 4 for GLES2, 8 for all other graphics APIs.
Unlimited

Built-in 管线设计年代久远,Spot 光只提供单一角度(outer);没有分离的内圈/外圈控制逻辑。功能受限但兼容性强。

Culling Per Object / Per Tile / Per Layer

Culling(剔除) = 决定某个物体要不要被某盏灯光影响。

  • Per Object
    每个物体单独决定是否被某个灯光影响。
    👉 常见于传统管线(Built-in),比较直接,但性能一般。

  • Per Tile
    屏幕被划分成小方块(tile,例如 16x16 像素),再决定这些 tile 中的像素是否要算某个灯光。
    👉 这是 tiled/clustered lighting,URP/HDRP 里都有,适合大量灯光场景。

  • Per Layer
    通过 Unity 的 Light Layers(光照层),只让特定层的物体被特定灯光影响。
    👉 例如:UI 层的物体不被场景灯光照亮。


☀️ 2. Multiple directional lights

是否支持场景中同时存在多个方向光(sun-like light)。

  • Built-in 支持多个,但性能差。

  • URP/HDRP 默认只允许 1 个方向光投射阴影,其他的只算光照不算阴影。


💡 3. Number of real-time lights per object

一件物体最多能被多少个 实时灯光(非烘焙)影响。

  • Built-in:无限制(但性能可能爆炸)。

  • URP:Forward 模式下有上限(如 GLES2 上限 4,其它 API 上限 8),Deferred 模式几乎无限。

  • HDRP:无限制。


📷 4. Number of real-time lights per Camera

每个相机一次渲染时,能同时考虑多少盏实时灯光。

  • Built-in:理论上无限(但拖慢性能)。

  • URP:有限制,比如移动端最多 32,其它平台 256。

  • HDRP:基于 tile/cluster,Deferred 模式下可以做到每 tile 63 盏灯,Forward 模式下每 cluster 63。

URP Forward+ (Tiled vs Clustered) - #5 by Kabinet13 - Unity Engine - Unity Discussions

URP 为什么说 “Single pass only”

这指的是 URP 渲染架构与 Built-in 模式的本质差异:

  • Built-in 渲染管线使用 Multiple Passes。比如 Forward 渲染时,主光照用一个 Pass,其他光源累加再用多个 Pass(ForwardBase + ForwardAdd)RedditUnity Forums。

  • URP(Universal Render Pipeline)设计为 Single-pass 渲染:它不允许在一个 Shader 中定义多个 Pass,取而代之的是用一个线性流程(multiple stages)优化渲染,兼容更广平台,性能更高RedditUnity Forums。

那么,我可以写多个 Pass 吗?

  • 在纯 ShaderLab 里写多个 Pass 是可行的,但 URP 渲染流程不能执行它们;Unity 会报错或忽略它们Reddit。

  • 如果你想模拟多个渲染阶段效果,可以用 URP 的 Render Features / Scriptable Render Passes 插件功能,把不同渲染逻辑拆成多个阶段(stage),它们在 URP 管线中按顺序执行,效果类似但仍属于一个总流(render graph)Unity LearnUnity Documentation。

什么是 Light Cookies?

  • 在剧院和电影灯光中cookie(或称为 cucoloris、gobo)指在灯光前放置的图案板,让光线投射出特定的图案形状,比如窗户、树叶的阴影等 Wikipedia。

  • 在 Unity 中,Light Cookie 是一个 贴在 Light 上的遮罩贴图,可以改变光照的形状和强度,用于模拟花纹光斑、窗格阴影、海面反射等效果,并且实现效率高、运行时开销低 Unity DocumentationWayline。

在 Unity 各渲染管线中的支持情况

渲染管线是否支持 Light Cookies特性说明
Built-in Render Pipeline支持,仅使用 Alpha 通道形状遮罩仅影响光影形状,不支持颜色遮罩 Unity Documentation
URP (Universal Render Pipeline)不支持(正在研究但未实现)---新版支持了当前版本里无法使用 Light Cookies Unity Documentation
HDRP (High Definition Render Pipeline)支持彩色 cookies(RGB + Alpha)支持颜色和形状遮罩,效果更丰富 Unity Documentation

怎么在 Built-in 中使用 Light Cookie

  1. 制作贴图:用灰度图(或带透明图)代表遮罩,常为 Alpha 通道或 “从灰度产生 Alpha”。

  2. 设置 Texture:在 Unity Inspector 中,将图片的 Texture Type 设为 “Cookie”,并启用 Alpha From Grayscale(如果使用灰度图) Unity Documentation+1。

  3. 应用到灯光:拖动这个贴图到灯光组件的 Cookie 字段即可。

  4. 调整效果:聚光灯(Spot Light)会在光束范围内投影一次,定向光(Directional Light)可选择重复铺设效果,并可调整 Cookie Size 控制大小 Unity DocumentationWayline。

https://www.reddit.com/r/Unity3D/comments/13qsafw/does_urpsrp_officially_support_multipass_shaders/?utm_source=chatgpt.com

URP 是怎么处理多光照的?

1. Single-pass + 循环处理
  • URP 支持 一个 Pass 内处理多光源。Shader 会在这个 Pass 中使用 光源循环(light loop) 的方式,依次累积多个光源的贡献 Unity Documentation。

  • 这个逻辑适用于传统 Forward 渲染路径,也支持 Forward+ 渲染路径 Unity Documentation。

2. 每个物体最多处理有限数量光源
  • URP 在每个物体上默认只处理 1 个主光(Main Light) + 最多 8 个附加光源(Additional Lights),且这些都是每像素计算(可选改为 per-vertex)Unity DocumentationUnity Discussions。

  • 因此,它不会为每个光使用一个 Pass,而是在同一个 Pass 中用循环处理多个光源计算。

3. 为何不是多 Pass?
  • 多 Pass 渲染(如 Built-in 中常见的 ForwardBase + ForwardAdd)会为每个光源额外生成一个渲染调用,效率较低。

  • URP 的单 Pass 循环结构提高性能,并减少渲染开销,实现更高效率 Unity Documentation+1。


小结对比表

渲染管线类型多光照处理方式
Built-in使用多个 Pass(如 ForwardBase + 多个 ForwardAdd)
URP在一个 Pass 内用循环累积多个光源贡献

用一句用户社区语来解释:

URP “就是一次过处理所有光照,不按每个光拆 Pass” 的设计 Unity DocumentationUnity Discussions。

IES Lights(即 IES 灯光)源自真实灯具厂商提供的 IES 光度曲线(IES Profiles),用于模拟真实世界光源的发光分布。它们在 Unity(尤其 HDRP)中作为一种更加物理精准的渲染工具可直接使用。以下是核心信息:

Light Anchor 是什么?

**Light Anchor(灯光锚点)**是 HDRP 中专门提供的组件,用来让灯光绕目标点(锚点)相对主摄像机做动态定位或旋转,非常适合创建电影镜头般的灯光布置。它能让多个光源环绕主体位置,以实现更为灵活的打光效果。
Unity DocumentationUnity

使用方法:

  1. 选中场景中的一个 Light GameObject。

  2. 在 Inspector 点击 Add Component → Rendering → Light Anchor 添加组件。

  3. 组件会默认以当前挂载对象的位置作为 Anchor(锚点)。

  4. 设置属性即可控制灯光相对于 Anchor 和主摄像机的行为,包括:

  • Orbit(环绕):左右旋转角度

  • Elevation(仰角):上下角度

  • Roll:控制 Cookie 或 IES 灯光图样的旋转角

  • Distance:灯光距离锚点的距离

  • Up Direction:设置 Y 轴参考是相机视角还是世界方向

  • Anchor Position Override:让锚点跟随场景中某个 GameObject

  • Common presets:快速应用常见的影视打光角度预设
    Unity DocumentationUnity User Manual

Light Anchor 是 HDRP 内部实现的一部分,目前并没有单独公开的源码可以直接查看或修改。它由 HDRP 包内部的渲染工具所控制,属于 Unity 的闭源管线功能模块。如果你深入调试或改写其行为,可能需要自己实现类似 Shader + 脚本驱动逻辑。

https://docs.unity3d.com/6000.2/Documentation/Manual/shadow-cascades.html

当方向性光源产生的实时阴影靠近相机时,阴影会呈现出像素化的效果。 a problem called perspective aliasing, 

在 Scene 视图中可切换“Shadow Cascades”Draw Mode 检查每级阴影范围与切分是否合理Unity User Manual。

Unity 中 how to use?

Built-in 渲染管线

  • 前往 Project Settings → Quality,为每个 Quality Level 设置当中支持 0 / 2 / 4 级联阴影。

  • Unity 会自动配置阴影贴图分段的范围和比例Unity DocumentationUnity User Manual。

URP(Universal Render Pipeline)

  • Universal Render Pipeline Asset 中配置阴影级联数量与分段比例,比 Buit-in 更集中与统一Unity Documentation。

HDRP(High Definition Render Pipeline)

  • 在 HDRP 的 Volume Settings 中(如 Shadow Settings),让方向光支持级联阴影。HDRP 默认支持多级联,而 Shadow Map Atlas 处理更高级,且支持动态缩放、影图复用等优化Unity Documentation。

  • Stable Fit 投影:Unity 会尽可能让阴影贴图在摄像机旋转过程中保持“静止”,避免可见的阴影抖动或“游走”现象(shadow swimming)。

    “Stable Fit renders lower resolution shadows but they don’t wobble with camera movements.” Unity DocumentationStack Overflow

  • Close Fit 投影:它会让阴影贴图“紧贴”摄像机视野,从而利用更高分辨率渲染更清晰的阴影,但代价是当摄像机移动或旋转时,阴影贴图可能会“jitter”或略微抖动。

    “Close Fit renders higher resolution shadows but they can sometimes wobble slightly if the camera moves.” Unity DocumentationUnity DiscussionsStack Overflow

  • 如果你在场景中看到阴影边缘在相机移动时抖动或跳动,表明你的 Shadow Projection 设置不合适,这时可以尝试切换到 Stable Fit,改善视觉稳定性。

    “Try Changing Shadow projection → Close Fit That works for me !!”
    “But yes that pixel light solution did not work for me... after changing [...] from Stable Fit to Close Fit, I got a better result.” RedditStack Overflow

  • 如果你对阴影的清晰度要求更高,并愿意接受轻微抖动,可以选择 Close Fit,优先考虑画面质量。

Unity 中如何设置

这些选项可以在 Project Settings → Quality Settings → Shadows → Shadow Projection 中找到(仅存在于 Built-in 渲染管线中):

  • 选择 Stable FitClose Fit,然后根据需要调节 Shadow Distance、Cascade 数量等其他设置。 Unity Documentation

Screen-space shadows 是一种在 屏幕空间(Screen Space) 中计算阴影的技术,它通过 深度贴图和屏幕空间光线追踪/体素化 等方式,生成阴影信息,而不是依赖传统的 Shadow Maps:

  • Unity 官方文档中称它为 Screen Space Shadows Renderer Feature,适用于 URP 的 Forward 渲染。它使用额外的 Render Texture 来在屏幕空间计算主光源对不透明物体的阴影,并在渲染前进行绘制,节省多次读取 Shadow Cascade 贴图的资源开销。Unity Documentation

  • 在 URP 16.0+ 的新版文档里进一步说明:它用一个 单一的屏幕空间阴影贴图 来替代多个 Shadow Cascade 贴图,在 Forward 渲染中能提升性能,但会消耗更多内存,还需要 Depth Pre-Pass 支持。Unity Documentation

  • 社区讨论中也有人提到:这种 Screen-space 阴影可以为那些传统 Shadow Mapping(阴影贴图)没有涵盖到的区域补充阴影细节,但可能带来性能负担。Reddit

“Shadow Screen Space Pass” 在渲染流程中是哪里?

在实际的渲染流程里,它体现为一个新的 Render Pass,专门负责:

  • DrawOpaqueObjects pass 之前,进行深度预通道(Depth Pre-pass),构建场景的深度贴图。

  • 根据屏幕空间中不透明物体的深度信息,计算阴影遮蔽。

  • 输出一个屏幕空间阴影贴图。

  • 在后续实际渲染主光照时,使用该贴图来决定像素是否受阴影影响。

这个过程就是我们说的 "Shadow Screen Space Pass"。

将其与 Shadow Lighting Pass 区别对比

功能Shadow Lighting PassShadow Screen Space Pass
渲染阶段从光源视角绘制 Shadow Map在屏幕空间中基于深度贴图计算阴影信息
依赖机制依赖多个深度贴图(Shadow Cascades)依赖额外的屏幕空间贴图(Depth + Shadow Texture)
性能特点Shadow Map 切换和多次数读性能开销减少 Cascade 读取次数,但增加内存开销
应用范围用于所有可产生阴影的物体(包括透明)通常只用于不透明物体,透明仍使用 Shadow Map

如何在 Unity URP 中使用?

  1. 打开 Unity 编辑器,进入对应的 URP Renderer Asset 设置。

  2. 点击“A d d Renderer Feature”,添加 Screen Space Shadows

  3. 这样就会自动启用前 Depth Pre-pass,并在 DrawOpaqueObjects 阶段前计算并绘制屏幕空间阴影。

  4. 可以在 Frame Debugger 中查看 ScreenSpaceShadows Pass 与 MainLightShadow Pass 的区别,观察场景中哪些区域使用了哪一种方式。Unity Documentation

什么是 Shadow Bias?

Shadow Bias 是在进行比较判断(是否在阴影中)时,在深度上加入一个微小偏移值,以 避免由于数值精度和插值误差引起的自阴影问题。当一个像素距离几乎和 shadow map 中记录的深度相等时,渲染可能误判为被遮挡,从而出现 shadow acne。这时,通过添加 bias 可以确保这些“边界像素”正确被判为“可见”,而不出现伪影。 Unity DocumentationScratchapixel

Unity 中的 Bias 设置项

在 Unity 中,每个光源组件中有两个用来控制阴影偏移的参数:

  • Bias(深度偏差)(Depth Bias):在 shadow map 生成过程中,让渲染的几何体向光源方向微调(偏移),避免随着采样出现 self-shadow 问题。

  • Normal Bias(法线偏差):沿法线对几何体进行内缩,减少斜面或边缘的 shadow acne,但可能导致阴影靠内且变窄。

  • Unity URP 也支持这两个参数,可从 Pipeline Settings 或 Light 面板中自定义设置。Unity Documentation

Unity 中,每个光源组件中有两个用来控制阴影偏移的参数:

  • Bias(深度偏差)(Depth Bias):在 shadow map 生成过程中,让渲染的几何体向光源方向微调(偏移),避免随着采样出现 self-shadow 问题。

  • Normal Bias(法线偏差):沿法线对几何体进行内缩,减少斜面或边缘的 shadow acne,但可能导致阴影靠内且变窄。

  • Unity URP 也支持这两个参数,可从 Pipeline Settings 或 Light 面板中自定义设置。Unity Documentation

使用时的平衡取舍

调整类型效果可能副作用
增加 Bias(深度偏差)尽量减少 Shade Acne可能导致阴影与物体分离 (“peter-panning”)
增加 Normal Bias(法线偏差)减少斜面的自阴影伪影阴影轮廓变窄,可能出现 light bleeding

理想情况下,两者应尽量小,但又要足够防止伪影。这需要对不同场景进行视觉比对与调整。通常 Unity 的默认值适用于大多数场景。Unity DocumentationScratchapixelCatlike CodingMr F

社区调优经验

从 Unreal Engine 的官方文档也可看到类似设置:

“An overview of the Lighting example ... Shadow Bias … help objects feel more grounded along a surface. Decreasing value can lead to self-shadowing artifacts.”
Epic Games Developers

社区建议也提到:

“Try adjusting bias values and cascade settings to fix shadow artifacts.”
Epic Developer Community Forums

PCF(Percentage Closer Filtering)是什么?

PCF 是一种用于缓解 shadow map 划痕(锯齿阴影)问题的技术:

  • 原理:对每个像素,不只取一个深度比较结果,而是在 shadow map 周围采样多个位置,执行多次深度比较,然后将结果平均,这样能得到一个带有柔和边缘的阴影效果。

  • 术语由来:因为它计算的“阴影程度”是多次“是否靠近光源(closer)”判断结果的平均百分比。这就是为什么叫“Percentage Closer Filtering”。
    NVIDIA DeveloperWikipedia

一个通俗的例子就是,将硬阴影比作黑白边界,而 PCF 就把边界抹成灰色,形成软化过渡。

PCF 在现实代码里怎么做?

来自 OpenGL 教程的一个简单实现逻辑:

float CalcShadowFactor(vec4 LightSpacePos) {// 计算投影 UV 和深度值...for (offset in 3×3 kernel) {Factor += texture(shadowMap, offset); // 深度比较结果为 0 或 1}return Factor / 9.0; // 得到阴影占比
}

这里 texture() 是 shadow map 的 sampler2DShadow,返回的是比较结果(非传统纹理值)
ogldev.org

PCF 不只是在计算“模糊”,而是滤 Boolean 值

正如某位开发者在专业社区里解释的那样:

“PCF 处理的是布尔比较结果,而不是先滤深度再比较。”
GPU 硬件通常支持 2×2 的 PCF 核合并,并使用双线性插值来再滤一次。
Reddit

Unity 中的 PCF 实现方式(HDRP 举例)

在 Unity HDRP 中,就提供了多个阴影 滤波质量级别

  • Low(低):点光/聚光灯使用 PCF 3×3(4 次采样);方向光使用 PCF Tent 5×5(9 次采样)

  • Medium(中):使用 PCF 5×5(9 次采样)

  • High(高):使用更高级的 PCSS(Percentage Closer Soft Shadows)
    Unity Documentation+1

PCSS 是建立在 PCF 之上的软阴影版本,具有动态模糊尺寸的特点,依赖光源与阻挡物距离。
Unity DocumentationNVIDIA Developer Downloads

为什么 PCF 必不可少?

  • 抗锯齿能力出众:能显著缓解硬阴影边缘锯齿问题

  • 易于实现,性能可控:你可以根据设备状况选择 kernel 大小

  • Unity Shader Graph、URP 等都能支持 PCF 设置
    Unity Discussions

项目内容说明
核心原理多次采样 shadow map,平均比较结果得软阴影
算法重点滤的是布尔比较结果,不是深度值本身
Unity 实现HDRP 提供 Low/Medium/High,不同质量对应不同采样核
高级版本PCSS(软阴影)基于 PCF 增加动态模糊范围控制
优劣比较优点:抑制锯齿;缺点:采样次数越多,性能消耗越高

Unity Built-in 渲染管线和**URP(通用管线)**对光线追踪效果(如 Ambient Occlusion、Reflections 等)基本都标注为“不支持”──这是事实。Unity 将这些功能主要集中在 **HDRP(高清渲染管线)**中,并且依赖 DXR(DirectX Raytracing)的前提条件才能开启。Unity DiscussionsUnity DocumentationUnity

那我自己写的 Shader 说是光线追踪,但没用 HDRP,这算什么?

这其实是一种让人容易混淆的说法。你遇到的是一种类似“光线追踪效果 simulation”的自定义 Shader 或算法,例如:

  • 利用 ray marching 在片元 Shader 中模拟追踪光线;

  • 或在 Compute Shader 里自己实现射线投射逻辑,比如处理反射、阴影等。

从技术上讲,这属于“自己的射线追踪逻辑”,并不是利用硬件 DXR 和 Unity HDRP 提供的“真正”的 Ray Tracing 功能。这种方式 虽然可以做出类似效果,但不被官方标为“Ray-traced Reflections”等功能,因为这些标记特指 HDRP + DXR 的硬件加速实现。Unity Discussions

Book of the Dead: Quixel, wind, scene building, and content optimization tricks

赛道与挑战项目

1) Shading / 材质表现

项目:风雨湿润一体化材质(地面+金属+布料三材质)

  • 要点:屏幕空间雨滴扰动、法线/粗糙度随雨强度实时变化、积水区间接反射融合。

  • 验收:RTX 4060 笔电 1080p 60 FPS;额外 Draw 不超过 +2;显存 < 300 MB;雨强从 0→1 过渡无跳变与拉花。

2) Render Feature / RenderGraph

项目:URP 延迟贴花(Decal)与法线混合

  • 要点:在 URP 自写贴花 Pass,支持 BaseColor/Normal/Roughness 投射,法线正确切换切线空间。

  • 验收:100 个贴花不掉帧;与阴影、后处理兼容;边界无锯齿/无双影;材质球界面可视化参数面板。

3) GPU 仿真 / Compute

项目:10 万体 Boids + 障碍回避 + 蒙皮跟随

  • 要点:ComputeBuffer 驱动,DrawMeshInstancedIndirect 渲染,小队编队与目标点切换,支持 1 个蒙皮角色作为吸引体。

  • 验收:10 万体 60 FPS;GC 0 次;Dispatch/Frame ≤ 3;转向/回避无穿模;提供 Nsight/RenderDoc 抓帧截图与参数表。

4) 体积效果 / 雾光

项目:体素化体积雾(Froxels)+ 阴影

  • 要点:视锥体体素网格,单向光体积阴影积分,体积蓝噪点时间降噪。

  • 验收:体积阴影稳定无闪烁;降噪后残噪 < 5%(以差值帧统计);近景光柱清晰、远景渐隐自然。

5) 工具链 / TA Pipeline

项目:纹理通道打包与探针可视化工具

  • 要点:一键把多贴图通道压进 RGBA,自动生成导入规则;场景内可视化 Light Probe/Reflection Probe 影响区域。

  • 验收:美术拖拽源贴图→自动生成目标材质可用包;误配率 0;探针热区/死区一目了然;有 EditorWindow 与日志。

统一交付格式(每个项目都这样)

  • Repo 结构Assets/Runtime, Assets/Editor, Docs/,内含 README、Profiling 报告、已录制演示视频。

  • 指标表:FPS、CPU/GPU 时间、批次、显存、带宽、过绘。

  • 技术笔记:架构图 + 关键公式/伪代码 + 踩坑与对策。

  • 测试场景:小中大三档负载,截图与参数保存。

游戏内部常见的内存管理策略

游戏在内存压力下做的更多是资源卸载或画质降低,而非压缩内存。常用做法包括:

  • On-demand 卸载资源
    在收到系统的内存告警(例如 Android 的 onTrimMemory),游戏会释放缓存、非当前使用贴图等资源。
    Android Developers

  • 内存预分配机制
    开发者常通过 Arena 分配器、对象池等方法预先申请内存并反复使用,避免频繁申请导致碎片或崩溃。
    jenniferchukwu.com

  • 动态调整图像资源
    在资源加载和运行时,根据硬件性能动态调节纹理压缩、分辨率等,以减轻内存压力。
    DEV Community

Unity官方下载_Unity新版_从Unity Hub下载安装 | Unity中国官网

区域信息与 Unity 账户无关

  • 单纯创建 Unity ID(Unity 帐号)时,你只需填写电子邮件和密码,并不会被系统要求选择或确认所在地区。系统也不会依据你的网络位置自动将账号划分至某个区域。Unity

  • Unity 的后台组织结构由你本人创建或加入的 Unity Organizations(组织) 决定,而非基于 IP 或国家划分。你可以随时管理或切换你的组织,与地理位置无关。Unity

https://www.youtube.com/watch?v=KvVL-LIq28A

“There was an error during the Project Binding process. Please make sure you are online and logged in: Failed to get the service authentication token. Try again or contact Unity support.”

这是 Unity 在尝试将项目连接到 Cloud Diagnostics 服务时,未能获取有效服务验证令牌而导致的问题。

结论:Hub 走了代理不代表 Editor 内的 Unity AI 请求也走了。AI 走的是 Editor 的网络栈;若 Editor 没经代理,服务端按出口 IP判定到中国区,就会提示 “not available in your region”。Unity 明确写了代理要分别让各组件识别,且 AI 在中国不可用。Unity Documentation+1Unity Discussions

你现在该做的最小改动

把启动脚本再加两行

UNITY_PROXYSERVER 是 Editor 使用 libcurl 时的专用变量;很多人只设 HTTP(S)_PROXY,导致 Editor 不跟随。Unity Discussions+2Unity Discussions+2

https://discussions.unity.com/t/offline-usage-of-unity-getting-harder/763430?utm_source=chatgpt.com

// Handle the final result after all attempts have been exhausted or a definitive failure was encountered.if (result != null){if (result.Result.Error.AiResponseError == AiResultErrorEnum.UnavailableForLegalReasons)Account.settings.RegionAvailable = false;if (result.Result.Error.AiResponseError == AiResultErrorEnum.ApiNoLongerSupported)Account.settings.PackagesSupported = false;var errorMessage = result.Result.Error.AiResponseError == AiResultErrorEnum.RateLimitExceeded // typically means wrong url (staging vs prod)? $"Account information returned {result.Result.Error.AiResponseError} on Url '{selectedEnvironment}'. Is the Url correct?\nTrace Id {result.SdkTraceId} => {result.W3CTraceId}": $"Error after {retryAttempt + 1} attempt(s): {result.Result.Error.AiResponseError} - {result.Result.Error.Errors.FirstOrDefault()} -- Result type: {typeof(TResponse).Name} -- Url: {selectedEnvironment} -- Trace Id {result.SdkTraceId} => {result.W3CTraceId}";if (!string.IsNullOrEmpty(UnityConnectProvider.organizationKey) && errorMessage != s_LastLoggedError){Debug.Log(errorMessage);s_LastLoggedError = errorMessage;}}

UnavailableForLegalReasons 是服务端直接拒绝(等价于 451/政策限制)。请求已发到 generators-beta.ai.unity.com,所以链路通。要么 Editor 仍用到受限出口 IP,要么账号/组织被政策标记。Unity Documentation

  • VRAM 是专用的显卡内存
    它使用高带宽的 GDDR/HBM 类型 RAM,紧邻 GPU,读写速度极快、延迟低。用途包括保存纹理、帧缓冲、着色器常量等。
    Super UserWikipedia

  • 系统RAM(DDR)是通用内存
    用于操作系统、程序、CPU 运算,但带宽与延迟均逊于 VRAM。系统 RAM 和 VRAM 在物理与逻辑上是隔离的。
    Super UserWikipedia

当 VRAM 不足,系统怎么做?

  • 溢出到系统 RAM
    当 GPU 的 VRAM 不够时,驱动会尝试让 GPU 从系统 RAM 获取数据,尤其是没有及时释放的纹理或缓冲区,或者有重用需求时。
    但这需要通过 PCI-Express 总线,速度远慢于 VRAM,延迟与带宽大幅下降。
    Super UseriRender Cloud Rendering ServiceDiskMFRStack Overflowtherealmjp.github.io

  • 社区经验反馈
    Reddit 用户指出,即使发生“spillover”,显卡性能会急剧下降,帧率可能从几十 FPS 跳到个位数。

    “It’s like saying yes you can run Windows and game on a 15 year old HDD... You just shouldn’t.”
    Reddit

  • 现代集成 GPU(UMA 架构)例外
    集成 GPU(iGPU)与 CPU 共享同一物理内存。GPU 使用系统 RAM 的一部分作为其显存区域,这不算“溢出”,而是架构本身的设计。
    Reddittherealmjp.github.io

特别说明:新硬件/驱动支持手动调整共享显存

  • Intel 推出了 Shared GPU Memory Override(Arc iGPU)
    允许用户将高达 87% 的系统 RAM 分配给 iGPU 用作显存。适用于 AI 或高 VRAM 需求任务,但可能影响 CPU 性能。
    Tom's HardwareTechRadar

  • AMD 有类似的 Variable Graphics Memory(VGM)
    可通过 Adrenalin 软件,让笔记本将多达 75% 的系统 RAM 当作 VRAM 使用,提高游戏表现。
    The Verge

类型存储位置使用方式
独立显卡(普通情况)GPU 专用 VRAM高速专用内存,不与 CPU 共享
当 VRAM 不够系统 RAM 作为溢出通过 PCIe 缓慢访问,性能大幅下降
集成 GPU(UMA)系统 RAM(共享)架构设计为共享,无效区分显存和 RAM
新驱动功能可手动分配内存池Intel/AMD 提供工具扩展系统 RAM 用作 GPU 内存区域

3.顶部页签_哔哩哔哩_bilibili

还有红绿色盲的选项

4.CPU Usage 上_哔哩哔哩_bilibili

分析单个函数被调用的情况,和单个函数主动调别的模块的情况

5.CPU Usage 下_哔哩哔哩_bilibili

树形的显示timeline,这样更直观的直接看到那个函数占用时长很长

Frame Rate 与 精度间的关系

情况帧率影响建议做法
Raycast 每帧调用(Update 内)部分帧缺失导致错判。但检测逻辑保持准确性优化性能,避免卡顿,必要时合并多次调用
物理碰撞(固定步调)使用 FixedUpdate,帧率波动不影响推荐物理模拟使用 FixedUpdate
快速移动穿透问题(tunneling)高速度情况下可能跳过碰撞启用 CCD(Continuous Collision Detection) 或用 ray 越距离检测 Godot Forumdigitalrune.github.io

实战建议

  1. 用 FixedUpdate 而不是每帧调用射线。

  2. 若目标速度极快,考虑 CCD 或在移动路径上用短距离 raycast 避免漏判。

  3. 避免帧率低导致逻辑执行不稳定。必要时限制最低 FPS 或使用时间累积模拟。

是否使用固定时间步(fixed timestep)。Unity 默认物理在 FixedUpdate 中以固定间隔运行,与帧率无关,因此碰撞逻辑保持一致。

“The frame-rate won't affect physics if you've got it set to simulate during the fixed-update (default).” Unity Discussions

什么是垂直同步,什么是三重缓冲。垂直同步到底要不要开,垂直同步和三重缓冲到底有什么用。

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

显示器都有一个自己的刷新频率,60Hz的显示器一秒钟就是刷新60张画面,144Hz显示器就是一秒钟刷新144张画面。这当中,每一张画面我们都称之为一帧。

显示器的刷新率是固定的,比如60Hz显示器那么他就是固定每隔1/60秒刷新一帧。

显示屏的刷新率是固定的,也就是说你看上去屏幕即使没有更新画面,但是他底层还是在刷新的,而推动刷新的帧率是不固定的

基本机制区分

  • 刷新率(Refresh Rate):显示器固定以每秒 X 次(如 60 Hz、144 Hz)重绘屏幕,即使画面内容未变,背后仍在周期性发起刷新。WikipediaSamsung Business Insights

  • 帧率(Frame Rate):由 GPU/CPU 决定、随负载浮动,表示每秒生成了多少帧内容。IntelAVADirect

结论:显示器持续刷新,帧率则反映你系统实际有多少画面可供显示。

常见误区与实际效果

  • 若帧率低于刷新频率,显示器会在没有新帧输入时重复上一个画面,导致暂停或卡顿感,但硬件仍按固定频率刷新。

  • 若帧率超过刷新率,显示器仅显示其能力范围内的帧,未呈现的帧会被“丢弃”或重复显示。RedditAVADirectSteam Community

伏笔:可变刷新率(VRR)

  • 有些现代屏幕支持 可变刷新率(VRR),能根据系统帧率自动调整刷新频率,实现同步,从而消除卡顿与撕裂。常见技术包括 G-Sync、FreeSync、Adaptive-Sync。WikipediaViewSonic

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

所以虽然很多人对于游戏画面流畅的定义是60FPS,但是你要清楚的就是,在你不能保证显卡输出的帧和显示器刷新率完美契合,那么显卡输出60FPS实际上是不流畅的,因为你的显示器一直会发生错帧现象,你可能就会看到50帧的画面,所以这就是为什么,保证游戏画面流畅的帧数需要高于60而不是等于60。

Freesync的驱动部件由厂家自己或者找外包完成,同面板不同产品性能品质可以差几十条街,极端例子FS2735 VS 马云DIY。

而不同面板的性能又层次不齐,就导致各种黑屏,闪屏,莫名其妙的延迟等现象,而G-sync的显示器,从研发,设计,量产都是由NV全程参与协调的,同时还需要往显示器内部植入专用芯片,也就是G-sync实际就是一个高门槛,这个门槛就决定了你的体验肯定比层次不齐的Freesync强,但是如果使用的是顶尖的Freesync面板,那其体验一点都不比G-sync差,所以评论区有个比较专业的老哥就说了,其实G-sync就是买个放心,保证这个技术肯定能带给你良好的体验,而Freesync就有点抽奖的意思了,运气好,这个面板完美适配Freesync,运气不好,体验很差,这个功能干脆就不开。


文章转载自:

http://ZhyhMwaj.sLLpt.cn
http://Vh07JlSq.sLLpt.cn
http://pRQb3lZC.sLLpt.cn
http://alPxBgRy.sLLpt.cn
http://clEUvxKu.sLLpt.cn
http://RZ7YYgMJ.sLLpt.cn
http://qfpIEkcm.sLLpt.cn
http://KQrtEL66.sLLpt.cn
http://41NPfy9q.sLLpt.cn
http://ZJm9rJce.sLLpt.cn
http://A6SQKxhW.sLLpt.cn
http://1s4bvfAu.sLLpt.cn
http://T434rvbm.sLLpt.cn
http://oWShPkSf.sLLpt.cn
http://lAYTIKrF.sLLpt.cn
http://bKIqh2ht.sLLpt.cn
http://6RFXU7Xd.sLLpt.cn
http://KMA6nm3t.sLLpt.cn
http://v9ifOAUd.sLLpt.cn
http://pW8r8kMU.sLLpt.cn
http://A8MuONXJ.sLLpt.cn
http://q2FzjdTL.sLLpt.cn
http://V4UnXOkc.sLLpt.cn
http://PA8Xgchh.sLLpt.cn
http://TAnpNdgc.sLLpt.cn
http://dRmFq0m2.sLLpt.cn
http://vmIZjElv.sLLpt.cn
http://OWhx37gc.sLLpt.cn
http://RY9BuVBY.sLLpt.cn
http://3NH5Bjjx.sLLpt.cn
http://www.dtcms.com/a/374072.html

相关文章:

  • Cy5-Tyramide, Cyanine 5 Tyramide;1431148-26-3
  • JMeter接口测试全流程解析
  • ARM处理器的小常识
  • Go语言极速入门与精要指南从零到精通的系统化学习路径
  • RK3576 android14 usb_audio_policy_configuration.xml解析
  • 本地安装部署svn服务,并设置外网远程访问内网svn,含路由器转发和端口映射工具教程
  • idea2025构建springboot项目能运行的样例
  • 【底层机制】std::unordered_map 扩容机制
  • Cpp::STL—位图bitset的使用与模拟实现(39)
  • 链表 (C/C++)
  • WinEdt编译tex文件失败解决办法
  • C语言第12讲
  • commons-email
  • (堆)347. 前 K 个高频元素
  • GitHub Release Monitor部署指南:实时追踪开源项目更新与自动通知
  • 重新定义音频编程:SoundFlow如何以模块化设计革新.NET音频开发生态
  • SQL 注入与防御-第八章:代码层防御
  • Miniflux 安全升级:绑定域名并开启 HTTPS
  • 标准 HTTP 状态码详解
  • STM32开发(创建工程)
  • MFC 图形设备接口详解:小白从入门到掌握
  • APM32芯得 EP.34 | 告别I2C“假死”——APM32F103硬件IIC防锁死设计
  • n8n入门
  • 静态住宅IP的特点
  • 数智之光燃盛景 共同富裕创丰饶
  • colmap+pycolmap带cuda编译
  • Nano-Bananary 搭建 使用 nano banana
  • 前端性能监控与优化:从 Lighthouse 到 APM
  • 浅聊一下微服务的网关模块
  • 硬件开发2-ARM基本概要