refactored face line parsing to support multiline faces

This commit is contained in:
Rachel Hwang 2017-06-15 17:57:05 -04:00
parent 7e82e90b35
commit 2396899f5d
1 changed files with 110 additions and 41 deletions

View File

@ -57,8 +57,15 @@ var facePattern2 = /f(\s+-?\d+\/-?\d+){3,}/;
var facePattern3 = /f(\s+-?\d+\/-?\d+\/-?\d+){3,}/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... var facePattern3 = /f(\s+-?\d+\/-?\d+\/-?\d+){3,}/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var facePattern4 = /f(\s+-?\d+\/\/-?\d+){3,}/; // f vertex//normal vertex//normal vertex//normal ... var facePattern4 = /f(\s+-?\d+\/\/-?\d+){3,}/; // f vertex//normal vertex//normal vertex//normal ...
var faceSpacePattern = /f?\s+/; // Just for line continuations
var faceSpaceOrSlashPattern = /(f?\s+)|(\/+\s*)/g; var facePattern5 = /((\s|^)+-?\d+\/?(\s|$)){1,}/; // f vertex vertex vertex ...
var facePattern6 = /((\s|^)+-?\d+\/-?\d+(\s|$)){1,}/; // f vertex/uv vertex/uv vertex/uv ...
var facePattern7 = /((\s|^)+-?\d+\/-?\d+\/-?\d+(\s|$)+){1,}/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var facePattern8 = /((\s|^)+-?\d+\/\/-?\d+(\s|$)){1,}/; // f vertex//normal vertex//normal vertex//normal ...
var faceSpacePattern = /(f?\s+)|(\s+\/)|(\s*\\)/g;
var faceSpaceOrSlashPattern = /(f?\s+)|(\/+\s*)|(\s+\/)|(\s*\\)/g;
var scratchCartesian = new Cartesian3(); var scratchCartesian = new Cartesian3();
/** /**
@ -101,6 +108,12 @@ function loadObj(objPath, options) {
// All mtl paths seen in the obj // All mtl paths seen in the obj
var mtlPaths = []; var mtlPaths = [];
// Buffers for face data that spans multiple lines
var faceVertices = [];
var facePositions = [];
var faceUvs = [];
var faceNormals = [];
function getName(name) { function getName(name) {
return (name === '' ? undefined : name); return (name === '' ? undefined : name);
} }
@ -166,6 +179,20 @@ function loadObj(objPath, options) {
var zMag = Cartesian3.magnitude(zAxis); var zMag = Cartesian3.magnitude(zAxis);
var min = Math.min(xMag, yMag, zMag); var min = Math.min(xMag, yMag, zMag);
// If all the points are on a line, just remove one of the zero dimensions
if (xMag === 0 && (yMag === 0 || zMag === 0)) {
var i;
for (i = 0; i < positions.length; i++) {
positions2D[i] = new Cartesian2(positions[i].y, positions[i].z);
}
return positions2D;
} else if (yMag === 0 && zMag === 0) {
for (i = 0; i < positions.length; i++) {
positions2D[i] = new Cartesian2(positions[i].x, positions[i].y);
}
return positions2D;
}
var center = obb.center; var center = obb.center;
var planeXAxis; var planeXAxis;
var planeYAxis; var planeYAxis;
@ -200,7 +227,7 @@ function loadObj(objPath, options) {
Plane.fromPointNormal(origin, normal, plane); Plane.fromPointNormal(origin, normal, plane);
ray.direction = normal; ray.direction = normal;
for (var i = 0; i < positions.length; i++) { for (i = 0; i < positions.length; i++) {
ray.origin = positions[i]; ray.origin = positions[i];
var intersectionPoint = IntersectionTests.rayPlane(ray, plane, intPoint); var intersectionPoint = IntersectionTests.rayPlane(ray, plane, intPoint);
@ -279,6 +306,14 @@ function loadObj(objPath, options) {
return index; return index;
} }
function get3DPoint(index, result) {
var pi = getOffset(index, positions, 3);
var px = positions.get(pi + 0);
var py = positions.get(pi + 1);
var pz = positions.get(pi + 2);
return Cartesian3.fromElements(px, py, pz, result);
}
// Given a sequence of three points A B C, determine whether vector BC // Given a sequence of three points A B C, determine whether vector BC
// "turns" clockwise (positive) or counter-clockwise (negative) from vector AB // "turns" clockwise (positive) or counter-clockwise (negative) from vector AB
var scratch1 = new Cartesian3(); var scratch1 = new Cartesian3();
@ -333,6 +368,7 @@ function loadObj(objPath, options) {
var i; var i;
for (i = 0; i < vertices.length; ++i) { for (i = 0; i < vertices.length; ++i) {
var u = (defined(uvs)) ? uvs[i] : undefined; var u = (defined(uvs)) ? uvs[i] : undefined;
var n = (defined(normals)) ? normals[i] : undefined; var n = (defined(normals)) ? normals[i] : undefined;
@ -340,24 +376,18 @@ function loadObj(objPath, options) {
vertexIndices.push(index); vertexIndices.push(index);
// Collect the vertex positions as 3D points // Collect the vertex positions as 3D points
var pi = getOffset(index + 1, positions, 3); positions3D.push(get3DPoint(positions[i], new Cartesian3()));
var px = mesh.positions.get(pi + 0);
var py = mesh.positions.get(pi + 1);
var pz = mesh.positions.get(pi + 2);
positions3D.push(new Cartesian3(px, py, pz));
} }
var positions2D = projectTo2D(positions3D); var positions2D = projectTo2D(positions3D);
if (isConvex(positions2D)) { if (isConvex(positions2D)) {
// Use the fan method to triangulate
for (i=1; i < vertices.length-1; ++i) { for (i=1; i < vertices.length-1; ++i) {
primitive.indices.push(vertexIndices[0]); primitive.indices.push(vertexIndices[0]);
primitive.indices.push(vertexIndices[i]); primitive.indices.push(vertexIndices[i]);
primitive.indices.push(vertexIndices[i+1]); primitive.indices.push(vertexIndices[i+1]);
} }
} else { } else {
// Since the projection doesn't respect winding order, reverse the order of // Since the projection doesn't respect winding order, reverse the order of
// the vertices before triangulating to enforce counter clockwise. // the vertices before triangulating to enforce counter clockwise.
var windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D); var windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
@ -372,7 +402,66 @@ function loadObj(objPath, options) {
} }
} }
} }
}
function trimEmpty(entry) { return entry.trim() !== ''; }
// Parse a line of face data.
// Because face data can span multiple lines, attribute data is buffered in parallel lists
// faceVertices : names of a vertices for caching
// facePosition : indices into position array
// faceUvs : indices into uv array
// faceNormals : indices into normal array
function parseFaceLine(line, hasUvs, hasNormals) {
// get vertex data (attributes '/' separated)
faceVertices = faceVertices.concat(line.replace(faceSpacePattern, ' ').split(' ').filter(trimEmpty));
// get all vertex attributes for this line
var faceAttributes = line.replace(faceSpaceOrSlashPattern, ' ').split(' ').filter(trimEmpty);
var i;
if (hasUvs && hasNormals) {
for (i=0; i <= faceAttributes.length - 3; i += 3)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
faceNormals.push(faceAttributes[i+2]);
}
} else if (hasUvs) {
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
}
faceNormals = undefined;
} else if (hasNormals) {
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceNormals.push(faceAttributes[i+1]);
}
faceUvs = undefined;
} else {
for (i=0; i < faceAttributes.length; ++i)
{
facePositions.push(faceAttributes[i]);
}
faceUvs = undefined;
faceNormals = undefined;
}
// If there's a line continuation, buffer the results and don't create face yet
if (line.slice(-1) === '\\') {
return;
}
addFace(faceVertices, facePositions, faceUvs, faceNormals);
// Clear buffered data once face has been added.
faceVertices = [];
facePositions = [];
faceUvs = [];
faceNormals = [];
} }
function parseLine(line) { function parseLine(line) {
@ -418,38 +507,18 @@ function loadObj(objPath, options) {
} else if ((result = uvPattern.exec(line)) !== null) { } else if ((result = uvPattern.exec(line)) !== null) {
uvs.push(parseFloat(result[1])); uvs.push(parseFloat(result[1]));
uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image
} else { } else { // face line or invalid line
var faceVertices = line.replace(faceSpacePattern, ' ').substring(1).split(' '); // get vertex data (attributes '/' separated) // If we already have buffered data, this is a continued line
var faceAttributes = line.replace(faceSpaceOrSlashPattern, ' ').substring(1).split(' '); // get vertex attributes var continuedLine = faceVertices.length > 0;
var facePositions = [];
var faceUvs = [];
var faceNormals = [];
if (facePattern1.test(line)) { // format "f v v v ..." if (facePattern1.test(line) || (continuedLine && facePattern5.test(line))) { // format "f v v v ..."
addFace(faceVertices, faceAttributes, undefined, undefined); parseFaceLine(line, false, false);
} else if (facePattern2.test(line)) { // format "f v/uv v/uv v/uv ..." } else if (facePattern2.test(line) || (continuedLine && facePattern6.test(line))) { // format "f v/uv v/uv v/uv ..."
var i; parseFaceLine(line, true, false);
for (i=0; i <= faceAttributes.length - 2; i += 2) } else if (facePattern3.test(line) || (continuedLine && facePattern7.test(line))) { // format "v/uv/n v/uv/n v/uv/n ..."
{ parseFaceLine(line, true, true);
facePositions.push(faceAttributes[i]); } else if (facePattern4.test(line) || (continuedLine && facePattern8.test(line))) { // format "v//n v//n v//n ..."
faceUvs.push(faceAttributes[i+1]); parseFaceLine(line, false, true);
}
addFace(faceVertices, facePositions, faceUvs, undefined);
} else if (facePattern3.test(line)) { // format "v/uv/n v/uv/n v/uv/n ..."
for (i=0; i <= faceAttributes.length - 3; i += 3)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
faceNormals.push(faceAttributes[i+2]);
}
addFace(faceVertices, facePositions, faceUvs, faceNormals);
} else if (facePattern4.test(line)) { // format "v//n v//n v//n ..."
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceNormals.push(faceAttributes[i+1]);
}
addFace(faceVertices, facePositions, undefined, faceNormals);
} }
} }
} }