材质与环境光照: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:
@@ -211,6 +211,15 @@ void MaterialEditorPanel::DrawAssetMode(const EditorContext& ctx)
|
|||||||
if (c) { p.misc.z = flipV ? 1.0f : 0.0f; }
|
if (c) { p.misc.z = flipV ? 1.0f : 0.0f; }
|
||||||
EditParam(c);
|
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 重建)----
|
// ---- 纹理槽(变化 → 落盘 + waitIdle 重建)----
|
||||||
ImGui::SeparatorText("Textures");
|
ImGui::SeparatorText("Textures");
|
||||||
|
|||||||
@@ -288,12 +288,45 @@ namespace {
|
|||||||
dst.texPaths[Material::Albedo] =
|
dst.texPaths[Material::Albedo] =
|
||||||
ResolveUfbxTexture(modelDir, *base.texture);
|
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(
|
ENGINE_INFO(
|
||||||
"ufbx Mesh '{}': Material '{}': albedo={}", dst.name,
|
"ufbx Mesh '{}': Material '{}': albedo={} mr={} normal={} ao={} emissive={}",
|
||||||
mat->name.length ? U8Str(mat->name) : "?",
|
dst.name, mat->name.length ? U8Str(mat->name) : "?",
|
||||||
dst.texPaths[Material::Albedo].empty()
|
dst.texPaths[Material::Albedo].empty()
|
||||||
? "<none>"
|
? "<none>" : dst.texPaths[Material::Albedo],
|
||||||
: 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;
|
std::unordered_map<std::string, u32> boneSlots;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ layout(set = 1, binding = 6) uniform MaterialParams {
|
|||||||
vec4 factors; // x = metallic 因子,y = roughness 因子,z = 独立粗糙度图开关,w = MASK 镂空开关
|
vec4 factors; // x = metallic 因子,y = roughness 因子,z = 独立粗糙度图开关,w = MASK 镂空开关
|
||||||
vec4 baseColor; // glTF baseColorFactor:rgb 调色 albedo,a = BLEND 透明度
|
vec4 baseColor; // glTF baseColorFactor:rgb 调色 albedo,a = BLEND 透明度
|
||||||
vec4 surface; // x = ior(F0 换算),y = transmission(不透明段恒 0 语义),z = 自发光强度,w = 体积厚度
|
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 emissiveFactor; // 自发光颜色(rgb × emissiveMap × surface.z;黑 = 不发光)
|
||||||
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
|
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
|
||||||
vec4 uvT[6]; // 每槽 UV 平移 (tx, ty, 0, 0)
|
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 nT = normalize(T - N * dot(N, T)); // 正交化
|
||||||
vec3 B = cross(N, nT);
|
vec3 B = cross(N, nT);
|
||||||
vec3 sampled = texture(normalMap, uv).xyz * 2.0 - 1.0;
|
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;
|
if (dot(sampled, sampled) < 1e-4) return geomN;
|
||||||
|
|
||||||
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
|
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
|
||||||
@@ -257,17 +259,21 @@ void main() {
|
|||||||
|
|
||||||
vec3 irradiance = texture(irradianceMap, N).rgb;
|
vec3 irradiance = texture(irradianceMap, N).rgb;
|
||||||
float ao = texture(aoMap, ApplyUv(4, fragUV)).r;
|
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);
|
vec3 R = reflect(-V, N);
|
||||||
const float kMaxPrefilterMip = 4.0; // 与 Cubemap::kPrefilterMips - 1 同步
|
const float kMaxPrefilterMip = 4.0; // 与 Cubemap::kPrefilterMips - 1 同步
|
||||||
vec3 prefilteredColor = textureLod(prefilteredMap, R,
|
vec3 prefilteredColor = textureLod(prefilteredMap, R,
|
||||||
roughness * kMaxPrefilterMip).rgb;
|
roughness * kMaxPrefilterMip).rgb;
|
||||||
vec2 envBRDF = texture(brdfLut, vec2(NdotV, roughness)).rg;
|
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
|
vec3 ambient = (diffuse + specular) * ubo.ambientColor.rgb;
|
||||||
* mix(0.4, 1.0, shade0); // 阴影区环境同步衰减(简化遮蔽)
|
|
||||||
|
|
||||||
// 不透明段覆盖率恒 1:本 pass 只画 alphaMode=OPAQUE/MASK 表面,像素必
|
// 不透明段覆盖率恒 1:本 pass 只画 alphaMode=OPAQUE/MASK 表面,像素必
|
||||||
// 被完全覆盖。绝不能拿 albedo 贴图 alpha 当覆盖率——HI3/Genshin 脸部
|
// 被完全覆盖。绝不能拿 albedo 贴图 alpha 当覆盖率——HI3/Genshin 脸部
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ layout(set = 1, binding = 6) uniform MaterialParams {
|
|||||||
vec4 factors; // x = metallic 因子,y = roughness 因子,z = 独立粗糙度图开关,w = MASK 镂空开关
|
vec4 factors; // x = metallic 因子,y = roughness 因子,z = 独立粗糙度图开关,w = MASK 镂空开关
|
||||||
vec4 baseColor; // glTF baseColorFactor:rgb 调色 albedo,a = BLEND 透明度
|
vec4 baseColor; // glTF baseColorFactor:rgb 调色 albedo,a = BLEND 透明度
|
||||||
vec4 surface; // x = ior,y = transmission(KHR_materials_transmission),z = 自发光强度,w = 体积厚度
|
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 emissiveFactor; // 自发光颜色(rgb × emissiveMap × surface.z;黑 = 不发光)
|
||||||
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
|
vec4 uvA[6]; // 每槽 UV 线性变换(KHR_texture_transform,v-up 空间)(a11,a12,a21,a22),槽序 = binding
|
||||||
vec4 uvT[6]; // 每槽 UV 平移 (tx, ty, 0, 0)
|
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 nT = normalize(T - N * dot(N, T)); // 正交化
|
||||||
vec3 B = cross(N, nT);
|
vec3 B = cross(N, nT);
|
||||||
vec3 sampled = texture(normalMap, uv).xyz * 2.0 - 1.0;
|
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;
|
if (dot(sampled, sampled) < 1e-4) return geomN;
|
||||||
|
|
||||||
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
|
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
|
||||||
|
|||||||
Reference in New Issue
Block a user