-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
.mtl files support for .obj files to render color in 3D custom geometry #6710
Changes from 10 commits
a47fbbc
2143dba
3498ad0
5c7c07e
b46af55
0b7a1fe
77637ba
1169993
06c5e28
2b46a55
0790146
1fa08a2
be5cf6c
cd6039d
32f94f3
16fad39
c3538b7
3cb1a13
90a3a53
2fffa53
48b07a3
341b131
60a3b06
9538edc
56bc7f2
97950c7
4e46332
104463a
a4047af
7236340
b32c935
19e4655
14a2420
687e010
2aa937f
31bdeb9
ac68110
d7aa2f7
25bbdc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,8 @@ import './p5.Geometry'; | |
* @param {String} [fileType] | ||
* @return {p5.Geometry} the <a href="#/p5.Geometry">p5.Geometry</a> object | ||
*/ | ||
|
||
let materials = {}; //currently local | ||
p5.prototype.loadModel = function(path) { | ||
p5._validateParameters('loadModel', arguments); | ||
let normalize; | ||
|
@@ -150,16 +152,38 @@ p5.prototype.loadModel = function(path) { | |
} else if (fileType.match(/\.obj$/i)) { | ||
this.loadStrings( | ||
path, | ||
strings => { | ||
parseObj(model, strings); | ||
|
||
if (normalize) { | ||
model.normalize(); | ||
async lines => { | ||
const mtlLine = lines.find(line => line.startsWith('mtllib ')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the obj spec supports multiple mtls, so we might need to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought there could be just one mtl file to an obj file. After searching it through, yes there can be more. |
||
|
||
// console.log(mtlPath); | ||
try{ | ||
let parsedMaterials=null; | ||
if(mtlLine){ | ||
const mtlPath = path.replace(/\.obj$/, '.mtl'); | ||
parsedMaterials=await parseMtl(mtlPath); // Pass parsed materials to OBJ parsing | ||
} | ||
if (parsedMaterials){ | ||
await parseObj(model,lines, parsedMaterials); | ||
}else { | ||
await parseObj(model,lines); // No MTL file, parse OBJ directly | ||
} | ||
} catch (error) { | ||
if (failureCallback) { | ||
failureCallback(error); | ||
} else { | ||
p5._friendlyError('Error during parsing: ' + error.message); | ||
} | ||
} | ||
finally{ | ||
|
||
self._decrementPreload(); | ||
if (typeof successCallback === 'function') { | ||
successCallback(model); | ||
if (normalize) { | ||
model.normalize(); | ||
} | ||
|
||
self._decrementPreload(); | ||
if (typeof successCallback === 'function') { | ||
successCallback(model); | ||
} | ||
} | ||
}, | ||
failureCallback | ||
|
@@ -178,6 +202,54 @@ p5.prototype.loadModel = function(path) { | |
return model; | ||
}; | ||
|
||
function parseMtl(mtlPath){ //accepts mtlPath to load file | ||
return new Promise((resolve,reject)=>{ | ||
// console.log('parser is called'); | ||
let currentMaterial = null; | ||
p5.prototype.loadStrings( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think rather than calling this on this.loadStrings(
mtlPath,
(mtlLines) => {
const materials = parseMtl(mtlLines);
parseObj(model, lines, materials)
},
() => {
// handle failure
}
) Another benefit of this is that you maybe don't need |
||
mtlPath, | ||
lines => { | ||
for (let line = 0; line < lines.length; ++line){ | ||
const tokens = lines[line].trim().split(/\s+/); | ||
if(tokens[0] === 'newmtl') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice work on this parser, looks great! |
||
const materialName = tokens[1]; | ||
currentMaterial = materialName; | ||
materials[currentMaterial] = {}; | ||
}else if (tokens[0] === 'Kd'){ | ||
//Diffuse color | ||
materials[currentMaterial].diffuseColor = [ | ||
parseFloat(tokens[1]), | ||
parseFloat(tokens[2]), | ||
parseFloat(tokens[3]) | ||
]; | ||
} else if (tokens[0] === 'Ka'){ | ||
//Ambient Color | ||
materials[currentMaterial].ambientColor = [ | ||
parseFloat(tokens[1]), | ||
parseFloat(tokens[2]), | ||
parseFloat(tokens[3]) | ||
]; | ||
}else if (tokens[0] === 'Ks'){ | ||
//Specular color | ||
materials[currentMaterial].specularColor = [ | ||
parseFloat(tokens[1]), | ||
parseFloat(tokens[2]), | ||
parseFloat(tokens[3]) | ||
]; | ||
|
||
}else if (tokens[0] === 'map_Kd') { | ||
//Texture path | ||
materials[currentMaterial].texturePath = tokens[1]; | ||
} | ||
} | ||
resolve(materials); | ||
}, | ||
reject | ||
); | ||
}); | ||
|
||
} | ||
|
||
/** | ||
* Parse OBJ lines into model. For reference, this is what a simple model of a | ||
* square might look like: | ||
|
@@ -189,7 +261,7 @@ p5.prototype.loadModel = function(path) { | |
* | ||
* f 4 3 2 1 | ||
*/ | ||
function parseObj(model, lines) { | ||
function parseObj(model, lines, materials= {}) { | ||
// OBJ allows a face to specify an index for a vertex (in the above example), | ||
// but it also allows you to specify a custom combination of vertex, UV | ||
// coordinate, and vertex normal. So, "3/4/3" would mean, "use vertex 3 with | ||
|
@@ -205,6 +277,8 @@ function parseObj(model, lines) { | |
vn: [] | ||
}; | ||
const indexedVerts = {}; | ||
let currentMaterial = null; | ||
|
||
|
||
for (let line = 0; line < lines.length; ++line) { | ||
// Each line is a separate object (vertex, face, vertex normal, etc) | ||
|
@@ -213,7 +287,20 @@ function parseObj(model, lines) { | |
const tokens = lines[line].trim().split(/\b\s+/); | ||
|
||
if (tokens.length > 0) { | ||
if (tokens[0] === 'v' || tokens[0] === 'vn') { | ||
if (tokens[0] === 'usemtl') { | ||
// Switch to a new material | ||
currentMaterial = tokens[1]; | ||
if (currentMaterial && materials[currentMaterial]) { | ||
const diffuseColor = materials[currentMaterial].diffuseColor; | ||
model.vertexColors.push([ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we want to add to the diffuse colors for each vertex, where currently this is adding to the array once for each There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yes, the logic in my head was a little haywire and that's why I added to the array to |
||
diffuseColor[0], | ||
diffuseColor[1], | ||
diffuseColor[2] | ||
]); | ||
} else { | ||
model.vertexColors.push([1, 1, 1]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just thinking this through: when a model has vertex colors, then This would make for a good unit test btw: testing that if you import an obj that has materials, it uses the material colors when you draw it with |
||
} | ||
}else if (tokens[0] === 'v' || tokens[0] === 'vn') { | ||
// Check if this line describes a vertex or vertex normal. | ||
// It will have three numeric parameters. | ||
const vertex = new p5.Vector( | ||
|
@@ -285,7 +372,6 @@ function parseObj(model, lines) { | |
if (model.vertexNormals.length === 0) { | ||
model.computeNormals(); | ||
} | ||
|
||
return model; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
newmtl m000001 | ||
Ns 100 | ||
Kd 0 0 0.5 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m003627 | ||
Ns 100 | ||
Kd 0 0 0.942654 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m010778 | ||
Ns 100 | ||
Kd 0 0.815632 1 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m012003 | ||
Ns 100 | ||
Kd 0 0.965177 1 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m019240 | ||
Ns 100 | ||
Kd 0.848654 1 0.151346 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m021392 | ||
Ns 100 | ||
Kd 1 0.888635 0 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m022299 | ||
Ns 100 | ||
Kd 1 0.77791 0 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
||
newmtl m032767 | ||
Ns 100 | ||
Kd 0.5 0 0 | ||
Ks 1 1 1 | ||
Ka 0 0 0 | ||
Ni 1 | ||
d 1 | ||
illum 2 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
mtllib octa-color.mtl | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The plant obj is 9mb, which might slow down tests. Maybe for the missing material test, we can make a duplicate of this colored obj, but change the path from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, that's what I had thought of too, made the same changes already for |
||
v 1 0 0 | ||
v 0 1 0 | ||
v 0 0 1 | ||
v -1 0 0 | ||
v 0 -1 0 | ||
v 0 0 -1 | ||
usemtl m000001 | ||
f 1 5 6 | ||
usemtl m003627 | ||
f 2 1 6 | ||
usemtl m010778 | ||
f 1 2 3 | ||
usemtl m012003 | ||
f 4 2 6 | ||
usemtl m019240 | ||
f 4 5 3 | ||
usemtl m021392 | ||
f 5 4 6 | ||
usemtl m022299 | ||
f 2 4 3 | ||
usemtl m032767 | ||
f 5 1 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we use this btw? Looks like we always pass in materials as a parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes I had to remove it , missed it though.