donmccurdy/glTF-Transform

Vertex color space conversion command

zeux opened this issue · 4 comments

zeux commented

According to glTF specification, vertex colors are stored in linear space: KhronosGroup/glTF#1638

However, some assets in the wild use sRGB color space. This is particularly a problem for Sketchfab point clouds, since it looks like Sketchfab exporter assumes vertex colors are sRGB, and for point clouds the rendered result uses vertex colors directly so the error is very evident.

It would be nice if there was a way to fix this with glTF-Transform. This is motivated by me having to fix it with a one-off program for KhronosGroup/glTF-Sample-Assets#31.

The goal would be to be able to take glTF file from here, and display it correctly in three.js / Babylon.js after running the command.
https://sketchfab.com/3d-models/flower-point-cloud-photogrammetry-13a409d10f154d5dbfd009fe75d52222

Would a script to run on https://gltf.report work for you? This should fix the colors:

import { vertexColorSpace } from '@gltf-transform/functions';

await document.transform(vertexColorSpace({ inputColorSpace: 'srgb' }));

It isn't a command in the CLI currently, because I felt like this was a rare issue, but if that's not been your experience then I'd be open to including it.

zeux commented

Ah, nice! I didn't realize this is available as a transform since it wasn't exposed as a CLI argument.

I'm personally fine with running a script but I do want to point out that as far as I can tell, all or nearly all point cloud assets downloaded from Sketchfab use sRGB colors so they will need fixup for use within the rest of glTF ecosystem. Up to you whether to include a tool based on this; I think for non-point clouds this is probably a much more rare issue indeed.

zeux commented

By the way, maybe I'm doing something wrong but while the transform itself works (at least in node), it doesn't seem to work in gltf.report in Chrome.

Here's the code that I can run via node and it works without issues:

import { Document, NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import { vertexColorSpace } from '@gltf-transform/functions';

// Configure I/O.
const io = new NodeIO()
    .registerExtensions(ALL_EXTENSIONS)

// Read from URL.
const document = await io.read('sketchfab/pointcloud/flower_point_cloud_photogrammetry.glb');

await document.transform(vertexColorSpace({ inputColorSpace: 'srgb' }));

const glb = await io.write('flower.glb', document);

This converts from the incorrect color space:

image

To the correct color space:

image

However, if I run the two-line snippet inside gltf.report after loading the original scene (attached), the visual output doesn't change and pressing "Export" and then loading the resulting .glb file in gltf-viewer also shows the scene with incorrect color space.

I haven't used gltf.report scripting functionality before so maybe I just am not pressing the right button somewhere.

flower_point_cloud_photogrammetry.zip

Hmmm that is a bug, thanks! The viewer does change detection, attempting to avoid pushing extra data to the undo stack, and seems to miss this. Adding some other trivial call to a setter at the end of the script, like below, would register the change and update the export.

import { vertexColorSpace } from '@gltf-transform/functions';

await document.transform(vertexColorSpace({ inputColorSpace: 'srgb' }));

// force change detection 🙃
const material = document.getRoot().listMaterials()[0];
material.setAlphaMode('OPAQUE');