From 1201480d4a9c7843f8d632103ecd67884d00586b Mon Sep 17 00:00:00 2001 From: Youssef Fellah Date: Fri, 1 May 2026 20:13:11 +0100 Subject: [PATCH 1/3] Implement glTF COLOR_0 vertex color support in StandardMaterial and UnlitMaterial --- assets/scene_renderer/shaders/DebugMaterial.hlsl | 4 ++++ .../scene_renderer/shaders/MaterialInterface.hlsli | 1 + assets/scene_renderer/shaders/MaterialVertex.hlsl | 2 ++ .../scene_renderer/shaders/StandardMaterial.hlsl | 2 ++ assets/scene_renderer/shaders/UnlitMaterial.hlsl | 2 ++ src/ppx/scene/scene_gltf_loader.cpp | 14 +++++++++++++- 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/assets/scene_renderer/shaders/DebugMaterial.hlsl b/assets/scene_renderer/shaders/DebugMaterial.hlsl index 6da4ac730..f3e70e803 100644 --- a/assets/scene_renderer/shaders/DebugMaterial.hlsl +++ b/assets/scene_renderer/shaders/DebugMaterial.hlsl @@ -15,6 +15,7 @@ #define ENABLE_VTX_ATTR_TEXCOORD #define ENABLE_VTX_ATTR_NORMAL #define ENABLE_VTX_ATTR_TANGENT +#define ENABLE_VTX_ATTR_COLOR #include "MaterialInterface.hlsli" @@ -35,6 +36,9 @@ float4 psmain(StandardVertexOutput input) : SV_TARGET else if(Draw.dbgVtxAttrIndex == DBG_VTX_ATTR_INDEX_TANGENT) { color = mul(Instances[Draw.instanceIndex].modelMatrix, float4(input.Tangent.xyz, 0)).xyz; } + else if(Draw.dbgVtxAttrIndex == DBG_VTX_ATTR_INDEX_COLOR) { + color = input.Color; + } return float4(normalize(color), 1); } diff --git a/assets/scene_renderer/shaders/MaterialInterface.hlsli b/assets/scene_renderer/shaders/MaterialInterface.hlsli index ec13860aa..ca7ee03de 100644 --- a/assets/scene_renderer/shaders/MaterialInterface.hlsli +++ b/assets/scene_renderer/shaders/MaterialInterface.hlsli @@ -65,6 +65,7 @@ struct DrawParams { #define DBG_VTX_ATTR_INDEX_TEXCOORD 1 #define DBG_VTX_ATTR_INDEX_NORMAL 2 #define DBG_VTX_ATTR_INDEX_TANGENT 3 +#define DBG_VTX_ATTR_INDEX_COLOR 4 #if defined(__spirv__) [[vk::push_constant]] diff --git a/assets/scene_renderer/shaders/MaterialVertex.hlsl b/assets/scene_renderer/shaders/MaterialVertex.hlsl index aa6721fd9..0689d3a54 100644 --- a/assets/scene_renderer/shaders/MaterialVertex.hlsl +++ b/assets/scene_renderer/shaders/MaterialVertex.hlsl @@ -15,6 +15,7 @@ #define ENABLE_VTX_ATTR_TEXCOORD #define ENABLE_VTX_ATTR_NORMAL #define ENABLE_VTX_ATTR_TANGENT +#define ENABLE_VTX_ATTR_COLOR #include "MaterialInterface.hlsli" StandardVertexOutput vsmain(StandardVertexInput input) @@ -29,5 +30,6 @@ StandardVertexOutput vsmain(StandardVertexInput input) output.TexCoord = input.TexCoord; output.Normal = input.Normal; output.Tangent = input.Tangent; + output.Color = input.Color; return output; } diff --git a/assets/scene_renderer/shaders/StandardMaterial.hlsl b/assets/scene_renderer/shaders/StandardMaterial.hlsl index edac55784..ba74f6aaf 100644 --- a/assets/scene_renderer/shaders/StandardMaterial.hlsl +++ b/assets/scene_renderer/shaders/StandardMaterial.hlsl @@ -15,6 +15,7 @@ #define ENABLE_VTX_ATTR_TEXCOORD #define ENABLE_VTX_ATTR_NORMAL #define ENABLE_VTX_ATTR_TANGENT +#define ENABLE_VTX_ATTR_COLOR #include "MaterialInterface.hlsli" #include "ppx/PBR.hlsli" @@ -46,6 +47,7 @@ float4 psmain(StandardVertexOutput input) : SV_TARGET baseColor = baseColor * float4(RemoveGamma(color.rgb, 2.2), color.a); } + baseColor.rgb *= input.Color; // Metal/roughness float metallic = material.metallicFactor; diff --git a/assets/scene_renderer/shaders/UnlitMaterial.hlsl b/assets/scene_renderer/shaders/UnlitMaterial.hlsl index 2bd011f2c..fce849686 100644 --- a/assets/scene_renderer/shaders/UnlitMaterial.hlsl +++ b/assets/scene_renderer/shaders/UnlitMaterial.hlsl @@ -15,6 +15,7 @@ #define ENABLE_VTX_ATTR_TEXCOORD #define ENABLE_VTX_ATTR_NORMAL #define ENABLE_VTX_ATTR_TANGENT +#define ENABLE_VTX_ATTR_COLOR #include "MaterialInterface.hlsli" // ------------------------------------------------------------------------------------------------- @@ -38,6 +39,7 @@ float4 psmain(StandardVertexOutput input) : SV_TARGET float4 value = tex.Sample(sam, uv); color = color * value; } + color.rgb *= input.Color; return color; } diff --git a/src/ppx/scene/scene_gltf_loader.cpp b/src/ppx/scene/scene_gltf_loader.cpp index cae41664c..bb038f4c0 100644 --- a/src/ppx/scene/scene_gltf_loader.cpp +++ b/src/ppx/scene/scene_gltf_loader.cpp @@ -1658,12 +1658,24 @@ ppx::Result GltfLoader::LoadMeshData( std::vector colors; if (loadParams.requiredVertexAttributes.bits.colors && !IsNull(gltflAccessors.pColors)) { PPX_ASSERT_MSG((colorFormat == targetColorFormat), "GLTF: vertex colors format is not supported"); - colors = UnpackFloat3s(*gltflAccessors.pColors); + if (gltflAccessors.pColors->type == cgltf_type_vec3) { + colors = UnpackFloat3s(*gltflAccessors.pColors); + } + else if (gltflAccessors.pColors->type == cgltf_type_vec4) { + auto colors4 = UnpackFloat4s(*gltflAccessors.pColors); + for (auto& c : colors4) { + colors.push_back(glm::float3(c.r, c.g, c.b)); + } + } + else { + PPX_ASSERT_MSG(false, "GLTF: vertex colors format must be VEC3 or VEC4"); + } } // Process vertex data for (cgltf_size i = 0; i < gltflAccessors.pPositions->count; ++i) { TriMeshVertexData vertexData = {}; + vertexData.color = glm::float3(1, 1, 1); vertexData.position = positions[i]; if (loadParams.requiredVertexAttributes.bits.normals && !normals.empty()) { From 15f09acf4c03b50252203d66f474a816d86484f1 Mon Sep 17 00:00:00 2001 From: Fellah Youssef Date: Wed, 20 May 2026 16:32:18 +0100 Subject: [PATCH 2/3] Fix formatting of vertexData color assignment --- src/ppx/scene/scene_gltf_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ppx/scene/scene_gltf_loader.cpp b/src/ppx/scene/scene_gltf_loader.cpp index bb038f4c0..a77460282 100644 --- a/src/ppx/scene/scene_gltf_loader.cpp +++ b/src/ppx/scene/scene_gltf_loader.cpp @@ -1675,7 +1675,7 @@ ppx::Result GltfLoader::LoadMeshData( // Process vertex data for (cgltf_size i = 0; i < gltflAccessors.pPositions->count; ++i) { TriMeshVertexData vertexData = {}; - vertexData.color = glm::float3(1, 1, 1); + vertexData.color = glm::float3(1, 1, 1); vertexData.position = positions[i]; if (loadParams.requiredVertexAttributes.bits.normals && !normals.empty()) { From 8ac0562ed0ffea59f5394eb15ea1fd3652fecd8e Mon Sep 17 00:00:00 2001 From: Youssef Fellah Date: Mon, 31 Aug 2026 20:08:34 +0100 Subject: [PATCH 3/3] Enable glTF COLOR_0 vertex colors in the scene loader Address the Vulkan validation error reported when running vk_gltf_basic_materials: the scene-renderer pipeline is built from the shared MaterialVertex vertex shader which (with vertex color support) declares an input at Location 4, but the loader was still forcing `bits.colors = false`, so the pipeline never received a matching vertex attribute description. - Stop disabling vertex colors in GltfLoader::LoadMeshInternal so the material-requested COLOR_0 attribute (Location 4) is actually loaded. - Drop the overly strict color-format assert in LoadMeshData. COLOR_0 is valid as VEC3/VEC4 with float or normalized component types; the unpack helpers already convert components to floats via cgltf_accessor_unpack_floats. - Request vertex colors from UnlitMaterial since its shader now multiplies the base color by input.Color. - clang-format-16 pass over the changed sources. --- src/ppx/scene/scene_gltf_loader.cpp | 12 ++++-------- src/ppx/scene/scene_material.cpp | 1 + 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ppx/scene/scene_gltf_loader.cpp b/src/ppx/scene/scene_gltf_loader.cpp index a77460282..fd8c20664 100644 --- a/src/ppx/scene/scene_gltf_loader.cpp +++ b/src/ppx/scene/scene_gltf_loader.cpp @@ -1635,7 +1635,6 @@ ppx::Result GltfLoader::LoadMeshData( auto texCoordFormat = GetFormat(gltflAccessors.pTexCoords); auto normalFormat = GetFormat(gltflAccessors.pNormals); auto tangentFormat = GetFormat(gltflAccessors.pTangents); - auto colorFormat = GetFormat(gltflAccessors.pColors); PPX_ASSERT_MSG((positionFormat == targetPositionFormat), "GLTF: vertex positions format is not supported"); auto positions = UnpackFloat3s(*gltflAccessors.pPositions); @@ -1657,7 +1656,9 @@ ppx::Result GltfLoader::LoadMeshData( } std::vector colors; if (loadParams.requiredVertexAttributes.bits.colors && !IsNull(gltflAccessors.pColors)) { - PPX_ASSERT_MSG((colorFormat == targetColorFormat), "GLTF: vertex colors format is not supported"); + // COLOR_0 can be VEC3 or VEC4 with a float or normalized component type. The + // unpack functions (via cgltf_accessor_unpack_floats) convert the components to + // floats, so the exact accessor format does not need to be checked here. if (gltflAccessors.pColors->type == cgltf_type_vec3) { colors = UnpackFloat3s(*gltflAccessors.pColors); } @@ -1675,7 +1676,7 @@ ppx::Result GltfLoader::LoadMeshData( // Process vertex data for (cgltf_size i = 0; i < gltflAccessors.pPositions->count; ++i) { TriMeshVertexData vertexData = {}; - vertexData.color = glm::float3(1, 1, 1); + vertexData.color = glm::float3(1, 1, 1); vertexData.position = positions[i]; if (loadParams.requiredVertexAttributes.bits.normals && !normals.empty()) { @@ -1909,11 +1910,6 @@ ppx::Result GltfLoader::LoadMeshInternal( localLoadParams.requiredVertexAttributes = externalLoadParams.requiredVertexAttributes; } - // - // Disable vertex colors for now: some work is needed to handle format conversion. - // - localLoadParams.requiredVertexAttributes.bits.colors = false; - // Load mesh data and batches scene::MeshDataRef meshData = nullptr; std::vector batches = {}; diff --git a/src/ppx/scene/scene_material.cpp b/src/ppx/scene/scene_material.cpp index 6d01169ed..f6b880a4a 100644 --- a/src/ppx/scene/scene_material.cpp +++ b/src/ppx/scene/scene_material.cpp @@ -118,6 +118,7 @@ scene::VertexAttributeFlags UnlitMaterial::GetRequiredVertexAttributes() const { scene::VertexAttributeFlags attrFlags = scene::VertexAttributeFlags::None(); attrFlags.bits.texCoords = true; + attrFlags.bits.colors = true; return attrFlags; }