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)文件声明渲染技法而无需编写着色器代码。它们指定:

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;
  }
}
Key insight: The 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_mainps_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文件位置 — 在哪里找到它们