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

OBJ 3D File Formats

The bits and bytes...

 


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:

Obj format overview (triangle only obj file)

.
obj file:

mtllib tree.mtl
o Icosphere
v 0.089624 1.419387 0.052847
vt 0.818181 0.000000
vn 0.5499 0.7413 0.3847
usemtl Material.001
f 1
/1/1 14/2/1 13/3/1


.mtl file:

newmtl Material.001
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.217401 0.800000 0.176586
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2



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&]














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.