Files
HelloVulkan/Engine/include/Engine/Renderer/Material.h
T
atdunbg beba491bcb 阶段性合并:动画重定向、碎裂共享库、第三人称玩法、编辑器面板与 vendored ufbx
- 动画:HumanoidRig 三层架构(standard 标准槽 / dialects 方言映射 / mapper 配对),
  指/趾统一走世界增量两遍式烘焙;AnimationAttach 拆为纯算法 + facade;修正 HumanoidBasis
  行走基朝向与跨骨架去重、根运动通道
- 物理:CharacterController 角色互碰撞 / shapeOffset / 接触事件;PhysicsWorld 接触合成与
  字符冲量判定
- 渲染与材质:Model 多材质按材质拆子 mesh 与贴图路径解析、DDS 直传、GLB 内嵌纹理落盘、
  不透明通道 alpha 固定 1.0、glTF FlipUVs 对齐;SceneSerializer 支持 meshIndex 与材质覆盖
- 脚本:FractureLib 抽为共享库(HostView 桥接)、WallFracture 参数直绑、新增
  ThirdPersonCamera / Follower / WASDMove 玩法;移除 GameDirector / PlayerController / Target
- 编辑器:新增 GamepadPanel、LogPanel(LogRing),改进 Inspector / 材质 / 统计 / 视口面板
- 依赖:vendored ufbx(FBX 5.x/6.x/7.x 全版本解析,替代 assimp 对 FBX 6.1 的拒读)
2026-10-11 22:22:19 +08:00

