Add animation controller system, material assets and skeleton visualization

- .animctrl state machine asset (params/transitions/blend trees, 1D+2D
  directional blending) with Unity Animator-style editor panel: state
  list, transitions, params, directional pad preview driving live
  CrossFade on the selected entity
- Split animation evaluation out of SceneRenderer into
  AnimationSystem/AnimationEvaluator; skin palettes with rest-pose
  fallback and blend-weight epsilon filtering
- MaterialAsset (.material) with reload-safe preview tile pool
  (DropMaterial clears dirty refs before instance destruction)
- EditorGizmoPass skeleton wires + viewport joint overlay; camera
  projection rework (baked Vulkan Y-flip, ortho support)
- Editor/game build split via HELLOVULKAN_EDITOR option
This commit is contained in:
2026-10-07 01:50:04 +08:00
parent a941207ae3
commit cc837bc605
71 changed files with 8198 additions and 548 deletions
+39 -7
View File
@@ -44,8 +44,21 @@ layout(set = 1, binding = 5) uniform sampler2D roughnessMap; // 独立粗糙度
layout(set = 1, binding = 6) uniform MaterialParams {
vec4 factors; // x = metallic 因子,y = roughness 因子,z = 独立粗糙度图开关,w = MASK 镂空开关
vec4 baseColor; // glTF baseColorFactor:rgb 调色 albedo,a = BLEND 透明度
vec4 surface; // x = ior(F0 换算),y = transmission(不透明段恒 0 语义),z = 自发光强度,w = 体积厚度
vec4 misc; // x = unlit(KHR_materials_unlit,1 = 早退直出 albedo)
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
vec4 uvT[6]; // 每槽 UV 平移 (tx, ty, 0, 0)
} matParams;
// 每槽 UV 变换:uv' = A·uv + t(identity 时退化为直通)。slot 必须
// 字面量调用点(编译期展开索引);6 = Material::kSlotCount
vec2 ApplyUv(int slot, vec2 uv) {
vec4 a = matParams.uvA[slot];
vec4 t = matParams.uvT[slot];
return vec2(a.x * uv.x + a.y * uv.y + t.x,
a.z * uv.x + a.w * uv.y + t.y);
}
// CSM 阴影(sampler2DShadow:单次采样 = 硬件 2×2 深度比较 PCF)
layout(set = 2, binding = 0) uniform sampler2DShadow shadowMap0; // CSM 级联 0(最近)
layout(set = 2, binding = 1) uniform sampler2DShadow shadowMap1; // 级联 1
@@ -136,23 +149,40 @@ vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {
}
void main() {
vec4 albedoTex = texture(albedoMap, fragUV);
vec4 albedoTex = texture(albedoMap, ApplyUv(0, fragUV));
// alphaMode=MASK 镂空(表针/栅栏等硬边贴图):低于阈值的纹素直接丢弃
if (matParams.factors.w > 0.5 && albedoTex.a < 0.5) discard;
vec3 albedo = albedoTex.rgb * matParams.baseColor.rgb;
vec4 mr = texture(metallicRoughnessMap, fragUV);
// KHR_materials_unlit:无光照语义(文字标签/示意图),albedo 直出
if (matParams.misc.x > 0.5) {
outColor = vec4(albedo, albedoTex.a * matParams.baseColor.a);
outVelocity = fragVelocity;
return;
}
vec4 mr = texture(metallicRoughnessMap, ApplyUv(2, fragUV));
// 粗糙度源按 factors.z 切换:glTF 合图工作流读 MR.g;
// FBX/OBJ specular 工作流(z=1)换用独立粗糙度图 R 通道
float roughness = clamp(mix(mr.g, texture(roughnessMap, fragUV).r,
float roughness = clamp(mix(mr.g, texture(roughnessMap, ApplyUv(5, fragUV)).r,
matParams.factors.z) * matParams.factors.y,
0.045, 1.0);
float metallic = clamp(mr.b * matParams.factors.x, 0.0, 1.0);
vec3 emissive = texture(emissiveMap, fragUV).rgb;
// 自发光强度(KHR_materials_emissive_strength,缺省 1)
vec3 emissive = texture(emissiveMap, ApplyUv(3, fragUV)).rgb * matParams.surface.z;
vec3 N = MappedNormal(normalize(fragNormal), fragTangent, fragUV);
vec3 N = MappedNormal(normalize(fragNormal), fragTangent, ApplyUv(1, fragUV));
vec3 V = normalize(ubo.cameraPos.xyz - fragWorldPos);
// 双面法线:cull 关闭 + glTF doubleSided=true,背面片元(表壳后盖/
// 内壁等从背面看到的表面)几何法线背向相机,NdotL≤0 → 直接光全灭、
// IBL 采错半球 = 纯黑壳(three.js DoubleSide 对背面自动翻法线,
// 这里对齐该语义;与 translucent shader 的翻转同款)
if (dot(N, V) < 0.0) N = -N;
float NdotV = max(dot(N, V), 1e-4);
vec3 F0 = mix(vec3(0.04), albedo, metallic); // 电介质基准反射率 4%
// F0 按折射率换算(KHR_materials_ior):((ior-1)/(ior+1))²;
// glTF 缺省 ior=1.5 → 0.04,与旧固定值一致
float ior = max(matParams.surface.x, 1.0);
vec3 F0 = mix(vec3((ior - 1.0) / (ior + 1.0)
* (ior - 1.0) / (ior + 1.0)),
albedo, metallic); // 电介质 F0 / 金属 albedo
vec3 Lo = vec3(0.0);
float shade0 = 1.0f; // 第 0 盏光的阴影因子(环境光同步衰减用)
@@ -213,7 +243,7 @@ void main() {
vec3 kD_amb = (1.0 - F_amb) * (1.0 - metallic);
vec3 irradiance = texture(irradianceMap, N).rgb;
float ao = texture(aoMap, fragUV).r;
float ao = texture(aoMap, ApplyUv(4, fragUV)).r;
vec3 diffuse = kD_amb * irradiance * albedo * ao;
vec3 R = reflect(-V, N);
@@ -229,5 +259,7 @@ void main() {
// alpha = albedo 贴图覆盖率 × baseColorFactor.a(glTF alphaMode=BLEND
// 混合源);不透明资产两者恒 1 行为不变。预乘在 tonemap 段完成。
outColor = vec4(ambient + Lo + emissive, albedoTex.a * matParams.baseColor.a);
// ==== DEBUG B1: 纯 albedo 直出(验证贴图绑定/UV 采样)====
// outColor = vec4(albedo, 1.0);
outVelocity = fragVelocity;
}