Skip to main content

How to add materials and textures to a GLB file

About Us
Published by JET BI
20 January 2025
245

How to add materials and textures to a GLB file: a step-by-step guide

 

Introduction

The GLB format (or its text analog glTF) is widely used for 3D models due to its lightweight nature and support for physically based materials (PBR — Physically Based Rendering). It allows developers and designers to store complex 3D models, complete with geometry, textures, materials, animations, and scenes, in a single binary file. This makes GLB an ideal format for applications in gaming, AR/VR, and web-based 3D content. High-quality materials and textures are critical for achieving realistic and visually appealing 3D models. They not only add depth and detail to the model but also enhance the overall user experience. In this guide, we will look at how to programmatically add materials and textures to a GLB file, enhancing its visual quality and realism. We will also provide tips on creating high-quality materials to ensure your 3D models are ready for any platform or use case.

 

PBR Basics and GLB Structure
 

A GLB file consists of:

Meshes: the geometry of the model.

Materials: a description of the visual properties (color, metallicity, roughness, etc.).

Textures: images used to add details (albedo, normals, metallicity, etc.).


PBR materials use physically correct lighting, which allows you to create realistic scenes. The main parameters of PBR:

Base Color (Albedo): the main color of the surface.

Metallic: The degree of light reflection typical of metals.

Roughness: Adjusts the smoothness of the surface (higher values ​​= more matte surface).

Normal Map: Used to add fine details such as bumps or dents.


 

Initial Step

Launch Blender and Pycharm (or any other IDE, where python is installed).
C:\Users\smykr\Desktop\article_2_materials\1.png


Make an export of this file to glTF format.
C:\Users\smykr\Desktop\article_2_materials\2.jpg

Save it in any directory and name it as you wish.
C:\Users\smykr\Desktop\article_2_materials\3.jpg

 

Adding base colors

To add base colors to the GLB model, you can use the pygltflib library. Install this library with command: 

pip install pygltflib


Launch this code in your IDE.

from pygltflib import GLTF2, Material

# Loading the GLB file
file_path = "path/to/model.glb"
glb = GLTF2().load(file_path)

# Creating a new material with a base color
new_material = Material(
    name="CustomMaterial",
    pbrMetallicRoughness={
        "baseColorFactor": [1.0, 0.0, 0.0, 1.0],  # Red color with full opacity
        "metallicFactor": 0.0,  # Non-metallic
        "roughnessFactor": 0.8  # Matte surface
    }
)

# Adding the material to the model
glb.materials.append(new_material)

# Assigning the new material to the first primitive mesh
for mesh in glb.meshes:
    for primitive in mesh.primitives:
        primitive.material = len(glb.materials) - 1  # Index of the new material

# Saving the updated file
glb.save("model_with_material.glb")

 

Explanations:

baseColorFactor defines the color of the material. In this case, it is red.

MetalFactor controls the metallicity of the material. A value of 0.1 makes the surface slightly metallic.

RoughnessFactor controls the roughness. A value of 0.8 makes the surface matte.

As a result, the mesh models will use red color, low metallicity and high roughness.

Now you have to import this file from your working directory back to Blender.

C:\Users\smykr\Desktop\article_2_materials\4.jpg
C:\Users\smykr\Desktop\article_2_materials\9.jpg

You have to receive this red cube:
C:\Users\smykr\Desktop\article_2_materials\5.png

 

Loading and assigning textures

Textures greatly improve the appearance of the model. Let's consider adding an albedo texture (Base Color).

from pygltflib import GLTF2, Image, Texture, Sampler, Material

# Loading the GLB file
file_path = "path/to/model.glb"
glb = GLTF2().load(file_path)

# Loading the texture image
texture_path = "path/to/texture.png"
with open(texture_path, "rb") as f:
    image_data = f.read()

# Creating an Image object
image = Image(uri="path/to/texture.png")
glb.images.append(image)

