Posts Tagged ‘obj’

Parse floating point numbers from a string in ruby

Monday, April 11th, 2016

Given a string like "v 1.2 4.2342 8.2 -1.0e14" (e.g., from a .obj file), you could use the following ruby line to extract an ordered list of the contained floating point numbers:

line.scan(/[+-]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?/).collect{|s| s.to_f}

which would produce

=> [1.2, 4.2342, 8.2, 100000000000000.0]

Unzip OBJ-style mesh into a per-vertex attribute mesh

Wednesday, January 6th, 2016

The .obj mesh file format allows corners of triangles to pull attributes from different sources. The triangle:

v 0 0 0
v 1 0 0
v 0 0 0
vn 1 0 0
vn 0 1 0
vt 0 0 0
f 1/1/1 2/1/1 3/1/2

pulls vertex positions from entries (1,2,3) in the v ... vertex position list, texture coordinates from entries (1,1,1) in the vt ... list, and normals from entries (1,2,2) in the vn normals list.

If we think of corners being described by all attributes there are potentially #F*3 distinct corners. Often information is shared, and in the best case the position/texture/normal indices are all the same, so #V distinct corners. Usually it’s some mixture in between.

I added igl::unzip_corners to libigl which “unzips” an OBJ-style mesh into per-vertex attribute mesh: each new vertex is a distinct corner, so the new face list indexes all attributes in lock step (ideal for OpenGL). I was careful to determine uniqueness combinatorially so, for example, combinatorially distinct input vertices happening to share the same attributes (two vertices at the same position, etc.) don’t get merged (you could always use igl::remove_duplicate_vertices if you wanted to do that).

Here’s a little demo program:

  Eigen::MatrixXd V, TC, N;
  Eigen::MatrixXi F,FTC,FN;
  igl::readOBJ(argv[1],V,TC,N,F,FTC,FN);
  if(FTC.size() == 0)
  {
    FTC = F;
  }
  Eigen::MatrixXi U,G,J;
  igl::unzip_corners<Eigen::MatrixXi>({F,FTC},U,G,J);
  // New mesh vertices and texture coordinates indexed by G
  GV = igl::slice(Eigen::MatrixXd(V),U.col(0),1);
  GTC = igl::slice(Eigen::MatrixXd(TC),U.col(1),1);

Writing a mesh to an .obj file in a single line with Eigen

Wednesday, April 29th, 2015

I was recently revisiting our igl::writeOBJ code and realized that for simple meshes, the code for writing an .obj file can be really simple:

ofstream("test.obj")<<
  V.format(IOFormat(FullPrecision,0," ","\n","v ","","","\n"))<<
  (F.array()+1).format(IOFormat(FullPrecision,0," ","\n","f ","","","\n"));

Update: And because why not, here’s a .off writer:

ofstream("test.off")<<
  "OFF\n"<<V.rows()<<" "<<F.rows()<<" 0\n"<<
  V.format(IOFormat(FullPrecision,0," ","\n","","","","\n"))<<
  (F.array()).format(IOFormat(FullPrecision,0," ","\n","3 ","","","\n"));

Scrape 3D model from Sketchfab

Wednesday, October 16th, 2013

SketchFab has many 3D models, like this bulldog. Open up their webgl viewer and extract the following Javascript variables to recover the model vertices and faces.

// Copy result of this:
view3D._scene.children[2].children[0].children[0].children[0].children[0].children[0].children[0].children[1].attributes.Vertex._elements
// to U


for each primitive p
  // Copy result of this
  view3D._scene.children[2].children[0].children[0].children[0].children[0].children[0].children[0].children[1].primitives[p].indices._elements
  // to P{p+1}.indices, and 
  view3D._scene.children[2].children[0].children[0].children[0].children[0].children[0].children[0].children[1].primitives[p].mode // 5 means TRIANGLE_STRIP, 4 means TRIANGLES
  // to P{p+1}.mode

