ADD: Normal mapping

This commit is contained in:
2025-11-01 17:32:14 +09:00
parent d5ff6263ee
commit fbc937974d
28 changed files with 2802 additions and 264 deletions

View File

@@ -20,4 +20,8 @@
- Materials & sRGB
- See `docs/asset_manager.md` for mesh/material creation and sRGB/UNORM handling.
- Conventions:
- Albedo/base color → sRGB
- Metallic-Roughness → UNORM (G=roughness, B=metallic)
- Normal map → UNORM (+Y green up)

View File

@@ -32,6 +32,11 @@
- Thirdparty deps
- Vendored under `third_party/` and brought in via CMake. Do not edit headers directly; update through targets.
- Optional: MikkTSpace tangents
- Enable at configure time: `-DENABLE_MIKKTS=ON` (default ON if found).
- Requires `third_party/MikkTSpace/mikktspace.c` and `mikktspace.h` (provided).
- Disable to use the builtin GramSchmidt generator: `-DENABLE_MIKKTS=OFF`.
- Validation Layers
- Enabled in Debug (`kUseValidationLayers = true` in `src/core/config.h`).
- Disable by building Release or toggling the flag during local experimentation.

View File

@@ -18,6 +18,12 @@
- Name SPIRV files with full extension, e.g. `fullscreen.vert.spv`, `deferred_lighting.frag.spv`.
- Use `EngineContext::getAssets()->shaderPath("<name>.spv")` when registering pipelines.
- Use sRGB formats for albedo textures and UNORM for PBR control textures (see `docs/asset_manager.md`).
- Material UBO layout (`GLTFMaterialData`):
- `vec4 colorFactors;`
- `vec4 metal_rough_factors; // x = metallic, y = roughness`
- `vec4 extra[14]; // extra[0].x = normalScale`
- Material texture bindings (set=1):
- binding=1 `colorTex`, binding=2 `metalRoughTex`, binding=3 `normalMap`.
- Adding a pipeline (graphics)
- Fill `GraphicsPipelineCreateInfo` with shader paths, descriptor set layouts, optional push constants, and a `configure(PipelineBuilder&)` callback to set topology, raster, depth/blend, and attachment formats.

View File

@@ -24,3 +24,13 @@
- Confirm the `.spv` file changed (timestamp) and click “Reload Changed” in the Pipelines window.
- Ensure you are editing the correct files referenced by `shaderPath()`.
- GLSL error: `no such field in structure 'materialData': extra`
- Ensure `shaders/input_structures.glsl` defines `vec4 extra[14];` inside `GLTFMaterialData` to match C++ `MaterialConstants`.
- Normals look inverted when using normal maps
- The engine expects +Y (green up) tangent-space normals. Flip the green channel in your texture if needed.
- Tangent seams or artifacts
- Build with MikkTSpace enabled: `-DENABLE_MIKKTS=ON`.
- Check that your mesh has non-degenerate UVs.

View File