162 lines
8.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// Created by atdunbg on 2026/9/21.
//
// Material:PBR 材质 = 纹理槽组 + 因子参数 UBO + 一个描述符集。
//
// 槽位(binding = 槽位序号,与 simple_shader.frag 契约一致):
// 0 albedo(BaseColor,sRGB) 1 normal(切线空间法线,线性)
// 2 metallicRoughness(线性:G=粗糙度,B=金属度,glTF 约定)
// 3 emissive(自发光,sRGB) 4 ao(环境光遮蔽,线性)
// 5 roughness(独立粗糙度图,R 通道——FBX/OBJ specular 工作流,
// glTF 合图工作流不用此槽)
// 6 材质参数 UBO(fragment,kParamsBinding)
//
// 纹理非拥有(Model 的纹理缓存持有);缺槽由调用方传默认纹理。
// 因子(metallicFactor/roughnessFactor)乘在贴图上:
// glTF(MR 合图 B=金属度语义)→ 因子取 glTF 声明(默认 1/1),
// factors.z=0 → shader 直接读 MR.g 当粗糙度
// FBX(metalness 独立图 + roughness 独立图)→ metal 图落 MR 槽
// (灰度 R=G=B,.b 读金属度恰好正确),roughness 图落 Roughness
// 槽,factors.z=1 → shader 用 Roughness.r 替换 MR.g
// OBJ(specular 工作流)→ metallic=0,独立 roughness 图同 FBX;
// 无图时 roughness 因子按 Ns 换算
//
#ifndef HELLOVULKAN_MATERIAL_H
#define HELLOVULKAN_MATERIAL_H
#include <Engine/Core/Types.h>
#include <Engine/Core/FrameContext.h>
#include <glm/glm.hpp>
#include <vulkan/vulkan.hpp>
#include <array>
#include <string>
namespace Engine {
class Device;
class MemoryAllocator;
class DescriptorManager;
class Texture;
class UniformBuffer;
// 材质因子(乘贴图;无贴图时即最终值)
// x = metallic 因子 y = roughness 因子
// z = 独立粗糙度图开关(1 = 用 Roughness 槽 R 通道替换 MR.g)
// 注意:与 shader MaterialParams UBO 严格同序同布局(全 vec4,std140
// 无填充歧义),加字段必须双端同步(simple_shader*.frag)
struct MaterialParams {
// x = metallic 因子,y = roughness 因子,z = 独立粗糙度图开关,w = MASK 镂空开关
// 默认 = 电介质表面推荐值(Unity/UE 同款):
// metallic = 0 皮肤/头发/布料等非金属的正确值
// roughness = 1.0 因子语义是"乘贴图",1.0 = 贴图值直用(同 glTF
// roughnessFactor 缺省);配合兜底 MR 纹理 G=128
// 得 effective roughness ≈ 0.5,不再是 ×0.5 后的
// 0.25 假高光(ufbx 路径不写 factors,全靠这里兜底)
glm::vec4 factors{0.0f, 1.0f, 0.0f, 0.0f};
// glTF baseColorFactor:rgb 乘进 albedo,a 作 BLEND 透明度
glm::vec4 baseColor{1.0f, 1.0f, 1.0f, 1.0f};
// glTF 表面扩展(KHR_materials_ior / transmission / volume /
// emissive_strength):x = 折射率(F0 = ((ior-1)/(ior+1))²),
// y = 透射率(0 = 普通表面),z = 自发光强度,w = 体积厚度
//(折射屏幕偏移的世界距离,0 = 无弯曲直透)
glm::vec4 surface{1.5f, 0.0f, 1.0f, 0.0f};
// 杂项语义:
// x = unlit(KHR_materials_unlit,shader 早退直出 albedo)
// y = UV 左右镜像(u → 1-u,1 = 开启)
// z = UV 上下镜像(v → 1-v,1 = 开启)
// w = 保留
// 镜像作用于材质全部纹理槽,叠加在每槽 UV 变换(uvA/uvT)之后:
// 用于纠正源资产 UV 朝向(部分角色 rip 的 UV 与 glTF 上左原点
// 约定相反,贴图整体翻转)。材质级语义,非单槽
glm::vec4 misc{0.0f, 0.0f, 0.0f, 0.0f};
// glTF emissiveFactor:自发光颜色(rgb;黑 = 不发光)。emissive
// 槽默认兜底纹理是纯黑,无贴图时 Emissive Strength 乘出来恒黑
// ——无贴图想要发光就调这里(rgb × 贴图 × surface.z)
glm::vec4 emissiveFactor{0.0f, 0.0f, 0.0f, 0.0f};
// 每槽 KHR_texture_transform(glTF2 每个 textureInfo 独立声明
// offset/scale/rotation——烘焙单份顶点 UV 无法表达"一材质多槽
// 各异变换",收敛为 shader 侧线性式 uv' = A·uv + t,作用在 glTF
// 规范 UV 空间(v=0 = 图像顶);顶点 UV 经 aiProcess_FlipUVs 已
// 归一至该空间,A/t 即规范式 off + R(rot)·S(scale)·uv 的摊平,
// 换算推导见 Model.cpp glTF 分支注释)。
// uvA[slot] = (a11, a12, a21, a22)(行主 2×2),uvT[slot] = (tx, ty, 0, 0)。
// 长度必须 = Material::kSlotCount;std140 vec4 数组步长 16B 与
// CPU 布局天然对齐
glm::vec4 uvA[6] = {{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}};
glm::vec4 uvT[6] = {};
// albedo 贴图 alpha 作细节叠加遮罩(脸部腮红/卧蚕等局部效果):
// rgb = 叠加色(与 baseColor 同款直乘/直用,不做空间换算),
// a = 强度(0 = 关闭,mix 恒等无副作用)。alpha 遮罩来自贴图本身,
// 无 alpha 或 alpha 恒 1 的贴图开启后即等效整体染色
glm::vec4 alphaOverlay{0.0f, 0.0f, 0.0f, 0.0f};
};
class Material {
public:
// 槽位序号(与 binding 对齐)
enum Slot : u32 {
Albedo = 0,
Normal = 1,
MetallicRoughness = 2,
Emissive = 3,
Ao = 4,
Roughness = 5, // 独立粗糙度图(R 通道)
kSlotCount = 6, // 纹理槽数
kParamsBinding = 6, // 参数 UBO binding
};
Material(Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout layout,
const std::array<Texture*, kSlotCount>& textures,
const MaterialParams& params,
bool transparent = false);
~Material();
Material(const Material&) = delete;
Material& operator=(const Material&) = delete;
vk::DescriptorSet GetDescriptorSet() const { return m_DescriptorSet; }
Texture* GetTexture(Slot slot) const { return m_Textures[slot]; }
// 透明队列归属(glTF alphaMode=BLEND;CPU 收集侧用)
bool IsTransparent() const { return m_Transparent; }
// ---- 编辑器调参入口(零 GPU 重建路径)----
// 参数直写:全 in-flight 槽同步覆盖写,与 ctor 初始化同一绑定
// 语义(binding 覆盖写,ring 槽位共用同一 descriptor binding)。
// 理论上存在 in-flight 帧读到半新半旧参数的撕裂窗口(动态偏移
// ring 是根治演进点)——UI 段低频编辑 + 48B 小块 memcpy 下实践
// 无感。纹理槽变化不走这里(那是重建路径,见 MaterialAsset)。
// 实现外置(UniformBuffer 头文件内仅前置声明)
void UpdateParams(const MaterialParams& params);
// 队列归属切换(收集侧 CPU 标志,描述符不变):透明 ↔ 不透明
void SetTransparent(bool t) { m_Transparent = t; }
// 材质缓存键:同贴图组合+同因子+同透明语义共享一份(Model 层使用)
static std::string MakeCacheKey(const std::string paths[kSlotCount],
const MaterialParams& params,
bool transparent);
// ---- 预览缩略图身份(editor tile 池的缓存键,game 不消费)----
// serial:出生唯一号(进程内单调递增,不复用)——裸指针做键有
// ABA 风险(旧材质析构后新材质恰好分配到同一地址,池误判命中)
u64 GetSerial() const { return m_Serial; }
// editVersion:参数编辑代数,UpdateParams 每次 ++
//(tile 池以此判定"缓存的球已过期需重渲")
u32 GetEditVersion() const { return m_EditVersion; }
private:
std::array<Texture*, kSlotCount> m_Textures{};
vk::DescriptorSet m_DescriptorSet;
Scope<UniformBuffer> m_ParamsBuffer; // per-slot 参数 ring(创建时写死)
bool m_Transparent = false;
u64 m_Serial = 0; // ctor 取号(定义见 Material.cpp)
u32 m_EditVersion = 0;
};
} // namespace Engine
#endif //HELLOVULKAN_MATERIAL_H