Then in matlab you can issue:

V = reshape(U,3,[])';
F = [];
for p = 1:numel(P)
  switch P{p}.mode
  case 4
    F = [F;reshape(P{p}.indices+1,3,[])'];
  case 5
    pF = triangles_from_strip(P{p}.indices+1);
    dblA = doublearea(V,pF);
    F = [F;pF(dblA>0,:)];
  end
end

Then you can save it to a obj, off or stl file or just render it in MATLAB:

sketchfab bulldog in matlab

QuickLook generator plugin for 3D model mesh file formats (.off, .obj, .mesh, .wrl)

Sunday, October 6th, 2013

Using libigl and Mesa3D’s off screen rendering is was easy to whip up a QuickLook preview and thumbnail generator for our favorite 3D model file formats. I opted to avoid Xcode and compile the application using a good old Makefile. You can find the project in the libigl examples libigl/examples/quicklook-mesh/ (as of version 0.3.2).

Once installed the QuickLook generator will make (static) previews of any .mesh, .off, .obj or .wrl files when hit [space] after selecting the file in Finder.app.

Mesh quicklook preview

Or when you use one of the fancier Finder.app views

Mesh quicklook thumbnail

I imagine I’ll be perfecting this over time, but for now it shows 6 canonical views and uses a double-sided material to give you an idea of any inconsistent mesh orientation issues. It should work for triangle meshes or general polygonal meshes.

You can skip compiling and just download Mesh.qlgenerator. Install it by moving Mesh.qlgenerator/ into /Library/QuickLook/. Then either restart you computer or issue in a Terminal:

qlmanage -r
qlmanage -r cache

Update: I’ve finally fixed some issues with the dynamic libraries. The updated Mesh.qlgenerator now contains a binary which should work anywhere, without requiring you to install Mesa3D or any other dependencies.

Update: I’ve moved this out of the libigl/examples to its own repo on github.

OBJ reader, mesh viewer in browser with WebGL

Wednesday, April 10th, 2013

mesh in browser

I’m getting around to release source code and demos for my PhD projects and I thought it would be cool to try out writing those demos using WebGL. After toying around (for a few years now), I have a little proof of concept.

This little mesh viewer can load an .obj mesh file (just bare basics of the format) from (1) the remote server, (2) a selected file, or (3) a drag-and-drop file. Just drag an .obj file from your folder onto the viewer! For now there’s not much interface, just a simple zoom mechanism. But I’m going to build on this and keep updated the page.

The source code is heavily borrowed from around the web. See the .js sources.

TexMapPreview: simple texture mapping utility

Wednesday, September 21st, 2011

texmappreview simple texture mapping utility working on woody I posted the source and binary of TexMapPreview. It’s a little texture mapping utility I’ve been using to visualize texture maps on the meshes I deform. It takes as input a mesh (with texture coordinates) and an (texture) image. Then it can either write the visualization of the texture mapped mesh to an output file or display it in a GLUT window. Glut is the only dependency. TexMapPreview itself can only read and write .tga image files. But, I include a bash script wrapper which uses ImageMagick’s convert tool to enable reading and writing of all sorts of file formats (.png, .jpg, .tiff, whatever convert can read/write).

We thank Scott Schaefer for providing the wooden gingerbread man image from “Image Deformation Using Moving Least Squares”.

Convert .vert/.tri pairs into obj with simple bash script

Friday, May 13th, 2011

Here’s a tiny bash script you can save in verttri2obj.sh to convert .vert/.tri pairs like those of the TOSCA mesh repository:


#!/bin/bash
cat $1 | sed -e "s/^/v /g" > $3
cat $2 | sed -e "s/^/f /g" >> $3

And call it with:


./verttri2obj.sh mesh.vert mesh.tri mesh.obj

Update: Here’s a little bash oneliner that uses the script above to convert all the .vert/.tri pairs in a directory to objs:


ls -1 *.vert | sed -e "s/\(.*\).vert/~\/path\/to\/verttri2obj.sh \1.vert \1.tri \1.obj/g" | bash

Converting the entire TASCO repository above took about a minute and a half on my computer.

Convert quad mesh OBJ to triangle mesh OBJ using regular expressions (with bash and sed)

Wednesday, December 15th, 2010

Here’s a simple bash one-liner that converts a quad mesh stored in an OBJ file into a triangle mesh stored in a OBJ file. It splits every quad (a,b,c,d) into two triangles (a,b,c) and (a,c,d).

I issue this in the bash shell of my mac (you may have to tweak the sed syntax):


cat quads.obj | sed -E -e "s/f ([0-9\/]+) ([0-9\/]+) ([0-9\/]+) ([0-9\/]+)/f \1 \2 \3`echo -e "\r"`f \1 \3 \4/g" > triangles.obj

Or I open the file with vim and use:


:%s/f \([0-9\/]\+\) \([0-9\/]\+\) \([0-9\/]\+\) \([0-9\/]\+\)/f \1 \2 \3\rf \1 \
3 \4/g

Simple .obj mesh reader for MATLAB

Monday, March 8th, 2010

matlab obj mesh reader screenshotI wrote a little .obj file format reader in MATLAB. It only reads the vertices and faces of a triangle mesh (ignoring all the other commands and features). I use it to extract the vertex and face arrays. Here’s the code, I save it in a file called read_vertices_and_faces_from_obj_file.m:

function [V,F] = read_vertices_and_faces_from_obj_file(filename)
  % Reads a .obj mesh file and outputs the vertex and face list
  % assumes a 3D triangle mesh and ignores everything but:
  % v x y z and f i j k lines
  % Input:
  %  filename  string of obj file's path
  %
  % Output:
  %  V  number of vertices x 3 array of vertex positions
  %  F  number of faces x 3 array of face indices
  %
  V = zeros(0,3);
  F = zeros(0,3);
  vertex_index = 1;
  face_index = 1;
  fid = fopen(filename,'rt');
  line = fgets(fid);
  while ischar(line)
    vertex = sscanf(line,'v %f %f %f');
    face = sscanf(line,'f %d %d %d');
    face_long = sscanf(line,'f %d//%d %d//%d %d//%d',6);
    face_long_long = sscanf(line,'f %d/%d/%d %d/%d/%d %d/%d/%d',9);

    % see if line is vertex command if so add to vertices
    if(size(vertex)>0)
      V(vertex_index,:) = vertex;
      vertex_index = vertex_index+1;
   % see if line is simple face command if so add to faces
    elseif(size(face,1)==3)
      F(face_index,:) = face;
      face_index = face_index+1;
    % see if line is a face with normal indices command if so add to faces
    elseif(size(face_long,1)==6)
      % remove normal
      face_long = face_long(1:2:end);
      F(face_index,:) = face_long;
      face_index = face_index+1;
    % see if line is a face with normal and texture indices command if so add to faces
    elseif(size(face_long_long,1)==9)
      % remove normal and texture indices
      face_long_long = face_long_long(1:3:end);
      F(face_index,:) = face_long_long;
      face_index = face_index+1;
    else
      fprintf('Ignored: %s',line);
    end

    line = fgets(fid);
  end
  fclose(fid);
end

Then I can read and render a mesh with phong shading:

[V,F] = read_vertices_and_faces_from_obj_file('path/to/your/mesh.obj');
trisurf(F,V(:,1),V(:,2),V(:,3),'FaceColor',[0.26,0.33,1.0 ]);
light('Position',[-1.0,-1.0,100.0],'Style','infinite');
lighting phong;

Update: I changed the above to account for other triangle face lines (as per Limdor’s comment). However, there is a much fuller version available in my qptoolbox and the libigl tutorial shows how to create a readOBJ using C++ via a mex function which results in much faster loading times for big meshes.