@@ -40,9 +40,11 @@ Use either the convenience descriptor (`MeshCreateInfo`) or the direct overload
struct AssetManager::MaterialOptions {
std::string albedoPath; // resolved through AssetManager
std::string metalRoughPath; // resolved through AssetManager
std::string normalPath; // resolved through AssetManager (tangent-space normal)
bool albedoSRGB = true; // VK_FORMAT_R8G8B8A8_SRGB when true
bool metalRoughSRGB = false; // VK_FORMAT_R8G8B8A8_UNORM when false
GLTFMetallic_Roughness::MaterialConstants constants{};
bool normalSRGB = false; // normal maps should be UNORM
GLTFMetallic_Roughness::MaterialConstants constants{}; // extra[0].x as normalScale
MaterialPass pass = MaterialPass::MainColor; // or Transparent
};
@@ -113,7 +115,7 @@ ctx->scene->addMeshInstance("sphere.instance", sphere,
glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, -2.f)));
```
Textured primitive (albedo + metal-rough):
Textured primitive (albedo + metal-rough + normal):
```c++
AssetManager::MeshCreateInfo ti{};
@@ -124,7 +126,9 @@ ti.geometry.vertices = std::span<Vertex>(v.data(), v.size());
ti.geometry.indices = std::span<uint32_t>(i.data(), i.size());
ti.material.kind = AssetManager::MeshMaterialDesc::Kind::Textured;
ti.material.options.albedoPath = "textures/ground_albedo.png"; // sRGB
ti.material.options.metalRoughPath = "textures/ground_mr.png"; // UNORM
ti.material.options.metalRoughPath = "textures/ground_mr.png"; // UNORM, G=roughness, B=metallic
ti.material.options.normalPath = "textures/ground_n.png"; // UNORM
ti.material.options.constants.extra[0].x = 1.0f; // normalScale
// ti.material.options.pass = MaterialPass::Transparent; // optional
auto texturedPlane = ctx->getAssets()->createMesh(ti);
@@ -156,4 +160,5 @@ ctx->scene->removeGLTFInstance("chair01");
- Reuse by name: `createMesh("name", ...)` returns the cached mesh if it already exists. Use a unique name or call `removeMesh(name)` to replace.
- sRGB/UNORM: Albedo is sRGB by default, metal-rough is UNORM by default. Adjust via `MaterialOptions`.
- Hot reload: Shaders are resolved via `shaderPath()`; pipeline hot reload is handled by the pipeline manager, not the AssetManager.
- Normal maps: Not wired into the default GLTF PBR material in this branch. Adding them would require descriptor and shader updates.
- Normal maps: Supported. If `normalPath` is empty, a flat normal is used.
- Tangents: Loaded from glTF when present; otherwise generated. Enable MikkTSpace at configure time with `-DENABLE_MIKKTS=ON`.

43
docs/materials.md Normal file
View File

@@ -0,0 +1,43 @@
Materials and Textures Overview (PBR)
Current state (as of Nov 1, 2025)
- PBR textures bound per material (set=1):
- binding=0: GLTFMaterialData (UBO)
- binding=1: `colorTex` (albedo/base color) — sRGB
- binding=2: `metalRoughTex` (G=roughness, B=metallic) — UNORM
- binding=3: `normalMap` (tangent-space normal, UNORM)
- GBuffer writes worldspace normals. Tangentspace normal maps are decoded with TBN using a signcorrect bitangent (B = sign * cross(N, T)).
- Numeric fallbacks via `MaterialConstants` (CPU) / `GLTFMaterialData` (GPU):
- `colorFactors` (RGBA). Defaults to 1 if zero.
- `metal_rough_factors` (X=metallic, Y=roughness). Roughness is clamped to ≥ 0.04 in shaders.
- `extra[0].x` = `normalScale` (scalar, default 1.0). Multiplies the XY of decoded normal.
- Defaults when a texture is missing:
- Albedo → checkerboard error texture
- MR → white (no effect)
- Normal → 1×1 flat normal (0.5, 0.5, 1.0)
Implications for primitive meshes
- Primitives can use:
- Albedo + MR + Normal textures, or
- Numeric factors only, or
- Any mix (missing textures fall back to defaults).
Texture conventions
- Albedo/base color: sRGB.
- Metallic-Roughness: UNORM; channels: G=roughness, B=metallic.
- Normal map: UNORM; expected +Y (green up). If your maps look inverted, flip the green channel offline.
Notes on tangent space
- Tangents are loaded from glTF when present (`TANGENT` attribute, vec4 where w is handedness).
- If missing, the engine generates tangents:
- Default: robust GramSchmidt with handedness.
- Preferred: MikkTSpace (enabled by CMake option `ENABLE_MIKKTS=ON`).
Notes on MikkTSpace
- Recommended for parity with content tools. Enable at configure time: `-DENABLE_MIKKTS=ON`.
- Falls back automatically to the internal generator if disabled or if MikkTS fails.
Usage Examples
- Adjust normal strength per material: set `material.constants.extra[0].x` (CPU) or `normalTexture.scale` in glTF.
- Primitive with PBR textures:
- Set `MeshMaterialDesc::Kind::Textured` and fill `albedoPath`, `metalRoughPath`, and `normalPath`.