CD Code Digest Hub /GTA V · v2

着色器与材质:game/shader_source、technique group、CShaderLib、自定义着色效果

50 分钟阅读 10 个章节

本页解释 GTA V 游戏层的着色器体系:game/shader_source 中 .fx/.fxh 的组织方式(“megashader”按宏组合生成上百个材质着色器)、构建工具链与平台变体、technique 命名约定与 technique group(渲染阶段如何让同一个材质在 GBuffer/阴影/水反射/前向等场景下选用不同 technique)、CShaderLib 的全局着色器常量与状态缓存,以及按实体实例定制着色器参数的 CCustomShaderEffect* 系列(ped/车辆/树/草/道具/色调/武器/镜面/电缆/内部/UV 动画)。

背景与相关页面#

相关源码文件#

文件内容
src/dev_ng/game/shader_source/common.fxh、commonMS.fxh全局着色器公共头(约 3000 行)与 MSAA 公共头
src/dev_ng/game/shader_source/Megashader/megashader.fxh + *.fx通用材质“megashader”及其 107 个配置变体
src/dev_ng/game/shader_source/{Peds,Vehicles,Terrain,Vegetation,Water,Sky,Custom,VFX,Lighting,PostFX,Util,Debug}各族着色器
src/dev_ng/game/shader_source/VS_Project/*着色器 VS 工程、fx.rules、makeshader.bat、batch/rsm_*.bat、readme.txt
src/dev_ng/game/shaders/ShaderLib.{h,cpp}CShaderLib:technique group 注册、着色器加载、全局常量、延迟材质 ID、状态块
src/dev_ng/game/shaders/CustomShaderEffect*.{h,cpp}、CustomShaderEffectTree.psc自定义着色效果基类与 11 个派生类型
src/dev_ng/game/shaders/CustomDrawableShaderVar.*、ShaderHairSort.*、ShaderEdit.*辅助:成组 shader var、头发排序渲染、bank 着色器编辑器
src/dev_ng/game/renderer/DrawLists/drawList.{h,cpp}CCustomShaderEffectDC、CopyOffShader(CSE 进入 drawlist)

1. shader_source 目录结构#

按本次盘点(Get-ChildItem 统计 .fx/.fxh 数量):

目录.fx.fxh代表文件
Megashader1074default、normal_spec、normal_spec_detail_dpm_tnt、decal_*、emissive*、parallax*、cutout_fence*、weapon_*、cloth_*;头:megashader.fxh、megashader_deferredRS.fxh、detail_map.fxh、Puddle.fxh
Vehicles542车漆/轮胎/玻璃/车灯等(未逐一列出)
Terrain334地形混合(未逐一列出)
Peds291ped、ped_default*、ped_wrinkle*、ped_hair_*、ped_fur、ped_decal*、ped_cloth*、ped_enveff
Vegetation/Trees、Vegetation/Grass20、103、3trees_*(含 _tnt、camera_aligned/facing、lod/lod2、shadow_proxy)、grass_batch*、grass_fur*
VFX206ptfx_*、ptxgpu_render/update、rmptfx_*、vfx_decal*、vfx_fogvolume、vfx_lightningStrike、golf_trail
Water123water、water_river*、water_shallow、water_foam、water_fountain、water_poolenv、waterTex
Custom(含 Glass/Mirror/Cable/Rope)11 + 171blend_2lyr、damage_blits、radar、rage_bink、skinblend、glass_*、mirror_*
Lighting(含 Lights/Shadows/AO)9 + 12 + 9 + 64 + 6 + 5 + 1deferred_lighting、deferred_ambient、deferred_volume、tiled_lighting、point/spot/capsule/directional、cascadeshadows*、shadowZCM、SSAO、HDAO、HDAO2
PostFX104postfx、dofCompute、dofDiffusion、adaptiveDof、avgLuminanceCompute、exposureGPU、mlaa、DistortionWarp
Sky(含 Clouds)1 + 81sky_system、clouds_*
Util67im、imMS、scaleform_shaders、BlurCS、ClearCS、MemoryCS
Debug713debug_rendering、debug_shadows、debug_lightprobe 等

目录名本身无需证据;具体文件名来自目录清单。共享头:common.fxh 包含 grcore/config_switches.h、Util/macros.fxh、Peds/ped_common_values.h、vfx/vfx_shared.h、scene/EntityId_shared.h、Util/BatchInstancing.fxh,以及 RAGE shaderlib 的 PN 三角形曲面细分头 src/dev_ng/game/shader_source/common.fxh:29-36、src/dev_ng/game/shader_source/common.fxh:849。许多 .h 文件同时被 C++ 与 HLSL 包含以共享常量(例如 cascadeshadows_common.fxh 被 RenderPhaseCascadeShadows.h 包含、TiledLightingSettings.h 用 __GTA_COMMON_FXH 区分两侧)src/dev_ng/game/renderer/RenderPhases/RenderPhaseCascadeShadows.h:10、src/dev_ng/game/renderer/Lights/TiledLightingSettings.h:10。

1.1 megashader:宏组合生成材质#

每个 megashader .fx 只是一组 #define 加一行 #include "../Megashader/megashader.fxh"。例如 normal_spec.fx 声明顶点声明 #pragma dcl position diffuse texcoord0 normal tangent0,再定义 USE_NORMAL_MAP、USE_SPECULAR、USE_DEFAULT_TECHNIQUES、USE_REFLECT、USE_DYNAMIC_REFLECT、CAN_BE_ALPHA_SHADER/CAN_BE_CUTOUT_SHADER、USE_ALPHACLIP_FADE src/dev_ng/game/shader_source/Megashader/normal_spec.fx:1-30。megashader.fxh 根据这些宏启用视差、布料、湿度、第二高光层等代码路径(#ifdef USE_PARALLAX_MAP、USE_CLOTH、USE_WETNESS_MULTIPLIER、USE_NORMAL_MAP、USE_SPECULAR…)src/dev_ng/game/shader_source/Megashader/megashader.fxh:48-228。文件名后缀是事实上的材质特征命名:_tnt(色调调色板)、_dpm(位移/视差图)、_pxm(视差遮挡)、_um(UV 微动画)、_detail、_decal、_reflect、_cubemap_reflect、_emissive*、_wind、_wrinkle、_twiddle(推断:后缀含义由宏名与目录交叉得出,未逐一核对每个 .fx 的宏)。

1.2 平台/着色模型差异#

common.fxh 用以下宏切换平台路径:__MAX(3ds Max 工具预览版本)、__LOW_QUALITY、__SHADERMODEL(如 >= 40 才有 ALPHA_SHADOWS)、__PS3(PS3 用 EDGE 在 SPU 上蒙皮,因此不生成 skinned technique)、__WIN32PC、RSG_ORBIS、__FXL(Xenon)src/dev_ng/game/shader_source/common.fxh:204-260、src/dev_ng/game/shader_source/common.fxh:300-329。关键开关:

宏定义证据
ALPHA_SHADOWS__SHADERMODEL >= 40src/dev_ng/game/shader_source/common.fxh:204
DRAWSKINNED_TECHNIQUES!__PS3 || USE_VEHICLE_INSTANCED_WHEEL_SHADER(注释:PS3 用 EDGE 内部蒙皮)src/dev_ng/game/shader_source/common.fxh:216
CUTOUT_OR_SSA_TECHNIQUES镂空着色器,或 SM≥40 时用 alphaclip 实现“点阵淡出”src/dev_ng/game/shader_source/common.fxh:222
FORWARD_TECHNIQUES非静态贴花/草着色器,或 PC/Orbissrc/dev_ng/game/shader_source/common.fxh:238
SHADOW_CASTING_TECHNIQUES_OK依平台与着色器类型决定是否生成阴影 techniquesrc/dev_ng/game/shader_source/common.fxh:254-259

MSAA 变体:光照、PostFX、阴影处理等需要读取多重采样目标的着色器都有 *MS.fx 与 *MS0.fx 两个包装文件,它们只是先包含 commonMS.fxh 再包含原 .fx;*MS0 额外定义 SAMPLE_FREQUENCY 0,即只处理 sample 0 并模拟逐样本插值 src/dev_ng/game/shader_source/Lighting/Lights/pointMS0.fx:1-3、src/dev_ng/game/shader_source/Lighting/Lights/pointMS.fx:1-2、src/dev_ng/game/shader_source/commonMS.fxh:1-30。commonMS.fxh 中 MULTISAMPLE_TECHNIQUES 需 SM≥40 且为 PC/Orbis/Durango,ENABLE_EQAA 仅主机 src/dev_ng/game/shader_source/commonMS.fxh:4-5。C++ 侧对应 MultisampleMode:MM_SINGLE、MM_SUPER_SAMPLE、MM_TEXTURE_READS_ONLY(仅 PC 边缘 pass)src/dev_ng/game/renderer/Deferred/DeferredConfig.h:312-320;延迟光照因此按 [aaMode] 维护多套 shader/technique(例如 m_deferredShaders[aaMode][…]、m_techniques[MM_DEFAULT][…])src/dev_ng/game/renderer/Deferred/DeferredLighting.cpp:1803、src/dev_ng/game/renderer/Deferred/DeferredLighting.cpp:3159。

2. 构建:从 .fx 到 common:/shaders#

  • 工程:VS_Project/shaders_20xx.vcxproj 列出全部着色器;readme.txt 说明新增着色器要在工程中 <!-- ADD SHADER FILES HERE --> 处添加,并同步 .filters src/dev_ng/game/shader_source/VS_Project/readme.txt:1-10。
  • 自定义构建规则 fx.rules:对 *.fx 调用 RAGEShaderManager -config=…\shaderbuild_tu_dev_ng.xml -action=cleanbuild -noDependencies -shader=$(InputPath) -platform=… -platformConfig=…,输出扩展名可为 fxc/cgx/fx,并为 IncrediBuild 声明输出掩码 src/dev_ng/game/shader_source/VS_Project/fx.rules:1-40。
  • 批处理:batch/rsm_build_<platform>.bat 调 rsm_build_any.bat <platform> <dev|final>,后者以 -buildfromdirectory -incredibuild 整目录构建 src/dev_ng/game/shader_source/VS_Project/batch/rsm_build_any.bat:1-5、src/dev_ng/game/shader_source/VS_Project/batch/rsm_build_win32_50.bat:1。rsm_build__all.bat 列出的目标平台:durango、max、max_anon、orbis、win32、win32_40、win32_50、win32_nvstereo,各有 dev/final 配置(win32_40_lq 另有批处理)src/dev_ng/game/shader_source/VS_Project/batch/rsm_build__all.bat:1-17。
  • 旧入口 makeshader.bat/start_makeshader.rb:平台 win32_30/40/50、fxl_final(Xenon)、psn(PS3)、fx_max,可选 /Randomize、/noWaveLines,转调 %RS_TOOLSROOT%\script\coding\shaders\makeshader.bat,输出到 %RS_BUILDBRANCH%\common\shaders\ src/dev_ng/game/shader_source/VS_Project/makeshader.bat:1-26、src/dev_ng/game/shader_source/VS_Project/start_makeshader.rb:1-34。RAGEShaderManager 本体与 shaderbuild_tu_dev_ng.xml 在 tools_ng,不在本页范围。
  • 运行时加载:CShaderLib::LoadInitialShaders 在启动最早期从 update2:/common/shaders 只加载 im、rage_bink、scaleform_shaders、rage_fastmipmap(MSAA 时加 imMS),以便尽快显示片头;LoadAllShaders 再用 grmShaderFactory::PreloadShaders("common:/shaders")(MSAA 时额外读 preloadMS 列表)预载其余着色器,之后在 assert 构建中禁止再加载新着色器 src/dev_ng/game/shaders/ShaderLib.cpp:241-275、src/dev_ng/rage/base/src/grmodel/shaderfactory.cpp:83-86。预载列表文件属于构建产物,源码树中只有 RAGE 自带的 preload.list(rage/base/src/shaders、suite/src/lightshaders、suite/src/testshaderdrivers),游戏的列表未在源码树中找到。

3. technique 命名与 technique group#

3.1 命名约定#

megashader.fxh 中 technique 以 <组>_<绘制方式> 命名:组前缀如 deferred、deferredalphaclip、lightweight0/4/8(前向光照,0/4/8 盏灯)、lightweight*CutOut、lightweightHighQuality*、unlit、tool;绘制方式后缀为 draw、drawskinned、drawinstanced、drawtessellated src/dev_ng/game/shader_source/Megashader/megashader.fxh:5239-5703。部分 technique 名由宏包装,如 SHADER_MODEL_50_OVERRIDE(deferred_drawtessellated)(SM5 曲面细分版本)、SSTA_TECHNIQUE(deferredalphaclip_draw) src/dev_ng/game/shader_source/Megashader/megashader.fxh:5664、src/dev_ng/game/shader_source/Megashader/megashader.fxh:5692。

3.2 group 的注册与使用#

RAGE 引擎先注册 unlit、default、blit、tool 四个 group src/dev_ng/rage/base/src/grmodel/shader.cpp:101-105;游戏在 CShaderLib::PreInit 中、任何着色器加载之前(注释“We need to register all techniques before any shaders get loaded”)注册其余 group src/dev_ng/game/shaders/ShaderLib.cpp:287-413:

group使用者证据(注册 / 查找)
ld、shadtexture_ld(Xenon/D3D11/Orbis)局部灯阴影深度src/dev_ng/game/shaders/ShaderLib.cpp:289-294 / src/dev_ng/game/renderer/Shadows/ParaboloidShadows.cpp:725-728
wdcascade、shadtexture_wdcascade(PS3 EDGE 下为 wdcascadeedge 变体)级联阴影深度src/dev_ng/game/shaders/ShaderLib.cpp:296-303 / src/dev_ng/game/renderer/RenderPhases/RenderPhaseCascadeShadows.cpp:6078-6085
ldpoint、ldedgepoint 等PS3 局部阴影src/dev_ng/game/shaders/ShaderLib.cpp:305-315
waterreflection、waterreflectionalphaclip、waterreflectionalphacliptint水反射阶段src/dev_ng/game/shaders/ShaderLib.cpp:317-320 / src/dev_ng/game/renderer/RenderPhases/RenderPhaseWaterReflection.cpp:277-278
cube、cubeinst反射立方体图src/dev_ng/game/shaders/ShaderLib.cpp:322-326
alt0…alt8水体(水下低/高、环境、单 pass、泡沫、水高度等,注释给出对应关系)src/dev_ng/game/shaders/ShaderLib.cpp:328-337 / src/dev_ng/game/renderer/Water.cpp:2620-2634
lightweight0/4/8(+CutOut、CutOutTint、NoCapsule、HighQuality*、*WaterRefractionAlpha)前向光照(半透明、轻量路径)src/dev_ng/game/shaders/ShaderLib.cpp:339-389 / src/dev_ng/game/renderer/Lights/lights.cpp:1321-1322
imposter、imposterdeferred树替身、河流雾src/dev_ng/game/shaders/ShaderLib.cpp:361-363 / src/dev_ng/game/renderer/TreeImposters.cpp:218-221
deferredbsped 混合形状变体src/dev_ng/game/shaders/ShaderLib.cpp:370-371 / src/dev_ng/game/Peds/rendering/PedVariationStream.cpp:309
deferred、deferredalphaclip、deferredsubsamplealphaclip、deferredalphacliptint、deferredsubsamplealpha、deferredsubsamplewritealpha、deferredcutscene、deferredsubsamplealphatintGBuffer 写入的各种镂空/SSA/过场变体src/dev_ng/game/shaders/ShaderLib.cpp:373-381 / src/dev_ng/game/renderer/Deferred/DeferredLighting.cpp:569-577
seethrough、ui、entityselect、applydamage、clouddepth、debugoverlay热成像、UI、调试拾取、车辆损伤写入、光线云深度、调试叠加src/dev_ng/game/shaders/ShaderLib.cpp:391-413

工作方式:阶段在渲染线程上设置“强制 technique group”(例如头像/UI 3D 用 SetForcedTechniqueGroupId(FindTechniqueGroupId("deferred"))src/dev_ng/game/renderer/UI3DDrawManager.cpp:1765,drawlist 管理器维护强制 technique 栈 PushForcedTechnique/PopForcedTechnique),随后同一个材质着色器绘制时选择该 group 对应的 technique;ExecuteListAtAddr 结束时断言强制 group 已复位(见 drawlist 页 §2.1)。若某着色器没有该 group 的 technique,则不会以该 group 绘制(推断:依据 03 页对 grmShader technique 选择的描述,本页未复核引擎回退逻辑)。

4. CShaderLib:全局常量、材质 ID 与状态#

CShaderLib 是渲染线程使用的静态工具类,主要内容:

功能API(节选)证据
初始化PreInit(注册 group、加载首批着色器)、Init、LoadAllShaders、InitTxdsrc/dev_ng/game/shaders/ShaderLib.h:77-89
每次绘制的全局值SetGlobals(natAmb, artAmb, setAlpha, alpha, setStipple, invertStipple, stippleAlpha, dontWriteDepth, dontReadDepth, dontWriteColor)、SetScreenDoorAlpha、SetGlobalAlpha、SetAlphaTestRef、SetGlobalEmissiveScale、SetGlobalArtificial/NaturalAmbientScale、SetGlobalInInterior、SetGlobalToneMapScalerssrc/dev_ng/game/shaders/ShaderLib.h:95-129
雾、昼夜、湿度、反射、运动模糊掩码SetGlobalFogParams/Colors、ApplyDayNightBalance、SetGlobalDynamicBakeBoostAndWetness、SetGlobalReflectionCamDirAndEmissiveMult、Begin/EndMotionBlurMasksrc/dev_ng/game/shaders/ShaderLib.h:141-171
延迟材质 ID(写入模板)SetGlobalDeferredMaterial(material, force)src/dev_ng/game/shaders/ShaderLib.h:173

延迟材质 ID(模板位):低 3 位是材质类型(DEFERRED_MATERIAL_TYPE_MASK = 0x7,DEFERRED_MATERIAL_CLEAR = 7),高位为可叠加标志:INTERIOR = 8、SPECIALBIT = 16(预处理区域)、SPAREOR1 = 32(方向光之前用作 MSAA 边缘标志,之后用于水坑与场景灯;也用作本地玩家车辆徽标)、SPAREOR2 = 64、MOTIONBLUR = 128 src/dev_ng/game/shaders/ShaderLib.h:32-52。实体绘制时由 EntityDraw 调用 SetGlobalDeferredMaterial(matID, …) 写入(见 drawlist 页 §6.1),光照 pass 再以模板测试挑选像素(deferred-lighting-and-shadows.md §1)。

着色器变量缓存:globalScalars(x=全局 alpha,y=HDR 倍数,z=环境缩放)等以 ThreadVector4 ms_gCurrentScalarGlobals[NUMBER_OF_RENDER_THREADS] 与整数镜像 ms_giCurrentScalarGlobals[…][4] 按渲染线程保存 src/dev_ng/game/shaders/ShaderLib.cpp:95、src/dev_ng/game/shaders/ShaderLib.cpp:183-186;SetGlobals 只在值变化时才调用 SetScalarGlobalConstant(__DEV 可用 ms_gDisableShaderVarCaching 关闭缓存)src/dev_ng/game/shaders/ShaderLib.cpp:785-790;SetScalarGlobalConstant 更新当前线程的副本,若不是子渲染线程则同时更新所有线程的副本 src/dev_ng/game/shaders/ShaderLib.h:266-278。这表明主渲染线程设置的全局值被视为所有子渲染线程的初值(推断:由“非子线程写全部副本”的实现得出)。深度/颜色写入开关通过切换预建的状态块(如 ms_gNoDepthRead_DS/ms_gNoDepthWrite_DS)并保留当前模板参考值(材质 ID)实现 src/dev_ng/game/shaders/ShaderLib.cpp:767-779。

5. 自定义着色效果(CCustomShaderEffect*)#

5.1 问题与类型#

同一个模型(drawable)的不同实例需要不同的着色器参数:车漆颜色/涂装/灯光/损伤、ped 的皱纹/血迹/纹身/湿度、树的风动、道具色调等。RAGE 的 drawable 共享着色器组,因此游戏用“每实体一个参数对象 + 绘制前写入”的模式,即 Custom Shader Effect(CSE)。

eCSE_TYPE类触发条件(SetupForDrawable 中按着色器名查找)
CSE_ANIMUVCCustomShaderEffectAnimUV有 UV 动画字典的物体(ped/车辆禁止)
CSE_WEAPONCCustomShaderEffectWeapon使用 weapon_* 着色器
CSE_GRASSCCustomShaderEffectGrass使用 grass_batch* 着色器
CSE_PROPCCustomShaderEffectProp使用 normal_spec_wrinkle,或特定降落伞模型哈希 + normal_um(_tnt) 等
CSE_INTERIORCCustomShaderEffectInteriorDLC 内部着色器
CSE_TREECCustomShaderEffectTree树着色器(并检查是否含 _tnt)
CSE_CABLECCustomShaderEffectCable电缆着色器
CSE_MIRRORCCustomShaderEffectMirror镜面着色器
CSE_PEDCCustomShaderEffectPedmiType == MI_TYPE_PED
CSE_VEHICLECCustomShaderEffectVehiclemiType == MI_TYPE_VEHICLE
CSE_TINTCCustomShaderEffectTint色调调色板着色器(_tnt)

表证据:枚举 src/dev_ng/game/shaders/CustomShaderEffectBase.h:51-68;分派顺序与各分支 src/dev_ng/game/shaders/CustomShaderEffectBase.cpp:205-523(例如武器 src/dev_ng/game/shaders/CustomShaderEffectBase.cpp:245-268、草 src/dev_ng/game/shaders/CustomShaderEffectBase.cpp:274-289、道具 src/dev_ng/game/shaders/CustomShaderEffectBase.cpp:293-341、ped src/dev_ng/game/shaders/CustomShaderEffectBase.cpp:464-514、车辆 src/dev_ng/game/shaders/CustomShaderEffectBase.cpp:520-523);各类声明 CustomShaderEffect{AnimUV,Interior,Cable,Mirror,Grass,Ped,Prop,Tint,Tree,Vehicle,Weapon}.h。非 ped/车辆专用的 CSE 在 ped/车辆模型上出现会触发 “ArtError” 断言。CSE_TINT 的具体分派分支本页未逐行确认(列于表中是依据枚举与类存在)。

5.2 两级结构与生命周期#

  • 类型(master):CCustomShaderEffectBaseType : fwCustomShaderEffectBaseType,每个模型信息一个,带引用计数;SetupForDrawable(pDrawable, miType, pMI, …) 在 CBaseModelInfo::SetDrawable() 时调用,按上表创建具体类型并 Initialise(查找 shader var 索引),失败返回 NULL;另有 SetupMasterForModelInfo、SetupMasterVehicleHDInfo(车辆 HD 模型)src/dev_ng/game/shaders/CustomShaderEffectBase.h:74-103。类型对象在 Initialise 中把变量名解析成紧凑索引,例如 ped 类型以 u8 m_idVar* 保存漫反射调色板、皱纹掩码强度 0–5、汗/脂肪环境效果、血迹/纹身目标、损伤数据、湿衣数据、胡茬等(PedShaderGroupLookupVar/PedEffectLookupGlobalVar)src/dev_ng/game/shaders/CustomShaderEffectPed.h:48-79、src/dev_ng/game/shaders/CustomShaderEffectPed.cpp:217-285。
  • 实例:CCustomShaderEffectBase : fwCustomShaderEffect,由 CreateInstance(CEntity*) 为每个实体创建(CEntityDrawHandler::ShaderEffectCreateInstance,src/dev_ng/game/renderer/Entities/EntityDrawHandler.h:195)。接口:SetShaderVariables(rmcDrawable*)(渲染线程,绘制前写变量)、AddToDrawList(modelIndex, bExecute)(主线程,在 BeforeAddToDrawList 中把自身拷入 drawlist)、AddToDrawListAfterDraw、AddDataForPrototype(供原型批写入每实例数据)、实例化支持 WriteInstanceData/GetNumRegistersPerInstance/HasPerBatchShaderVars/AddBatchRenderStateToDrawList src/dev_ng/game/shaders/CustomShaderEffectBase.h:109-146。

5.3 跨线程:CSE 如何进入 drawlist#

CCustomShaderEffectDC 记录一个 DrawListAddress m_shaderOffset(CSE 的二进制拷贝位置)、模型索引、m_bExecute、m_bDoubleBuffered、m_bBrokenOffPart 等位域 src/dev_ng/game/renderer/DrawLists/drawList.h:630-662。拷贝由 CopyOffShader 完成:同一帧内同一 CSE 只拷贝一次(DL_MEMTYPE_SHADER 共享数据),双缓冲的 CSE 放入 DPT_LIFETIME_RENDER_THREAD 页(PS3 为 DPT_LIFETIME_GPU),并对 CSE 类型加引用、登记到 drawlist 管理器,在 fence 轮换后释放 src/dev_ng/game/renderer/DrawLists/drawList.cpp:241-283。源码注释承认“calling a virtual on a binary copy of an object”有风险 src/dev_ng/game/renderer/DrawLists/drawList.cpp:275——渲染线程实际在 drawlist 中的按位拷贝上调用虚函数 SetShaderVariables,因此 CSE 类必须可按位拷贝、不得持有需要析构的资源。车辆 CSE 还按渲染线程索引保存类型指针(m_pType[g_RenderThreadIndex])以支持子渲染线程 src/dev_ng/game/shaders/CustomShaderEffectVehicle.h:214-216。

5.4 代表性内容#

  • 车辆:车灯亮度表 m_fLightDimmer[light]、损伤开关/损伤纹理/包围半径/损伤倍率、前轮损伤偏移、涂装(livery)及第二涂装、自定义主/副颜色、断裂部件标志 src/dev_ng/game/shaders/CustomShaderEffectVehicle.h:204-271。
  • 树:风动微运动参数(低/高风、风速软钳制、水下过渡、仅 alpha 卡片刚度、三角波基函数等)由 parser 反射结构定义,可数据驱动 src/dev_ng/game/shaders/CustomShaderEffectTree.psc:1-44;TREES_ENABLE_BRANCH_BEND_AND_TRI_WAVE_MICRO_MOVEMENTS 时 CCustomShaderEffectTree::Init() 在 CRenderer::Init 中调用 src/dev_ng/game/renderer/Renderer.cpp:560-562。原型批对 CSE_TREE 有专门原型 g_TreePrototype(见 pipeline 页 §5.5)。
  • 电缆:DrawScene 在 Hybrid Alpha 前后调用 CCustomShaderEffectCable::UpdateWindParams/SwitchDrawCore src/dev_ng/game/renderer/RenderPhases/RenderPhaseStd.cpp:1865-1878。
  • 草:CCustomShaderEffectGrass::IntersectsScriptFlattenAABB 用于剔除与脚本“压平区域”相交的树/草 src/dev_ng/game/renderer/Entities/EntityDrawHandler.cpp:921-925。

6. 其他辅助#

文件作用证据
CustomDrawableShaderVar.*“在 drawable 的着色器中成组设置变量”的小工具(注释:CLONED_EFFECTS=0 时有用)src/dev_ng/game/shaders/CustomDrawableShaderVar.h:1-8
ShaderHairSort.*对使用头发着色器的几何体排序的蒙皮头发渲染器src/dev_ng/game/shaders/ShaderHairSort.h:1-10
ShaderEdit.*bank 着色器编辑器(CShaderEdit:全局纹理加载、强制应用、纹理查看器集成)src/dev_ng/game/shaders/ShaderEdit.h:32-78、src/dev_ng/game/renderer/Renderer.cpp:524-525
renderer/Util/ShaderUtil.*ShaderUtil::StartShader/EndShader、投影参数计算、UpsampleHelpersrc/dev_ng/game/renderer/Deferred/DeferredLighting.cpp:3159-3163、src/dev_ng/game/renderer/Lights/TiledLighting.cpp:774

7. 约束与边界行为#

  1. technique group 必须在着色器加载前注册,否则已加载 effect 中的 technique 无法映射到 group(PreInit 注释)。新增 group 需同时修改 CShaderLib::PreInit 与各着色器中的 technique 命名。
  2. 新增着色器需加入 shaders_20xx.vcxproj(与 .filters)并重新构建所有平台变体;运行时由预载列表加载,assert 构建中 LoadAllShaders 之后加载新着色器会断言。
  3. MSAA:需要读多重采样目标的着色器要提供 MS/MS0 包装;C++ 侧按 MultisampleMode 选择。
  4. CSE 的按位拷贝语义:CSE 被 sysMemCpy 拷入命令缓冲并在副本上调用虚函数;新增 CSE 字段必须是 POD 或在 AddKnownRefs/RemoveKnownRefs 中显式管理引用。
  5. 美术约束:ped/车辆不得使用 AnimUV/武器/草/道具/内部/树/电缆/镜面专用着色器(断言 “ArtError”)。

8. 未决问题 / 证据不足#

  • Vehicles(54 个 .fx)、Terrain(33 个)、Peds 着色器内部未阅读;megashader 后缀含义是归纳推断。
  • CSE_TINT 与 CSE_INTERIOR 的分派分支、CCustomShaderEffectTint/Prop/Weapon/Mirror/Interior/AnimUV 的参数内容未展开。
  • 引擎在材质缺少当前 group 的 technique 时的回退行为未在本页复核(依赖 03 页)。
  • 游戏使用的预载列表(preload/preloadMS)内容不在源码树中,未能核对实际预载集合。