# Creating a Sampler object
sampler = Sampler()
glb.samplers.append(sampler)

# Creating a Texture object
texture = Texture(sampler=len(glb.samplers) - 1, source=len(glb.images) - 1)
glb.textures.append(texture)

# Assigning the texture to the material
new_material = Material(
    name="TexturedMaterial",
    pbrMetallicRoughness={
        "baseColorTexture": {"index": len(glb.textures) - 1}
    }
)
glb.materials.append(new_material)

# Assigning the material to the mesh
for mesh in glb.meshes:
    for primitive in mesh.primitives:
        primitive.material = len(glb.materials) - 1

# Saving the file
glb.save("model_with_texture.glb")

 

Explanations:

Image: Represents the texture image file (e.g., texture.png) that you want to apply.

Sampler: Controls how the texture is sampled, such as wrapping or filtering.

Texture: Combines the image and sampler for use in the material.

baseColorTexture: Links the texture to the base color of the material.

As a result, the albedo texture (e.g., a detailed color image) is applied to the model, enhancing its appearance.

Import "model_with_texture.glb" as in the upper section.
C:\Users\smykr\Desktop\article_2_materials\6.png

 

Adding normal maps and other textures

To improve quality, you can add normal, metallic and roughness maps. These maps work similarly to albedo:

Load the map image.

Create an Image object, then a Texture.

Assign the texture to the corresponding material parameter (e.g. normalTexture, metallicRoughnessTexture).

Example of adding a normal map:

from pygltflib import GLTF2, Image, Texture, Sampler, Material

# Loading the GLB file
file_path = "path/to/model.glb"
glb = GLTF2().load(file_path)

# Loading the texture image
texture_path = "path/to/texture.png"
with open(texture_path, "rb") as f:
    image_data = f.read()

# Creating an Image object
image = Image(uri="path/to/texture.png")
glb.images.append(image)

# Creating a Sampler object
sampler = Sampler()
glb.samplers.append(sampler)

# Creating a Texture object
texture = Texture(sampler=len(glb.samplers) - 1, source=len(glb.images) - 1)
glb.textures.append(texture)

# Assigning the texture to the material
new_material = Material(
    name="TexturedMaterial",
    pbrMetallicRoughness={
        "baseColorTexture": {"index": len(glb.textures) - 1}
    }
)
glb.materials.append(new_material)

# Assigning the material to the mesh
for mesh in glb.meshes:
    for primitive in mesh.primitives:
        primitive.material = len(glb.materials) - 1

# Loading normal map
normal_map_path = "path/to/normal_map.png"
with open(normal_map_path, "rb") as f:
    normal_data = f.read()

image = Image(uri="path/to/normal_map.png")
glb.images.append(image)
texture = Texture(source=len(glb.images) - 1)
glb.textures.append(texture)

new_material.normalTexture = {"index": len(glb.textures) - 1}

# Saving the file
glb.save("model_with_texture_and_map.glb")

Explanations:

Material Assignment: Creates a new material (TexturedMaterial) and assigns the texture as the base color. Then, this material is linked to the mesh's primitives so it applies to the object.

Loading a Normal Map: Normal maps add depth and detail to the model without changing its geometry by simulating lighting variations.

The normal_map.png file is loaded as an additional Image and linked to a Texture object.

The normalTexture property of the material is set to reference this texture, enabling normal mapping.

Result: The model now includes realistic surface details, such as grooves or ridges, based on the normal map.
C:\Users\smykr\Desktop\article_2_materials\7.png

Tips for Creating High-Quality Materials

  1. Use textures with a resolution that is appropriate for your project. Avoid images that are too large, as this can slow down rendering.
  2. materials look best when using physically based lighting.
  3. Adjust the roughness and metallic parameters to achieve the desired effect.
  4. Test the model in environments with different lighting to ensure that it looks good in all conditions.
     

The Final Result

