常见坑与排障
按症状索引:在下表找到你的现象,跳到对应小节;每条给出多半原因、怎么办、去哪读深。
| 症状 | 跳转 |
|---|---|
| 画面全黑 / 什么都不显示 | #black-screen |
| 物体表面闪烁、叠面分不清前后(Z-Fighting) | #z-fighting |
| 远处或动画中的模型被误剔除、凭空消失 | #culling |
| macOS 上视口不出图 | #macos |
| iOS 上开混合后黑屏(浮点渲染目标) | #ios-blend |
| 浏览器里某些东西静默消失,桌面端正常 | #browser-drops |
| 浏览器首帧崩溃 / 启动即中止 | #browser-crash |
| iOS / 浏览器首帧特别慢 | #slow-first-frame |
| 直接改骨骼矩阵不生效 | #bone-matrix |
| 粒子完全看不到 | #particles |
| 逐实例属性(颜色等)不生效或全错 | #instance-location |
| 自定义 Pass 首帧画空,第二帧起才正常 | #shader-order |
| Uniform 怎么设都没反应 | #uniform-silent |
| GLSL 看着没错却编译失败 | #glsl-chars |
| PipelineSettings 改了不生效 | #settings-timing |
编译报「Color 是 System.Drawing.Color 和 Avalonia.Media.Color 的歧义引用」 | #color-ambiguity |
| 第 5 盏同类型光没效果 / 环境光参数不动作 | #limits-ambient |
| 切后台、分离控件回来后画面要不要重建 | #context-restore |
画面不出东西
画面全黑 / 什么都不显示
按命中率排查四个原因:
- 没加光源——默认 BlinnPhong 管线没光就是全黑。加一盏
DirectionalLight并设好RotationDegrees(方向光靠旋转定义照射方向,转背对模型同样是一片黑)。 - 相机没对准——场景必须有相机,
Aura3DView.MainCamera是默认相机;确认它没躲到物体背面或钻进球体内部,可用camera.LookAt(...)或FitToBoundingBox(model.BoundingBox, padding: 0.5f)对准目标。 CreateRenderPipeline赋值太晚——它必须在控件 GL 初始化之前(即加载之前)赋值;在SceneInitialized之后才设就晚了,指定的管线不会生效。BlendMode.Masked把半透明当裁剪丢弃——Masked 下 alpha ≤AlphaCutoff(默认 0.5)的像素直接discard,半透明贴图会大面积破洞甚至整块消失。要真正的半透明请用BlendMode.Translucent。
光与相机细节见 光照与阴影、相机与视角控制;管线赋值时机见 选择与配置管线。
物体表面闪烁、叠面分不清前后(Z-Fighting)
- 多半原因:深度缓冲精度不够,两个几乎重叠的面无法判别先后。
- 怎么办:把
PipelineSettings.DepthFormat设为DepthComponent32f(默认即 32f;若曾为省内存降到 16/24,调回来)。注意它在管线创建后改无效,须在创建前设置。 - 深读:选择与配置管线。
远处或动画中的模型被误剔除、凭空消失
- 多半原因:视锥剔除用的是按静态顶点算出的 T-Pose 包围盒;骨骼动画(行走、跳跃等)让模型明显超出包围盒时,还在视野里的网格会被剔掉。
- 怎么办:给模型
model.BoundingBoxPadding = new Vector3(2f)各方向扩包围盒,或model.CustomBoundingBox = new BoundingBox(min, max)完全覆盖动画范围;验证时可临时Settings.EnableFrustumCulling = false,或用Settings.Debug.ShowBoundingBox = true直接看包围盒。静止模型无需调整。 - 深读:动画系统。
macOS 上视口不出图
- 多半原因:宿主走了非 OpenGL 的原生渲染模式。
- 怎么办:在
AppBuilder里显式钉AvaloniaNativeRenderingMode.OpenGl。iOS 不需要这种特判(它有自己的 ANGLE 路径)。 - 深读:平台与渲染后端。
平台特有:静默失败
iOS 上开混合后黑屏(浮点渲染目标)
- 多半原因:iOS 的 ANGLE(Metal) 后端不提供
GL_EXT_float_blend;混合开启时绘制到 32 位浮点颜色附件(如Rgba32f)会被当作GL_INVALID_OPERATION静默丢弃——症状是黑屏而不是报错。 - 怎么办:HDR 渲染目标统一改用
Rgba16f(框架内置管线就是这么做的);自定义 Pass 不要申请Rgba32f颜色附件后又开混合。 - 深读:平台与渲染后端 → GLES 3.0 子集。
浏览器里某些东西静默消失,桌面端正常
- 多半原因:WebGL2 校验严格,违规的整条 draw 被静默丢弃。四大诱因:① 启用的 draw buffer 没有对应"被写入的片元输出"(depth-only FBO 忘
glDrawBuffers([GL_NONE]);片元声明了out但所有#ifdef分支都不写它);②UseShader/UseShader_Internal顺序写反(见 #shader-order);③ 颜色附件用了 RGB 族内部格式(RGB8/RGB16F/RGB32F不可渲染,必须 RGBA 族);④ 用了 WebGL2 不存在的入口点(如glGetTexLevelParameteriv)。 - 怎么办:自定义 Pass 按 GLES 3.0 子集检查以上四条;内置管线本身不受影响。
- 深读:平台与渲染后端 → GLES 3.0 子集。
浏览器首帧崩溃 / 启动即中止
- 多半原因:.NET 10 Release 裁剪删掉了 WASM interpreter-to-native trampoline(日志走到
[aura3d-webgl] output ...后aot-runtime-wasm.c:188 <disabled>、exit(1)),或 linked-icall 表与System.Private.CoreLib不同步(Your mono runtime and class libraries are out of sync/function signature mismatch)。启动即DllNotFoundException: libSkiaSharp则是 wasm 没链上原生库。 - 怎么办:应用
.csproj的 Release 下同时设三项:PublishTrimmed=false+RunAOTCompilation=false+WasmLinkIcalls=false(只设其一必挂其一);改完用全新bin/obj/发布目录,部署时整体替换远端静态目录并刷新dotnet.js缓存。 - 深读:平台与渲染后端 → .NET 10 Release 必填配置。
iOS / 浏览器首帧特别慢——属正常
- 多半原因:iOS 上 ANGLE 在运行时把 GLSL 翻成 MSL 逐变体编译、无磁盘缓存;浏览器上 Mono 解释器执行宿主代码慢。实测:iOS PBR+CSM 场景首帧约 5.6–5.9 s、简单场景 0.4–0.7 s;浏览器重场景首帧可能以分钟计。
- 怎么办:等首帧出来即正常;不要为性能单独开
RunAOTCompilation(会退化成 #browser-crash 的崩溃)。 - 深读:平台与渲染后端。
动画、实例与粒子
直接改骨骼矩阵不生效
- 多半原因:骨骼矩阵每帧在动画采样阶段由
IAnimationSampler.Update()重算,你在SceneUpdated里的直接写值会被覆盖。 - 怎么办:程序化控制骨骼需要自定义
IAnimationSampler,或确保在动画采样之后覆盖矩阵。 - 深读:动画系统 → 骨骼手动操作。
逐实例属性(颜色等)不生效或全错
- 多半原因:顶点着色器里声明的
layout(location = N)与BuildInVertexAttribute枚举值不一致(location 就是枚举的数字),或#ifdef INSTANCED_MESH分支忘了自己乘逐实例modelMatrix——覆盖顶点着色器就等于接管了实例变换。 - 怎么办:对照 内置 Pass 与着色器宏速查 的 location 约定表;
InstancedMesh.SetAttributeEnabled("InstanceNormalTransform", false)可关闭不需要的实例法线矩阵以省带宽。 - 深读:实例化渲染。
粒子完全看不到
- 多半原因:没调
Play();或关着自动出帧(AutoRequestNextFrameRendering = false却没逐帧RequestNextFrameRendering())。 - 怎么办:配置完成后
ps.Play();其余「粒子在原点 / 不移动 / 网格模式全黑 / Flipbook 不动」等按参数逐条排查。 - 深读:粒子系统 → 常见问题排查。
着色器与自定义 Pass
自定义 Pass 首帧画空,第二帧起才正常
- 多半原因:
UseShader_Internal()写在了UseShader(...)/AddDefines(...)之前——本帧绑定的还是上一帧(首帧是空宏)的变体。 - 怎么办:一律按
UseShader→UseShader_Internal→ 设 uniform → draw 的顺序写;另外宏顺序影响缓存 key(;拼接),建议UseShader一次性声明所有宏。 - 深读:自定义渲染管线。
Uniform 怎么设都没反应
- 多半原因:
Uniform*系列方法在着色器未激活(CurrentShader为空)或该 uniform 名在程序里不存在时静默跳过、不报错。不遍历网格的 Pass(纯RenderQuad/RenderCube)必须手动调用UseShader_Internal()。 - 怎么办:先检查激活顺序(#shader-order),再核对 GLSL 里 uniform 名拼写;引擎固定提供
modelMatrix/viewMatrix/projectionMatrix/cameraPosition,材质参数按同名 uniform 绑定。 - 深读:自定义渲染管线、自定义材质与着色器。
GLSL 看着没错却编译失败
- 多半原因:着色器源码里写了中文注释或全角字符。
- 怎么办:GLSL 内注释只用 ASCII;解释性文字写在 C# 侧。
- 深读:自定义材质与着色器。
配置与时机
PipelineSettings 改了不生效
- 多半原因:有些设置只能在管线创建前指定,创建后再改被忽略:
DepthFormat、DirectionalLightLimit/PointLightLimit/SpotLightLimit、CsmCascadeCount、CsmShadowMapResolution。其余(CsmSplitLambda、ToneMappingExposure、BrightnessClamp、AmbientIntensity、EnableFxaa、EnableFrustumCulling、Debug.*)随时可改、下帧生效。 - 怎么办:创建前的设置在 XAML
PipelineSettings或控件构造时指定;运行时调试用view.Scene.RenderPipeline.Settings.X = ...。 - 深读:选择与配置管线。
编译报「Color 是歧义的引用」
- 多半原因:Aura3D 的颜色属性(
Material.BaseColor、Light.LightColor、Texture.CreateFromColor(...)等)收的是System.Drawing.Color,而 Avalonia 工程里常用的是Avalonia.Media.Color;两个命名空间同时using时裸写Color就冲突。 - 怎么办:写全限定
System.Drawing.Color.White,或using DrawingColor = System.Drawing.Color;起别名。Avalonia 颜色转换:System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B)。 - 深读:快速开始。
第 5 盏同类型光没效果 / 环境光参数不动作
- 多半原因:默认每类光源上限 4 盏,超限的灯不产生光照和阴影;上限范围 1..10,且必须管线创建前调。另:
AmbientIntensity只对 BlinnPhong/CelShading 生效,PBR 管线用 IBL 环境光、不吃这个参数。 - 怎么办:管线创建前提高对应
*LightLimit;PBR 场景想要环境亮度请配 HDR 环境贴图。 - 深读:光照与阴影、选择与配置管线。
上下文与生命周期
切后台 / 控件分离再回来,画面要不要重建?
- 不用。 上下文丢失后
ContextLost触发、新上下文就绪时ContextRestored触发,全部 GPU 资源按需自动重建,画面自己回来;场景、节点、材质都在,不需要重建场景,也不会再次触发SceneInitialized——场景只在首次初始化时构建一次。 - 注意:不要订阅
SceneInitialized去重复建场景来"应对丢失";需要显式归还显存用Aura3DView.ReleaseGpuResources(),彻底结束用DestroyScene()。 - 深读:GPU 资源生命周期。