CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pywavefront

Python library for importing Wavefront .obj files and generating interleaved vertex data ready for rendering.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

materials.mddocs/

Materials and Textures

Material properties, texture management, and vertex data organization. Materials contain interleaved vertex arrays formatted for direct use with OpenGL rendering pipelines.

Capabilities

Material Objects

Materials store both visual properties and vertex geometry data in a format optimized for modern rendering.

class Material:
    def __init__(
        self,
        name: str,
        is_default: bool = False,
        has_faces: bool = False
    ):
        """
        Create a new material object.
        
        Parameters:
        - name: Material name as defined in .mtl file
        - is_default: Whether this is an auto-generated default material
        - has_faces: Whether to collect face topology data
        
        Attributes:
        - name: str - Material name
        - vertex_format: str - Vertex data format (e.g., "T2F_N3F_V3F")
        - vertices: List[float] - Interleaved vertex data array
        - diffuse: List[float] - Diffuse color [r, g, b, a] (0.0-1.0)
        - ambient: List[float] - Ambient color [r, g, b, a] (0.0-1.0)
        - specular: List[float] - Specular color [r, g, b, a] (0.0-1.0)
        - emissive: List[float] - Emissive color [r, g, b, a] (0.0-1.0)
        - transparency: float - Transparency value (0.0=opaque, 1.0=transparent)
        - shininess: float - Specular shininess factor
        - optical_density: float - Optical density for refraction
        - illumination_model: int - Illumination model (0-10)
        - texture: Texture - Diffuse texture map
        - texture_ambient: Texture - Ambient texture map
        - texture_specular_color: Texture - Specular color texture
        - texture_specular_highlight: Texture - Specular highlight texture
        - texture_alpha: Texture - Alpha/transparency texture
        - texture_bump: Texture - Bump/normal map texture
        """
    
    @property
    def has_normals(self) -> bool:
        """Check if vertex data contains normal vectors."""
        
    @property  
    def has_uvs(self) -> bool:
        """Check if vertex data contains texture coordinates."""
        
    @property
    def has_colors(self) -> bool:
        """Check if vertex data contains vertex colors."""
        
    @property
    def vertex_size(self) -> int:
        """Calculate how many float values each vertex contains in the interleaved data."""
    
    def pad_light(self, values: List[float]) -> List[float]:
        """
        Accept an array of up to 4 values, and return an array of 4 values.
        Pads with zeroes to length 4 if input is shorter.
        """
    
    def set_alpha(self, alpha: float) -> None:
        """Set alpha/transparency value on all four lighting attributes."""
    
    def set_diffuse(self, values: List[float] = None) -> None:
        """Set diffuse color with automatic padding to 4 values."""
    
    def set_ambient(self, values: List[float] = None) -> None:
        """Set ambient color with automatic padding to 4 values."""
    
    def set_specular(self, values: List[float] = None) -> None:
        """Set specular color with automatic padding to 4 values."""
    
    def set_emissive(self, values: List[float] = None) -> None:
        """Set emissive color with automatic padding to 4 values."""
    
    def set_texture(self, name: str, search_path: str) -> None:
        """Set diffuse texture map."""
    
    def set_texture_ambient(self, name: str, search_path: str) -> None:
        """Set ambient texture map."""
    
    def set_texture_specular_color(self, name: str, search_path: str) -> None:
        """Set specular color texture map."""
    
    def set_texture_specular_highlight(self, name: str, search_path: str) -> None:
        """Set specular highlight texture map."""
    
    def set_texture_alpha(self, name: str, search_path: str) -> None:
        """Set alpha/transparency texture map."""
    
    def set_texture_bump(self, name: str, search_path: str) -> None:
        """Set bump/normal map texture."""
    
    def unset_texture(self) -> None:
        """Remove the diffuse texture reference."""

Vertex Data Formats

Materials organize vertex data in interleaved arrays optimized for GPU rendering:

