read_obj

Read mesh data from wavefront OBJ format file, only triangle mesh supported.

Data supported are:

All other data will be discarded.

Contents

Syntax

[face,vertex] = read_obj(filename)
[face,vertex,extra] = read_obj(filename)

Description

filename: string, file to read.
face  : double array, nf x 3, connectivity of the mesh.
vertex: double array, nv x 3, position of the vertices.
extra : struct, anything other than face and vertex are included.

Example

[face,vertex] = read_obj('cube.obj');
[face,vertex,extra] = read_obj('face.obj');

Contribution

Author : Wen Cheng Feng
Created: 2014/03/26
Copyright 2014 Computational Geometry Group
Department of Mathematics, CUHK
http://www.math.cuhk.edu.hk/~lmlui
function [face,vertex,extra] = read_obj(filename)
% read whole file into a string
text = fileread(filename);
% split text into lines
[~,lines] = regexp(text,'\n','match','split');
% remove empty and comment lines
ind = cellfun(@(s) isempty(s) || strcmp(s(1),char(13)) || strcmp(s(1),'#'),lines);
lines(ind) = [];

% find all face lines that start with 'f'
ind = cellfun(@(s) strcmp(s(1),'f'),lines);
face_lines = lines(ind);
lines(ind) = [];
% determine format of face line
[type,format,sz] = get_format(face_lines{1});
% join face lines to a string
face_string = strjoin(face_lines,'\n');
% scan face from string
face = sscanf(face_string,format);
face = reshape(face,sz,length(face)/sz)';

% find all vertex lines that start with 'v'
ind = cellfun(@(s) strcmp(s(1:2),'v '),lines);
vertex_lines = lines(ind);
lines(ind) = [];
% determint format of vertex line
[type,format,sz] = get_format(vertex_lines{1});
% join vertex lines to a string
vertex_string = strjoin(vertex_lines,'\n');
% scan vertex from string
vertex = sscanf(vertex_string,format);
vertex = reshape(vertex,sz,length(vertex)/sz)';

% put all other stuff into a structure extra
extra = [];
if size(vertex,2) > 3
    % if vertex line have more than 3 number, then it's color
    vertex_color = vertex(:,4:end);
    vertex = vertex(:,1:3);
    extra.vertex_color = vertex_color;
end

% check if texture and normal are contained
texture = [];
normal = [];
ind = cellfun(@(s) strcmp(s(1:2),'vt'),lines);
texture_lines = lines(ind);
lines(ind) = [];
if sum(ind)
    texture_string = strjoin(texture_lines,'\n');
    [type,format,sz] = get_format(texture_lines{1});
    texture = sscanf(texture_string,format);
    texture = reshape(texture,sz,length(texture)/sz)';
    extra.texture = texture;
end
ind = cellfun(@(s) strcmp(s(1:2),'vn'),lines);
normal_lines = lines(ind);
if sum(ind)
    normal_string = strjoin(normal_lines,'\n');
    [type,format,sz] = get_format(normal_lines{1});
    normal = sscanf(normal_string,format);
    normal = reshape(normal,sz,length(normal)/sz)';
    extra.normal = normal;
end

% if texture or normal contained, retrive face_texture and face_normal from
% face array
if ~isempty(texture) && ~isempty(normal)
    face_texture = face(:,[2 5 8]);
    face_normal = face(:,[3 6 9]);
    face = face(:,[1 4 7]);
    extra.face_texture = face_texture;
    extra.face_normal = face_normal;
elseif ~isempty(texture) && isempty(normal)
    face_texture = face(:,[2 4 6]);
    face = face(:,[1 3 5]);
    extra.face_texture = face_texture;
elseif isempty(texture) && ~isempty(normal)
    face_normal = face(:,[2 4 6]);
    face = face(:,[1 3 5]);
    extra.face_normal = face_normal;
end

function [type,format,sz] = get_format(str)
% determine the format of input str
sn = '[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)'; % match number
ss = '[a-zA-Z]+'; % match string
format = regexprep(str,sn,'%f');
if format(end) ~= char(13)
    format = [format,'\n'];
end
[type,~] = regexp(str,ss,'match');
type = type{1};
[~,splitstr] = regexp(str,sn,'match');
sz = length(splitstr);