[SOLVED] Is this possible to extract materials from a GLB?

I know that the devs team are currently working to support GLTF in the editor.
Meanwhile, I’m looking to extract some materials from a GLB model and recreate them in the editor.

When we import an FBX in the editor, the editor extracts the materials automatically for us and generate “material” assets.

Is there a way to do that from a GLB? With some hacky code using the console maybe? By extracting the info when I load the GLB at runtime?

do you mean to extract materials, not shaders?

Oh yeah, I mean materials!

I just edited my post by changing “shaders” to “materials”.

I’m not sure there’s any way to do it at the moment. You can load glb at runtime and access materials there, but that won’t help you create assets from them.
Maybe you could source your asset in fbx format instead and import that?

The model I got is from Sketchfab and can only export in GLB with materials.

The thing is that the PLaycanvas engine can digest the GLB and generate these materials:
image

Leonidas gave me a script to generate a material asset from a Json here.

So from here, I’m close to what I want. I just need to extract the data to a json file at runtime and import that in the editor.

What’s the intention for having these materials in the Editor?

To make them easier to modify for 3D artists, duplicate them and change them a little for a product configurator. :slight_smile:

1 Like

so will you then assign them to loaded glb model using a script?

Exactly.

It’s not our first product configurator with Playcanvas and we already did that with FBX.

The challenge I got here is that the given source is a only GLB with a default visual. From there, I want to generate new materials (from the materials in the model) and give them to a 3D artist in the Playcanvas Editor.

Honestly, I can analyze the material in runtime from the GLB and get all the parameters to create by-hand new materials in the editor. But this will take me hours and there’s a lot of risk to enter a bad value and get a bad material. I’m looking to automate this task.

In theory, you can download a material asset JSON and work out what the asset attributes mapping to the runtime values and create your own JSON output from the GLB material array.

Yeah, that’s another solution.

I was hoping that, maybe, there was a script ready since you are working to integrate GLB into the editor. My guess is that you will extract these materials from a GLB when a user will import it into the editor, which is the current behavior with FBX.

1 Like

The solution won’t be something you be able to run yourself unfortunately. At this stage, outputing a large JSON string at runtime is your best bet.

1 Like

Alrigth! I will share my solution if I got something.

@yaustar: At this stage, outputing a large JSON string at runtime is your best bet.

I think I may got something. I still need to test it with more materials…

  1. In code, I create a clone of the desired material like this:
var mat2 = this.pc_entity.model.meshInstances[0].material.clone();
  1. I remove all parameters related to maps, meshInstances and chunks, because this generate big or strange values. In this case, this material was linked with a diffuse map and an opacity map:
mat2.meshInstances = null;
mat2._diffuseMap = null;
mat2._opacityMap = null;
mat2._chunks = null;
  1. I print the Json in string format into the console like this:
console.log(JSON.stringify(mat2));
  1. Based on Leonidas trick from here, I can copy paste the string from my console and recopy that in the console in the editor and generate a new material.

  2. I have a new material in my project!

What do you think of this?

I think you will need to write your own mapping. If you download a material JSON from the Editor, you can see the properties and formats are different (eg look at the diffuse color attribute:

{
    "ambient": [0, 0, 0],
    "ambientTint": false,
    "aoMapChannel": "r",
    "aoMapUv": 0,
    "aoMapTiling": [1, 1],
    "aoMapOffset": [0, 0],
    "diffuse": [1, 1, 1],
    "diffuseMapChannel": "rgb",
    "diffuseMapUv": 0,
    "diffuseMapTiling": [1, 1],
    "diffuseMapOffset": [0, 0],
    "specular": [0.23, 0.23, 0.23],
    "specularMapChannel": "rgb",
    "specularMapUv": 0,
    "specularMapTiling": [1, 1],
    "specularMapOffset": [0, 0],
    "specularAntialias": true,
    "occludeSpecular": 1,
    "useMetalness": false,
    "metalness": 1,
    "metalnessMapChannel": "r",
    "metalnessMapUv": 0,
    "metalnessMapTiling": [1, 1],
    "metalnessMapOffset": [0, 0],
    "conserveEnergy": true,
    "shininess": 32,
    "glossMapChannel": "r",
    "glossMapUv": 0,
    "glossMapTiling": [1, 1],
    "glossMapOffset": [0, 0],
    "fresnelModel": 0,
    "emissive": [0, 0, 0],
    "emissiveMapChannel": "rgb",
    "emissiveMapUv": 0,
    "emissiveMapTiling": [1, 1],
    "emissiveMapOffset": [0, 0],
    "emissiveIntensity": 1,
    "normalMapTiling": [1, 1],
    "normalMapOffset": [0, 0],
    "normalMapUv": 0,
    "bumpMapFactor": 1,
    "heightMapChannel": "r",
    "heightMapUv": 0,
    "heightMapTiling": [1, 1],
    "heightMapOffset": [0, 0],
    "heightMapFactor": 1,
    "alphaToCoverage": false,
    "alphaTest": 0,
    "opacity": 1,
    "opacityMapChannel": "r",
    "opacityMapUv": 0,
    "opacityMapTiling": [1, 1],
    "opacityMapOffset": [0, 0],
    "reflectivity": 1,
    "refraction": 0,
    "refractionIndex": 0.6666666666666666,
    "cubeMapProjection": 0,
    "cubeMapProjectionBox": {
        "center": [0, 0, 0],
        "halfExtents": [0.5, 0.5, 0.5]
    },
    "lightMapChannel": "rgb",
    "lightMapUv": 1,
    "lightMapTiling": [1, 1],
    "lightMapOffset": [0, 0],
    "depthTest": true,
    "depthWrite": true,
    "cull": 1,
    "blendType": 3,
    "shader": "blinn",
    "useFog": true,
    "useLighting": true,
    "useSkybox": true,
    "useGammaTonemap": true,
    "aoMapVertexColor": false,
    "diffuseMapVertexColor": false,
    "emissiveMapVertexColor": false,
    "specularMapVertexColor": false,
    "metalnessMapVertexColor": false,
    "opacityMapVertexColor": false,
    "glossMapVertexColor": false,
    "lightMapVertexColor": false,
    "diffuseMapTint": false,
    "specularMapTint": false,
    "emissiveMapTint": false,
    "metalnessMapTint": false,
    "mapping_format": "path"
}

Also a side note - glb loader swaps some shader chunks on materials it creates from glb. So at the moment if you’d preserved all material properties from glb and created material yourself, it would not match the one from glb due to those differently handled properties.

We have this issue to address it, but it has not been done yet: https://github.com/playcanvas/engine/issues/2404

1 Like

I have used this idea and it’s working very well! We have recreated like 30 to 40 materials with that and it saved us a lot of time!

For further readers, the only think is there was the vertex color setting (diffuseMapVertexColor) checked by default. We unchecked that for all the materials and the visual was great!

So yes it’s possible to extract and reintegrate materials from a GLB model.

image

Thank you Mystik