C:\Users\smykr\Desktop\article_2_materials\8.png


Full Code

from pygltflib import GLTF2, Image, Texture, Sampler, Material

# Loading the GLB file
file_path = "path/to/your/model.glb"
glb = GLTF2().load(file_path)

# Loading the albedo texture image
texture_path = "path/to/your/texture.png"
with open(texture_path, "rb") as f:
    image_data = f.read()

# Creating an Image object for the albedo texture
image = Image(uri="path/to/your/texture.png"
glb.images.append(image)

# Creating a Sampler object
sampler = Sampler()
glb.samplers.append(sampler)

# Creating a Texture object for the albedo texture
texture = Texture(sampler=len(glb.samplers) - 1, source=len(glb.images) - 1)
glb.textures.append(texture)

# Creating a new material with a base color texture
new_material = Material(
    name="TexturedMaterial",
    pbrMetallicRoughness={
        "baseColorTexture": {"index": len(glb.textures) - 1},
        "metallicFactor": 0.0,  # Non-metallic
        "roughnessFactor": 0.8  # Matte surface
    }
)
glb.materials.append(new_material)

# Assigning the material to the first primitive mesh
for mesh in glb.meshes:
    for primitive in mesh.primitives:
        primitive.material = len(glb.materials) - 1  # Index of the new material

# Loading the normal map texture
normal_map_path = "path/to/your/normal_map.png"
with open(normal_map_path, "rb") as f:
    normal_data = f.read()

# Creating an Image object for the normal map
normal_image = Image(uri="path/to/your/normal_map.png")
glb.images.append(normal_image)

# Creating a Texture object for the normal map
normal_texture = Texture(source=len(glb.images) - 1)
glb.textures.append(normal_texture)

# Assigning the normal map texture to the material
new_material.normalTexture = {"index": len(glb.textures) - 1}

# Saving the updated GLB file
glb.save("full_model.glb")

 

Conclusion

Adding materials and textures to GLB files with Python opens up endless possibilities for automating workflows and creating realistic 3D models. By programmatically applying materials, textures, and maps, you can ensure consistency across projects and maintain precision in your 3D assets. Experiment with different texture maps, such as normal or roughness maps, to achieve the desired level of realism and visual quality. Always test your models after making changes to ensure compatibility with your target platform, whether it's a game engine, AR application, or web viewer. The combination of creativity and scripting opens up opportunities to bring your ideas to life efficiently. Let’s bring more stunning models to the virtual world together.


Roman Smyk
Python Developer/Data Analyst
image
Expertise
Question to the expert
image

We have available resources to start working on your project within 5 business days

1 UX Designer

image

1 Admin

image

2 QA engineers

image

1 Consultant

image
Related Articles
All articles
image
How to Customize Salesforce Field Service Mobile for Your Technicians
Salesforce Field Service Mobile provides a standard technician experience that companies can extend to fit their own service processes. This article looks at areas where a custom mobile workflow can help: AI repair assistance, field documentation, external tools, back-office integrations, quotes and payments on site, barcode scanning and role-based mobile layouts. It also outlines four practical steps for planning a mobile workflow around the technician’s work.
21 October 2026
image
Salesforce Field Service Mobile: New Capabilities for Technicians
Salesforce Field Service Mobile continues to evolve with new capabilities for technicians working in the field. Explore how updates to job preparation, mobile forms, voice input, mapping, and Work Order views are changing the technician experience, and learn why configuring these capabilities around your service operations matters.
14 October 2026
image
Closing the Gap Between Field Service and Business Needs
Standard Salesforce Field Service configuration covers many service processes, but individual businesses can have different workflows, working conditions, scheduling rules, and operational requirements. This article looks at three areas where standard configuration can fall short: how technicians work, the conditions of field service operations, and business-specific processes. It also provides a practical checklist of signs that a Salesforce Field Service setup could benefit from customization.
07 October 2026