NFX & SURF Format NFX & SURF 格式
File Format Overview文件格式概览
NeoX separates material definition into two declarative file formats that work together with HLSL code:
NeoX 将材质定义分为两种声明式文件格式,与 HLSL 代码配合工作:
| Format格式 | Purpose用途 | Syntax语法 |
|---|---|---|
| .nfx | Render technique definition (pass structure, entry points)渲染技法定义(Pass 结构、入口点) | Custom declarative syntax自定义声明式语法 |
| .surf | Material properties descriptor (lighting model, resources, macros)材质属性描述符(光照模型、资源、宏) | XML |
| .hlsl | Shader code implementation着色器代码实现 | HLSL dialectHLSL 方言 |
NFX Format — Render Technique DeclarationNFX 格式 — 渲染技法声明
NFX (NeoX Effect) files declare rendering techniques without writing shader code. They specify:
NFX(NeoX Effect)文件声明渲染技法而无需编写着色器代码。它们指定:
- Technique/Pass structure: How many render passes, what their names are
- Technique/Pass 结构:多少个渲染 Pass、它们的名称
- Shader entry points: Which
.vs/.psfiles to use, what functions to call - Shader 入口点:使用哪些
.vs/.ps文件、调用什么函数 - Resource bindings: Texture slots, samplers, constant parameters
- 资源绑定:纹理槽位、采样器、常量参数
- Metadata: Author, category, description (for editor UI)
- 元数据:作者、分类、描述(用于编辑器 UI)
Example: common_nolight.nfx示例:common_nolight.nfx
// res/shader/common_nolight.nfx string SasUiLabel = "Common NoLight"; string SasUiCategory = "Basic"; string SasUiCompany = "NetEase"; string SasUiDescription = "Basic unlit shader"; // Texture declaration texture Tex0 < string SasUiLabel = "Base Texture"; >; sampler2D Tex0Sampler = sampler_state { Texture = <Tex0>; SamplerFilter[0] = FILTER_TRILINEAR; AddressU[0] = WRAP; AddressV[0] = WRAP; }; // Constant parameters float Brightness < string SasUiLabel = "Brightness"; string SasUiControl = "Slider"; float SasUiMin = 0.0; float SasUiMax = 2.0; > = 1.0; // Technique definition technique TShader { pass p0 { VertexShader = "common_nolight.vs" es300 vs_main; PixelShader = "common_nolight.ps" es300 ps_main; } }
es300 token specifies OpenGL ES 3.0 as the target platform. For D3D11, the engine uses the .hlsl source directly. The vs_main and ps_main are the actual function names in the compiled shader files.
关键洞察:es300 标记指定 OpenGL ES 3.0 为目标平台。对于 D3D11,引擎直接使用 .hlsl 源码。vs_main 和 ps_main 是编译后着色器文件中的实际函数名。
SURF Format — Material Properties DescriptorSURF 格式 — 材质属性描述符
SURF (Surface) files are XML descriptors that define material properties without hardcoding them in shader code. They act as a bridge between artist-facing material parameters and engine-side rendering.
SURF(Surface)文件是 XML 描述符,定义材质属性而无需在着色器代码中硬编码。 它们充当面向美术师的材质参数与引擎端渲染之间的桥梁。
SURF StructureSURF 结构
<!-- res/shader/built_in/surf/default.surf --> <NeoX> <Surface> <!-- 1. Lighting Model Selection --> <LightingModel DefaultName="Isotropy" ConfigurableList="Isotropy" /> <!-- 2. Shader Code Reference --> <Code File="shader\built_in\materials\default.hlsl" /> <!-- 3. Macro Switches --> <Macro> <Item Name="LIGHT_ENABLE" DefaultValue="1" /> <Item Name="EMISSIVE_TEXTURE" DefaultValue="0" /> <Item Name="NORMAL_MAP_ENABLE" DefaultValue="0" /> </Macro> <!-- 4. Resource Bindings --> <Resources> <Texture Slot="0" Name="Tex0" Label="Albedo" SamplerState="Trilinear_Wrap" /> <Texture Slot="1" Name="Tex1" Label="Normal Map" SamplerState="Trilinear_Wrap" /> <Parameter Name="BaseColor" Type="Float4" Default="1,1,1,1" Label="Base Color" /> </Resources> <!-- 5. Render State --> <RasterizerAndBlend BlendMode="OPAQUE" CullMode="Back" /> </Surface> </NeoX>
SURF Key ComponentsSURF 关键组件
| Component组件 | Purpose用途 | Example Values示例值 |
|---|---|---|
| LightingModel | Determines shading model决定着色模型 | Isotropy, Skin, Hair, ClearCoat, Toon, SSSS |
| Code | Points to HLSL implementation指向 HLSL 实现 | shader\built_in\materials\default.hlsl |
| Macro | Feature switches功能开关 | LIGHT_ENABLE, ALPHA_TEST_ENABLE |
| Resources | Texture slots & parameters纹理槽位 & 参数 | Tex0=Albedo, Tex1=Normal, BaseColor |
| RasterizerAndBlend | Render states渲染状态 | OPAQUE, TRANSPARENT, ADDITIVE |
Material Pipeline — How They Work Together材质管线 — 它们如何协同工作
The three file types form a complete material definition:
三种文件类型形成完整的材质定义:
+----------------------------------------------------------+ | 1. Artist creates .surf file (or selects existing one) | | v Chooses LightingModel: Isotropy | | v Enables macros: NORMAL_MAP_ENABLE=1 | | v Assigns textures: Tex0=albedo.png, Tex1=normal.png | +----------------------------------------------------------+ v +----------------------------------------------------------+ | 2. Engine reads .surf --> loads referenced .hlsl file | | File="shader\built_in\materials\default.hlsl" | +----------------------------------------------------------+ v +----------------------------------------------------------+ | 3. .hlsl file implements material functions: | | float3 GetAlbedo(RawData data) { ... } | | float3 GetNormal(RawData data) { ... } | | #if NORMAL_MAP_ENABLE --> decode normal map | +----------------------------------------------------------+ v +----------------------------------------------------------+ | 4. Rendering pipeline calls via .nfx: | | technique TShader { | | pass p0 { | | VertexShader = "default.vs" es300 vs_main; | | PixelShader = "default.ps" es300 ps_main; | | } | | } | +----------------------------------------------------------+
Example Walkthrough — Building a Custom Material实例演练 — 构建自定义材质
Let's trace how a custom "glowing emissive" material is defined:
让我们追踪一个自定义"发光自发光"材质是如何定义的:
Step 1: Create SURF file步骤 1:创建 SURF 文件
<!-- res/shader/custom/glowing.surf --> <NeoX> <Surface> <LightingModel DefaultName="Unlit" /> <Code File="shader\custom\glowing.hlsl" /> <Macro> <Item Name="EMISSIVE_TEXTURE" DefaultValue="1" /> <Item Name="PULSE_ANIMATION" DefaultValue="1" /> </Macro> <Resources> <Texture Slot="0" Name="Tex0" Label="Emissive Map" /> <Parameter Name="GlowIntensity" Type="Float" Default="2.0" /> <Parameter Name="PulseSpeed" Type="Float" Default="1.0" /> </Resources> <RasterizerAndBlend BlendMode="ADDITIVE" CullMode="None" /> </Surface> </NeoX>
Step 2: Implement HLSL shader步骤 2:实现 HLSL 着色器
// res/shader/custom/glowing.hlsl #include "../built_in/materials/material_common.hlsl" Texture2D Tex0 : register(t0); SamplerState Tex0Sampler : Trilinear_Wrap; float GlowIntensity; float PulseSpeed; float Time; // Injected by engine float3 GetEmissive(RawData data) { float3 emissive = Tex0.Sample(Tex0Sampler, data.uv0).rgb; #if PULSE_ANIMATION float pulse = sin(Time * PulseSpeed) * 0.5 + 0.5; emissive *= pulse; #endif return emissive * GlowIntensity; }
Step 3: Reference in NFX (or use existing)步骤 3:在 NFX 中引用(或使用现有)
Most materials reuse existing NFX files like common_nolight.nfx. The engine's material system
automatically routes the SURF-defined shader code to the appropriate rendering pass.
大多数材质重用现有 NFX 文件如 common_nolight.nfx。引擎的材质系统
自动将 SURF 定义的着色器代码路由到相应的渲染 Pass。
File Locations — Where to Find Them文件位置 — 在哪里找到它们
- res/shader/*.nfxRoot-level NFX files (~30 files)根级 NFX 文件(~30 个文件)
- res/shader/built_in/surf/Built-in SURF descriptors (~120 files)内置 SURF 描述符(~120 个文件)
- res/shader/built_in/materials/Material HLSL implementations (~22 files)材质 HLSL 实现(~22 个文件)
- res/shader/macro_define.xmlGlobal macro enumeration全局宏枚举
- res/shader/built_in/forward_shading.renderRendering pipeline declaration (XML)渲染管线声明(XML)