着色器与材质:game/shader_source、technique group、CShaderLib、自定义着色效果
本页解释 GTA V 游戏层的着色器体系:game/shader_source 中 .fx/.fxh 的组织方式(“megashader”按宏组合生成上百个材质着色器)、构建工具链与平台变体、technique 命名约定与 technique group(渲染阶段如何让同一个材质在 GBuffer/阴影/水反射/前向等场景下选用不同 technique)、CShaderLib 的全局着色器常量与状态缓存,以及按实体实例定制着色器参数的 CCustomShaderEffect* 系列(ped/车辆/树/草/道具/色调/武器/镜面/电缆/内部/UV 动画)。
背景与相关页面#
grcEffect/grmShader/grmShaderGroup、technique group 的引擎实现、shaderlib共享 HLSL、资源中着色器绑定与 effect 预加载由 ../03-rage-graphics/grcore-device-and-effects.md 与 ../03-rage-graphics/models-drawables-and-shaders.md 负责。- bucket/sub-bucket 与 draw mode 如何选择绘制哪些几何见 render-pipeline-and-phases.md §5;GBuffer 布局与延迟光照着色器族见 deferred-lighting-and-shadows.md。
- 着色器离线编译工具(
RAGEShaderManager)与tools_ng配置属于工具链,见 ../24-toolchain/asset-pipeline.md 与 ../00-overview/build-and-config.md。 - ped/车辆的变体与损伤系统(CSE 的数据来源)见 ../06-peds/ped-motion-and-rendering.md、../08-vehicles/vehicle-architecture.md。
相关源码文件#
| 文件 | 内容 |
|---|---|
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 | 代表文件 |
|---|---|---|---|
Megashader | 107 | 4 | default、normal_spec、normal_spec_detail_dpm_tnt、decal_*、emissive*、parallax*、cutout_fence*、weapon_*、cloth_*;头:megashader.fxh、megashader_deferredRS.fxh、detail_map.fxh、Puddle.fxh |
Vehicles | 54 | 2 | 车漆/轮胎/玻璃/车灯等(未逐一列出) |
Terrain | 33 | 4 | 地形混合(未逐一列出) |
Peds | 29 | 1 | ped、ped_default*、ped_wrinkle*、ped_hair_*、ped_fur、ped_decal*、ped_cloth*、ped_enveff |
Vegetation/Trees、Vegetation/Grass | 20、10 | 3、3 | trees_*(含 _tnt、camera_aligned/facing、lod/lod2、shadow_proxy)、grass_batch*、grass_fur* |
VFX | 20 | 6 | ptfx_*、ptxgpu_render/update、rmptfx_*、vfx_decal*、vfx_fogvolume、vfx_lightningStrike、golf_trail |
Water | 12 | 3 | water、water_river*、water_shallow、water_foam、water_fountain、water_poolenv、waterTex |
Custom(含 Glass/Mirror/Cable/Rope) | 11 + 17 | 1 | blend_2lyr、damage_blits、radar、rage_bink、skinblend、glass_*、mirror_* |
Lighting(含 Lights/Shadows/AO) | 9 + 12 + 9 + 6 | 4 + 6 + 5 + 1 | deferred_lighting、deferred_ambient、deferred_volume、tiled_lighting、point/spot/capsule/directional、cascadeshadows*、shadowZCM、SSAO、HDAO、HDAO2 |
PostFX | 10 | 4 | postfx、dofCompute、dofDiffusion、adaptiveDof、avgLuminanceCompute、exposureGPU、mlaa、DistortionWarp |
Sky(含 Clouds) | 1 + 8 | 1 | sky_system、clouds_* |
Util | 6 | 7 | im、imMS、scaleform_shaders、BlurCS、ClearCS、MemoryCS |
Debug | 7 | 13 | debug_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 >= 40 | src/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/Orbis | src/dev_ng/game/shader_source/common.fxh:238 |
SHADOW_CASTING_TECHNIQUES_OK | 依平台与着色器类型决定是否生成阴影 technique | src/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 -->处添加,并同步.filterssrc/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 |
deferredbs | ped 混合形状变体 | 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、deferredsubsamplealphatint | GBuffer 写入的各种镂空/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、InitTxd | src/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、SetGlobalToneMapScalers | src/dev_ng/game/shaders/ShaderLib.h:95-129 |
| 雾、昼夜、湿度、反射、运动模糊掩码 | SetGlobalFogParams/Colors、ApplyDayNightBalance、SetGlobalDynamicBakeBoostAndWetness、SetGlobalReflectionCamDirAndEmissiveMult、Begin/EndMotionBlurMask | src/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_ANIMUV | CCustomShaderEffectAnimUV | 有 UV 动画字典的物体(ped/车辆禁止) |
CSE_WEAPON | CCustomShaderEffectWeapon | 使用 weapon_* 着色器 |
CSE_GRASS | CCustomShaderEffectGrass | 使用 grass_batch* 着色器 |
CSE_PROP | CCustomShaderEffectProp | 使用 normal_spec_wrinkle,或特定降落伞模型哈希 + normal_um(_tnt) 等 |
CSE_INTERIOR | CCustomShaderEffectInterior | DLC 内部着色器 |
CSE_TREE | CCustomShaderEffectTree | 树着色器(并检查是否含 _tnt) |
CSE_CABLE | CCustomShaderEffectCable | 电缆着色器 |
CSE_MIRROR | CCustomShaderEffectMirror | 镜面着色器 |
CSE_PED | CCustomShaderEffectPed | miType == MI_TYPE_PED |
CSE_VEHICLE | CCustomShaderEffectVehicle | miType == MI_TYPE_VEHICLE |
CSE_TINT | CCustomShaderEffectTint | 色调调色板着色器(_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/AddBatchRenderStateToDrawListsrc/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/SwitchDrawCoresrc/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、投影参数计算、UpsampleHelper | src/dev_ng/game/renderer/Deferred/DeferredLighting.cpp:3159-3163、src/dev_ng/game/renderer/Lights/TiledLighting.cpp:774 |
7. 约束与边界行为#
- technique group 必须在着色器加载前注册,否则已加载 effect 中的 technique 无法映射到 group(
PreInit注释)。新增 group 需同时修改CShaderLib::PreInit与各着色器中的 technique 命名。 - 新增着色器需加入
shaders_20xx.vcxproj(与.filters)并重新构建所有平台变体;运行时由预载列表加载,assert 构建中LoadAllShaders之后加载新着色器会断言。 - MSAA:需要读多重采样目标的着色器要提供
MS/MS0包装;C++ 侧按MultisampleMode选择。 - CSE 的按位拷贝语义:CSE 被
sysMemCpy拷入命令缓冲并在副本上调用虚函数;新增 CSE 字段必须是 POD 或在AddKnownRefs/RemoveKnownRefs中显式管理引用。 - 美术约束: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)内容不在源码树中,未能核对实际预载集合。