www.xbdev.net
xbdev - software development
Wednesday May 7, 2025
Home | Contact | Support | OBJ 3D File Formats The bits and bytes...
     
 

OBJ 3D File Formats

The bits and bytes...

 


Visualization of the obj file format - minimal working code on left and the model on the right.
Visualization of the obj file format - minimal working code on left and the model on the right.


OBJ File Format (.obj)


The `obj` file format is a text based format.

Example of what the file format looks like in a text editor (triangle only)

triangle.obj
# Equilateral Triangle OBJ File
mtllib triangle.mtl
o Triangle

# Vertices (y=0 for flat triangle)
-0.5 0 -0.288675  # Left vertex
v  0.5 0 -0.288675  # Right vertex
v  0.0 0  0.577350  # Top vertex

# Texture Coordinates (UV mapping)
vt 0.0 0.0  # Bottom-left
vt 1.0 0.0  # Bottom-right
vt 0.5 1.0  # Top-center

# Normals (facing up)
vn 0 1 0

# Material
usemtl DefaultMaterial

# Face (counter-clockwise winding)
f 1/1/1 2/2/1 3/3/1


The material information can be include inline in the obj - or included in an additional file with the '.mtl' extension. (This file is referenced in the obj using the
mtllib
tag):

triangle.mtl
# Material for the triangle
newmtl DefaultMaterial
Ka 1.0 1.0 1.0    
# Ambient color (white)
Kd 0.8 0.2 0.2    # Diffuse color (red)
Ks 0.5 0.5 0.5    # Specular highlights
Ns 32             # Shininess (0-1000)
illum 2           # Phong shading




Example obj file loader (in Javascript)


The following `obj` file loader is in a single file. Also converts non-triangle (quad) mesh elements to triangles.


Output for the example OBJ Loader - loads in a 3d model of a Stadium
Output for the example OBJ Loader - loads in a 3d model of a Stadium


readObj = function(txt)
{
    
console.log('readObj...');

    
let objects = [];

    
let materials = [];
    
objects.push( { 'name':'test''v':[], 'vt':[], 'vn':[], 'f':[], 'usemtl':'' } );
    
let data = { 'v':[], 'n':[], 'f':[], 'm':[] };

    
txt txt.replaceAll('  '' ');
    
let lines txt.split('\n');
    
console.log('num lines:'lines.length );

    
let curmat = -1;
  
    for (
let i=0i<lines.lengthi++)
    {
        
let line lines[i];
        
line line.trim()
        if ( 
line.length ) continue;
        if ( 
line[0] == '#'  ) continue;

        
let parts line.split(' ');
        if ( 
parts.length ) continue;
      
        try{
        switch( 
parts[0] )
        {            
              case 
'usemtl':
            {
               
let matname parts[1];
               if ( !
materials.includesmatname ) )
               {
                 
materials.pushmatname );
               }
               
curmat materials.indexOfmatname );
               
//console.log( 'curmat:', curmat );
            
}
            break;
            
            case 
'v'// v 0.089624 1.419387 0.052847
            
{
                
objects.reverse()[0].v.pushparts[1] );
                
objects.reverse()[0].v.pushparts[2] );
                
objects.reverse()[0].v.pushparts[3] );
            }
            break;

            case 
'vt'// vt 0.818181 0.000000
            
{
                
objects.reverse()[0].vt.pushparts[1] );
                
objects.reverse()[0].vt.pushparts[2] );
            }
            break;

            case 
'vn'// vn 0.5499 0.7413 0.3847
            
{
                
objects.reverse()[0].vn.pushparts[1] );
                
objects.reverse()[0].vn.pushparts[2] );
                
objects.reverse()[0].vn.pushparts[3] );
            }
            break;

            case 
'f'// f 1/1/1 14/2/1 13/3/1
            
{   
                
// f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
                // f v1//vn1 v2//vn2 v3//vn3 ... (double slashes)
                    


/*
If you have 4 indices, e.g.:

0 1 2 3
The division into two triangles would be one with the first 3 indices, and one with the first, third, and fourth. In this example:

0 1 2
0 2 3
Let's try some ASCII art to illustrate this:

3-------2
|      /|
|    /  |
|  /    |
|/      |
0-------1
*/
              
                
let i0 parts[1].split('/')[0]-1;
                
let i1 parts[2].split('/')[0]-1;
                
let i2 parts[3].split('/')[0]-1;
                
let i3 parts.length ==undefined : (parts[4].split('/')[0]-1);

                
let n0 parts[1].split('/')[2]-1;
                
let n1 parts[2].split('/')[2]-1;
                
let n2 parts[3].split('/')[2]-1;
                
let n3 parts.length ==undefined : (parts[4].split('/')[2]-1);

                if ( 
parts[1].includes('//') )
                {
                    
n0 parts[1].split('//')[1]-1;
                    
n1 parts[2].split('//')[1]-1;
                    
n2 parts[3].split('//')[1]-1;
                    
n3 parts.length == undefined : (parts[4].split('//')[1]-1);
                }

                if ( 
i3 == undefined // triangles
                
{
                    
let v = []
                    for (
let g=0g<3g++)
                    {
                    
let idx = [i0,i1,i2][g];
                    
let x0 objects.reverse()[0].v[  (3idx)+0   ];
                    
let y0 objects.reverse()[0].v[  (3idx)+1   ];
                    
let z0 objects.reverse()[0].v[  (3idx)+2   ];
                    
v.push( { x:x0y:y0z:z0 } );
                    }
                    
data.v.pushv[0].);  data.v.pushv[0].); data.v.pushv[0].);
                    