Supported Vertex Formats:

  • V3F - Positions only (x, y, z)
  • T2F_V3F - Texture coordinates + positions (u, v, x, y, z)
  • N3F_V3F - Normals + positions (nx, ny, nz, x, y, z)
  • T2F_N3F_V3F - Texture coords + normals + positions (u, v, nx, ny, nz, x, y, z)
  • C3F_V3F - Vertex colors + positions (r, g, b, x, y, z)
  • T2F_C3F_V3F - Texture coords + colors + positions (u, v, r, g, b, x, y, z)

The vertex format string describes the exact layout of the interleaved vertex array, allowing direct use with OpenGL vertex buffer objects (VBOs).

Material Properties

Materials support the full range of Wavefront material properties:

Color Properties:

  • Diffuse color (Kd) - Base surface color
  • Ambient color (Ka) - Ambient lighting response
  • Specular color (Ks) - Specular highlight color
  • Emissive color (Ke) - Self-illumination color

Surface Properties:

  • Transparency (d or Tr) - Surface transparency (0.0-1.0)
  • Shininess (Ns) - Specular exponent for highlights
  • Optical density (Ni) - Index of refraction for transparent materials
  • Illumination model (illum) - Lighting calculation method (0-10)

Illumination Models:

  • 0: Color on, Ambient off
  • 1: Color on, Ambient on
  • 2: Highlight on
  • 3: Reflection on, Ray trace on
  • 4: Transparency: Glass on, Reflection: Ray trace on
  • 5: Reflection: Fresnel on, Ray trace on
  • 6: Transparency: Refraction on, Reflection: Fresnel off, Ray trace on
  • 7: Transparency: Refraction on, Reflection: Fresnel on, Ray trace on
  • 8: Reflection on, Ray trace off
  • 9: Transparency: Glass on, Reflection: Ray trace off
  • 10: Casts shadows onto invisible surfaces

Texture Management

class Texture:
    def __init__(self, name: str, search_path: str):
        """
        Create a texture.
        
        Parameters:
        - name: Texture name possibly with path and options as it appears in the material
        - search_path: Absolute or relative path where the texture might be located
        
        Attributes:
        - path: str - File path to texture image
        - options: TextureOptions - Texture loading and sampling options
        - image: Any - Used externally by visualization module
        """
        
    @property
    def name(self) -> str:
        """The texture path as it appears in the material."""
        
    @name.setter
    def name(self, value: str) -> None:
        """Set the texture name."""
        
    @property
    def options(self) -> 'TextureOptions':
        """Options for this texture."""
        
    @property
    def file_name(self) -> str:
        """
        Obtain the file name of the texture.
        Handles Windows/relative paths and extracts just the filename.
        """
        
    @property
    def path(self) -> str:
        """Full path: search_path + name."""
        
    @path.setter  
    def path(self, value: str) -> None:
        """Set the texture path."""
        
    @property
    def image_name(self) -> str:
        """Legacy property name for texture path as it appears in material."""
        
    @image_name.setter
    def image_name(self, value: str) -> None:
        """Legacy setter for texture name."""
        
    def find(self, path: str = None) -> str:
        """
        Find the texture in the configured search path.
        Searches recursively in subdirectories if texture not found at direct path.
        
        Parameters:
        - path: Override the search path
        
        Returns:
        - str: Full path to found texture file
        
        Raises:
        - FileNotFoundError: If texture cannot be located
        """
        
    def exists(self) -> bool:
        """Check if the texture file exists at the configured path."""

class TextureOptions:
    def __init__(self):
        """
        Container for texture loading options and parameters with default values.
        
        Attributes:
        - name: str - Texture name (default: "default")
        - blendu: str - U-direction blending ("on"/"off", default: "on")
        - blendv: str - V-direction blending ("on"/"off", default: "on")
        - bm: float - Bump multiplier for bump maps (default: 1.0)
        - boost: float - Boost factor for mip-mapping (default: 0.0)
        - cc: str - Color correction ("on"/"off", default: "off")
        - clamp: str - Clamping mode ("on"/"off", default: "off")
        - imfchan: str - Channel for scalar/bump textures (default: "l")
        - mm: Tuple[float, float] - Range modification (base, gain, default: (0.0, 1.0))
        - o: Tuple[float, float, float] - Origin offset (u, v, w, default: (0.0, 0.0, 0.0))
        - s: Tuple[float, float, float] - Scale factors (u, v, w, default: (1.0, 1.0, 1.0))
        - t: Tuple[float, float, float] - Turbulence factors (u, v, w, default: (0.0, 0.0, 0.0))
        - texres: str - Texture resolution specification
        """

