Script Python : Apply a material for each occurence from a .json

I would like to apply a material for all the objects in the occurences with this script:

import json

# Définir le chemin vers ton fichier JSON d'entrée
json_path = r"\\ozone\materiaux.json"  # Remplace par le chemin correct

with open(json_path, "r") as file:
    materials_data = json.load(file)

# Récupérer toutes les occurrences dans la scène
occurrences = pxz.scene.getAllOccurrences()

# Récupérer tous les matériaux existants dans la scène
all_materials = pxz.material.getAllMaterials()
material_dict = {pxz.material.getMaterialName(mat): mat for mat in all_materials}

# Assigner les matériaux aux occurrences
for occ in occurrences:
    occ_name = pxz.scene.getOccurrenceName(occ)

    # Trouver si l'occurrence a un matériau défini dans le JSON
    material_info = next((item for item in materials_data if item["name"] == occ_name), None)

    if material_info:
        material_name = material_info["material"]

        if material_name in material_dict:
            material_id = material_dict[material_name]
            pxz.material.assignMaterial(occ, material_id)
            print(f"✅ Matériau '{material_name}' assigné à '{occ_name}'")
        else:
            print(f"⚠ Matériau '{material_name}' introuvable pour '{occ_name}'")
    else:
        print(f"❌ Aucun matériau défini pour '{occ_name}' dans le JSON")

my .json file look like this:

[
    {
        "name": "STOP LIGHT",
        "material": "TRANSPARENT"
    }
]

I can’t make the script for Pixyz Studio 2024.1 r28 working. Thank you in advance for your help.

Hi @Erc02 ,

It looks like the Forum layout missunderstood the code example you copy pasted. Can you try to reformat your message using the “Preformatted text” option (cf screenshot). Because it’s quite hard to read it currently.

Thanks ! :slight_smile:

I rewrote the python code:

import json

# Définir le chemin vers ton fichier JSON d'entrée
json_path = r"\\ozone\materiaux.json"  # Remplace par le chemin correct

with open(json_path, "r") as file:
    materials_data = json.load(file)

# Récupérer toutes les occurrences dans la scène
occurrences = pxz.scene.getAllOccurrences()

# Récupérer tous les matériaux existants dans la scène
all_materials = pxz.material.getAllMaterials()
material_dict = {pxz.material.getMaterialName(mat): mat for mat in all_materials}

# Assigner les matériaux aux occurrences
for occ in occurrences:
    occ_name = pxz.scene.getOccurrenceName(occ)

    # Trouver si l'occurrence a un matériau défini dans le JSON
    material_info = next((item for item in materials_data if item["name"] == occ_name), None)

    if material_info:
        material_name = material_info["material"]

        if material_name in material_dict:
            material_id = material_dict[material_name]
            pxz.material.assignMaterial(occ, material_id)
            print(f"✅ Matériau '{material_name}' assigné à '{occ_name}'")
        else:
            print(f"⚠ Matériau '{material_name}' introuvable pour '{occ_name}'")
    else:
        print(f"❌ Aucun matériau défini pour '{occ_name}' dans le JSON")

Thank you!

Thanks.
Can you try to elaborate a bit more on what your are trying to acheive ?
What the “name” key in your JSON is refering to ? And what the “material” key is refering to ?
You want to swap what with what ?

From want i understood:
You want to look for every occurence in your scene that has the name of the Json “name” key, then for them swap their material with the one defined in the Json “material” key ?

Yes! Exactly! For every occurence in my scene that has the name of the Json “name” key, for the objects inside of each occurence swap their material with the one defined in the Json “material” key

I propose to have a look at the sample scripts, for example the
Materials_ColorsByDensity.py and the resource Selim_B posted in another thread , see:
How to Handle Materials

There you can see that you need to call

createMaterial

see PixyzSDK: material.createMaterial(name, pattern, addToMaterialLibrary=True) → material.Material

At best, your JSON file would contain all the information necessary for the material pattern already. Then you could also use this: CreateMaterialFromDefinition

Now that you have your material (occurrence id), then you only have to set it the same way as in the example script.

core.setProperty(occ, “Material”, str(mat))

where “Material” is the name of the material and occ is your part occurrence. (See script)
or use the function

SetOccurrenceMaterial

Attention

Be aware that there are some details regarding materials and how they are assigned and displayed in Pixyz Studio/SDK when it comes to multi-material PartOccurrences.

See this discussion here: Subpart Materials
here Apply a material from metadata
Remove Materials
Discussion SubPart Materials

1 Like

Many thanks @DMG_GLein for providing helpfull threads.

@Erc02 I rewrote your code based on the goal we discussed. I provided a static materials_data structure, based on your specification. But feel free to load it from your json file.
I added a check to ensure the material you want to replace with, exist in the pxz scene.

from pxz import *

materialSwappingData =[
    {
        "name": "myOccurrenceName1",
        "material": "myCustomMat1"
    },
    {
        "name": "myOccurrenceName2",
        "material": "myCustomMat2"
    }
]

for matSwapData in materialSwappingData:

    # We retrieve the material id assosiated with the wanted material name (case-sensitive)
    materialsIds = material.findMaterialsByProperty("Name", matSwapData["material"], True)

    # Ensure we found one material with the specified name
    if len(materialsIds) == 0 :
        print("No materials found for name " + matSwapData["material"] + ", step will be skipped")
        continue


    # We retrieve all the occurrences from your scene with the specified name (case-sensitive)
    occurrencesFound = scene.findOccurrencesByProperty("Name", matSwapData["name"], [scene.getRoot()], True)

    # For each of them, we swap their materials
    for occurrence in occurrencesFound:
        # In our case, we do not pass regex into findMaterialsByProperty so we assume the first mat in the list is the correct one
        scene.setOccurrenceMaterial(occurrence, materialsIds[0])

        # If you also want to override your occurrence subParts materials, let's do it here.
        # First we need to know how many of them are attached to this occurrence
        numberOfSubPartMaterials = len(scene.listSubpartMaterials(occurrence))
        # Now we override each of them
        for subpartIndex in range(0, numberOfSubPartMaterials):
            scene.setSubpartMaterial(occurrence, subpartIndex, materialsIds[0])

        # Ensure the materials on the subParts are also applied on the patches
        scene.transferSubpartMaterialsOnPatches(occurrence)

I hope it will be clear and will make sense for your use case. Feel free to ask if you need more precision.