data.v.pushv[1].);  data.v.pushv[1].); data.v.pushv[1].);
                    
data.v.pushv[2].);  data.v.pushv[2].); data.v.pushv[2].);
                    
data.m.pushcurmat );
                    
data.m.pushcurmat );
                    
data.m.pushcurmat );
                    
data.f.pushdata.f.length );
                    
data.f.pushdata.f.length );
                    
data.f.pushdata.f.length );

                      
let n = [];
                    for (
let g=0g<[n0,n1,n2].lengthg++)
                    {
                    
let nx0 objects.reverse()[0].vn[  3*[n0,n1,n2][g]+0   ];
                    
let ny0 objects.reverse()[0].vn[  3*[n0,n1,n2][g]+1   ];
                    
let nz0 objects.reverse()[0].vn[  3*[n0,n1,n2][g]+2   ];
                    
n.push( { x:nx0y:ny0z:nz0 } );
                    }
                    
data.n.pushn[0].);  data.n.pushn[0].); data.n.pushn[0].);
                    
data.n.pushn[1].);  data.n.pushn[1].); data.n.pushn[1].);
                    
data.n.pushn[2].);  data.n.pushn[2].); data.n.pushn[2].);
                }
                else 
// quads 
                
{
                  
                    
let v = [];
                    for (
let g=0g<4g++)
                    {
                    
let idx = [i0,i1,i2,i3][g];
                    
let x0 objects.reverse()[0].v[  (3idx)+0   ];
                    
let y0 objects.reverse()[0].v[  (3idx)+1   ];
                    
let z0 objects.reverse()[0].v[  (3idx)+2   ];
                    
v.push( { x:x0y:y0z:z0 } );
                    }
                    
data.v.pushv[0].);  data.v.pushv[0].); data.v.pushv[0].);
                    
data.v.pushv[1].);  data.v.pushv[1].); data.v.pushv[1].);
                    
data.v.pushv[2].);  data.v.pushv[2].); data.v.pushv[2].);
                    
data.m.pushcurmat );
                    
data.m.pushcurmat );
                    
data.m.pushcurmat );
                    
data.f.pushdata.f.length );
                    
data.f.pushdata.f.length );
                    
data.f.pushdata.f.length );

                    
data.v.pushv[0].);  data.v.pushv[0].); data.v.pushv[0].);
                    
data.v.pushv[2].);  data.v.pushv[2].); data.v.pushv[2].);
                    
data.v.pushv[3].);  data.v.pushv[3].); data.v.pushv[3].);
                    
data.m.pushcurmat );
                    
data.m.pushcurmat );
                    
data.m.pushcurmat );
                    
data.f.pushdata.f.length );
                    
data.f.pushdata.f.length );
                    
data.f.pushdata.f.length );
                    
                    
let n = [];
                    for (
let g=0g<4g++)
                    {
                    
let idx = [n0,n1,n2,n3][g];
                    
let nx0 objects.reverse()[0].vn[  (3idx)+0   ];
                    
let ny0 objects.reverse()[0].vn[  (3idx)+1   ];
                    
let nz0 objects.reverse()[0].vn[  (3idx)+2   ];
                    
n.push( { x:nx0y:ny0z:nz0 } );
                    }
                    
data.n.pushn[0].);  data.n.pushn[0].); data.n.pushn[0].);
                    
data.n.pushn[1].);  data.n.pushn[1].); data.n.pushn[1].);
                    
data.n.pushn[2].);  data.n.pushn[2].); data.n.pushn[2].);

                    
data.n.pushn[0].);  data.n.pushn[0].); data.n.pushn[0].);
                    
data.n.pushn[2].);  data.n.pushn[2].); data.n.pushn[2].);
                    
data.n.pushn[3].);  data.n.pushn[3].); data.n.pushn[3].); 
                    
                }
            }
            break;

      }
// end switch(..)
      
      
}catch(e){ }

    }
// for

    
console.log'dump:'data.m.slice(020) );
  
    return [ 
data ];
}
// readObj(..)



Resources and Examples


• WebGPU Example [LINK]

• Notebook `obj` to `json` Example [https://notebook.xbdev.net/index.php?page=objtojson&]

• Visualization using JS/Canvas (WebBook Lab) [LINK]












Ray-Tracing with WebGPU kenwright WebGPU Development Cookbook - coding recipes for all your webgpu needs! WebGPU by Example: Fractals, Image Effects, Ray-Tracing, Procedural Geometry, 2D/3D, Particles, Simulations WebGPU Games WGSL 2d 3d interactive web-based fun learning WebGPU Compute WebGPU API - Owners WebGPU & WGSL Essentials: A Hands-On Approach to Interactive Graphics, Games, 2D Interfaces, 3D Meshes, Animation, Security and Production Kenwright graphics and animations using the webgpu api 12 week course kenwright learn webgpu api kenwright programming compute and graphics applications with html5 and webgpu api kenwright real-time 3d graphics with webgpu kenwright webgpu for dummies kenwright webgpu api develompent a quick start guide kenwright webgpu by example 2022 kenwright webgpu gems kenwright webgpu interactive compute and graphics visualization cookbook kenwright wgsl webgpu shading language cookbook kenwright WebGPU Shader Language Development: Vertex, Fragment, Compute Shaders for Programmers Kenwright wgsl webgpugems shading language cookbook kenwright WGSL Fundamentals book kenwright WebGPU Data Visualization Cookbook kenwright Special Effects Programming with WebGPU kenwright WebGPU Programming Guide: Interactive Graphics and Compute Programming with WebGPU & WGSL kenwright



 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2025 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.