Texture Types:

  • map_Kd - Diffuse color texture (most common)
  • map_Ka - Ambient color texture
  • map_Ks - Specular color texture
  • map_Ns - Specular highlight texture
  • map_d - Alpha/transparency texture
  • map_bump or bump - Bump/normal map texture

Material Parser

class MaterialParser:
    """
    Parser for .mtl material library files.
    Automatically invoked when processing mtllib statements in .obj files.
    """

The MaterialParser handles:

  • Material property parsing from .mtl files
  • Texture path resolution and loading
  • Color and numeric value conversion
  • Material validation and error handling

Usage Examples

# Access material properties
for name, material in scene.materials.items():
    print(f"Material: {name}")
    print(f"Diffuse color: {material.diffuse}")
    print(f"Has texture: {material.texture is not None}")
    print(f"Transparency: {material.transparency}")
    print(f"Illumination model: {material.illumination_model}")

# Check vertex data format and content
material = scene.materials['wood_material']
print(f"Vertex format: {material.vertex_format}")
print(f"Has normals: {material.has_normals}")
print(f"Has UVs: {material.has_uvs}")  
print(f"Has colors: {material.has_colors}")
print(f"Vertex count: {len(material.vertices)}")

# Access interleaved vertex data for rendering
if material.vertex_format == "T2F_N3F_V3F":
    # Data layout: [u, v, nx, ny, nz, x, y, z, u, v, nx, ny, nz, x, y, z, ...]
    vertices = material.vertices
    vertex_size = material.vertex_size  # Automatically calculated: 8 floats per vertex
    
    for i in range(0, len(vertices), vertex_size):
        u, v = vertices[i], vertices[i+1]           # Texture coordinates
        nx, ny, nz = vertices[i+2], vertices[i+3], vertices[i+4]  # Normal
        x, y, z = vertices[i+5], vertices[i+6], vertices[i+7]     # Position
        
# Material property modification
material.diffuse = [1.0, 0.5, 0.2, 1.0]  # Set orange diffuse color
material.shininess = 128.0                # Increase shininess
material.transparency = 0.8               # Make semi-transparent

# Working with textures
if material.texture:
    print(f"Diffuse texture: {material.texture.path}")
    print(f"Texture exists: {material.texture.exists()}")
    print(f"Texture filename: {material.texture.file_name}")
    
if material.texture_bump:
    print(f"Bump map: {material.texture_bump.path}")

# Material property setters with validation
material.set_diffuse([0.8, 0.2, 0.1])    # Will be padded to [0.8, 0.2, 0.1, 0.0]
material.set_ambient([0.1, 0.1, 0.1, 1.0])  # Full RGBA specification
material.set_alpha(0.75)  # Sets alpha on all lighting properties

# Texture management
material.set_texture("wood_diffuse.jpg", "/path/to/textures")
material.set_texture_bump("wood_normal.jpg", "/path/to/textures")

# Calculate vertex size dynamically
vertex_size = material.vertex_size
triangles_count = len(material.vertices) // vertex_size // 3
print(f"Material has {triangles_count} triangles")

# Working with texture options
if material.texture:
    options = material.texture.options
    print(f"Texture clamp mode: {options.clamp}")
    print(f"Bump multiplier: {options.bm}")
    
    # Find texture file in search paths
    try:
        texture_path = material.texture.find()
        print(f"Found texture at: {texture_path}")
    except FileNotFoundError:
        print("Texture file not found in search paths")

Install with Tessl CLI

npx tessl i tessl/pypi-pywavefront

docs

configuration.md

file-loading.md

index.md

materials.md

mesh-operations.md

visualization.md

tile.json