材质与环境光照:UE 打包 Specular 导入(R=AO/G=Rough/B=Metal 与 glTF MR 同序 → 同一贴图直供 MetallicRoughness + Ao 槽,factors 直用贴图,默认置翻绿位 misc.w);MappedNormal 支持 DirectX 法线翻绿(misc.w,编辑器加 Flip Green 开关);环境遮蔽拆分漫反射与高光(高光遮蔽更狠:室内高光须压暗,此前表面反射天空贴图 = 室内穿帮);ufbx 导入日志补齐 mr/normal/ao/emissive 槽位

This commit is contained in:
2026-10-18 15:23:07 +08:00
parent e7711134fe
commit 22309d24f0
4 changed files with 60 additions and 10 deletions
@@ -211,6 +211,15 @@ void MaterialEditorPanel::DrawAssetMode(const EditorContext& ctx)
if (c) { p.misc.z = flipV ? 1.0f : 0.0f; }
EditParam(c);
}
ImGui::SameLine();
{
// DirectX 法线绿通道翻转(UE 打包 Specular 资产由导入器默认为开;
// 方向反了在此逐材质纠正)。写 misc.w,旧 .material 缺省 0 = 关闭
bool flipG = p.misc.w > 0.5f;
const bool c = ImGui::Checkbox("Flip Green (DirectX)", &flipG);
if (c) { p.misc.w = flipG ? 1.0f : 0.0f; }
EditParam(c);
}
// ---- 纹理槽(变化 → 落盘 + waitIdle 重建)----
ImGui::SeparatorText("Textures");
+37 -4
View File
@@ -288,12 +288,45 @@ namespace {
dst.texPaths[Material::Albedo] =
ResolveUfbxTexture(modelDir, *base.texture);
}
// UE/ORCA 打包 Specular 工作流:R=AO, G=Roughness, B=Metalness。
// 通道与 glTF MR 合图(G=rough, B=metal)恰好同序 → 同一张贴图
// 直供 MetallicRoughness 槽 + Ao 槽,纹理缓存按路径去重共享同一
// Texture*。factors=(1,1,0,0):金属/粗糙因子直用贴图(z=0 → shader
// 读 MR.g 当粗糙度,同 glTF 语义)。UE 打包 Specular ⇔ DirectX
// 法线(同源约定)→ 默认置翻绿位 misc.w
if (const ufbx_material_map& spec = mat->pbr.specular_color;
spec.texture != nullptr) {
const std::string p =
ResolveUfbxTexture(modelDir, *spec.texture);
dst.texPaths[Material::MetallicRoughness] = p;
dst.texPaths[Material::Ao] = p;
dst.params.factors = glm::vec4(1.0f, 1.0f, 0.0f, 0.0f);
dst.params.misc.w = 1.0f;
}
if (const ufbx_material_map& nrm = mat->pbr.normal_map;
nrm.texture != nullptr) {
dst.texPaths[Material::Normal] =
ResolveUfbxTexture(modelDir, *nrm.texture);
}
if (const ufbx_material_map& emi = mat->pbr.emission_color;
emi.texture != nullptr) {
dst.texPaths[Material::Emissive] =
ResolveUfbxTexture(modelDir, *emi.texture);
}
ENGINE_INFO(
"ufbx Mesh '{}': Material '{}': albedo={}", dst.name,
mat->name.length ? U8Str(mat->name) : "?",
"ufbx Mesh '{}': Material '{}': albedo={} mr={} normal={} ao={} emissive={}",
dst.name, mat->name.length ? U8Str(mat->name) : "?",
dst.texPaths[Material::Albedo].empty()
? "<none>"
: dst.texPaths[Material::Albedo]);
? "<none>" : dst.texPaths[Material::Albedo],
dst.texPaths[Material::MetallicRoughness].empty()
? "<none>" : dst.texPaths[Material::MetallicRoughness],
dst.texPaths[Material::Normal].empty()
? "<none>" : dst.texPaths[Material::Normal],
dst.texPaths[Material::Ao].empty()
? "<none>" : dst.texPaths[Material::Ao],
dst.texPaths[Material::Emissive].empty()
? "<none>" : dst.texPaths[Material::Emissive]);
};
std::unordered_map<std::string, u32> boneSlots;
+11 -5
View File
@@ -45,7 +45,7 @@ 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),y = UV 左右镜像,z = UV 上下镜像
vec4 misc; // x = unlit(KHR_materials_unlit,1 = 早退直出 albedo),y = UV 左右镜像,z = UV 上下镜像,w = 法线绿通道翻转(DirectX)
vec4 emissiveFactor; // 自发光颜色(rgb × emissiveMap × surface.z;黑 = 不发光)
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
vec4 uvT[6]; // 每槽 UV 平移 (tx, ty, 0, 0)
@@ -124,6 +124,8 @@ vec3 MappedNormal(vec3 geomN, vec3 T, vec2 uv) {
vec3 nT = normalize(T - N * dot(N, T)); // 正交化
vec3 B = cross(N, nT);
vec3 sampled = texture(normalMap, uv).xyz * 2.0 - 1.0;
// DirectX 法线(绿通道朝下)→ OpenGL:翻绿。UE 打包 Specular 资产默认开
if (matParams.misc.w > 0.5) sampled.y = -sampled.y;
if (dot(sampled, sampled) < 1e-4) return geomN;
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
@@ -257,17 +259,21 @@ void main() {
vec3 irradiance = texture(irradianceMap, N).rgb;
float ao = texture(aoMap, ApplyUv(4, fragUV)).r;
vec3 diffuse = kD_amb * irradiance * albedo * ao;
// 漫反射环境遮蔽:材料 AO × 阴影软化(较温和,保留阴影内可读性)
float diffOcc = ao * mix(0.4, 1.0, shade0);
vec3 diffuse = kD_amb * irradiance * albedo * diffOcc;
vec3 R = reflect(-V, N);
const float kMaxPrefilterMip = 4.0; // 与 Cubemap::kPrefilterMips - 1 同步
vec3 prefilteredColor = textureLod(prefilteredMap, R,
roughness * kMaxPrefilterMip).rgb;
vec2 envBRDF = texture(brdfLut, vec2(NdotV, roughness)).rg;
vec3 specular = prefilteredColor * (F_amb * envBRDF.x + envBRDF.y);
// 高光遮蔽(specular occlusion):比漫反射更狠——室内环境高光必须压暗,
// 否则室内表面反射出天空贴图(穿帮根因)
float specOcc = ao * mix(0.12, 1.0, shade0);
vec3 specular = prefilteredColor * (F_amb * envBRDF.x + envBRDF.y) * specOcc;
vec3 ambient = (diffuse + specular) * ubo.ambientColor.rgb
* mix(0.4, 1.0, shade0); // 阴影区环境同步衰减(简化遮蔽)
vec3 ambient = (diffuse + specular) * ubo.ambientColor.rgb;
// 不透明段覆盖率恒 1:本 pass 只画 alphaMode=OPAQUE/MASK 表面,像素必
// 被完全覆盖。绝不能拿 albedo 贴图 alpha 当覆盖率——HI3/Genshin 脸部
+3 -1
View File
@@ -45,7 +45,7 @@ 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,y = transmission(KHR_materials_transmission),z = 自发光强度,w = 体积厚度
vec4 misc; // x = unlit(透射材质不会是 unlit,仅为与 simple_shader 布局一致),y = UV 左右镜像,z = UV 上下镜像
vec4 misc; // x = unlit(透射材质不会是 unlit,仅为与 simple_shader 布局一致),y = UV 左右镜像,z = UV 上下镜像,w = 法线绿通道翻转(DirectX)
vec4 emissiveFactor; // 自发光颜色(rgb × emissiveMap × surface.z;黑 = 不发光)
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
vec4 uvT[6]; // 每槽 UV 平移 (tx, ty, 0, 0)
@@ -123,6 +123,8 @@ vec3 MappedNormal(vec3 geomN, vec3 T, vec2 uv) {
vec3 nT = normalize(T - N * dot(N, T)); // 正交化
vec3 B = cross(N, nT);
vec3 sampled = texture(normalMap, uv).xyz * 2.0 - 1.0;
// DirectX 法线(绿通道朝下)→ OpenGL:翻绿。UE 打包 Specular 资产默认开
if (matParams.misc.w > 0.5) sampled.y = -sampled.y;
if (dot(sampled, sampled) < 1e-4) return geomN;
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);