-
-
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 5 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 |
---|---|---|
|
@@ -104,7 +104,6 @@ import './p5.Geometry'; | |
* @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,18 +149,37 @@ p5.prototype.loadModel = function(path) { | |
failureCallback | ||
); | ||
} else if (fileType.match(/\.obj$/i)) { | ||
const mtlFiles=[]; | ||
var mtlPath=''; | ||
var parsedMaterials={}; | ||
this.loadStrings( | ||
path, | ||
async lines => { | ||
const mtlLine = lines.find(line => line.startsWith('mtllib ')); | ||
|
||
// console.log(mtlPath); | ||
const mtlPromises = lines | ||
.map(line => line.trim().split(/\b\s+/)) | ||
.filter(tokens => tokens[0] === 'mtllib') | ||
.map(async tokens => { | ||
const objFileDir = path.substring(0, path.lastIndexOf('/')); | ||
//because path.dirname does not exist error to get path of mtlfiles | ||
|
||
// Replace the file name in the path with the MTL file name | ||
//find a better way to resolve path | ||
if(objFileDir){ | ||
mtlPath = objFileDir + '/' + tokens[1]; | ||
} | ||
else{ | ||
mtlPath=tokens[1]; | ||
} | ||
// Check if the MTL file has already been loaded | ||
const existingMtl = mtlFiles.find(mtl => mtl.path === mtlPath); | ||
if (!existingMtl) { | ||
// If not loaded, load and parse the MTL file | ||
parsedMaterials = await parseMtl(self, mtlPath); | ||
mtlFiles.push({ path: mtlPath, materials: parsedMaterials }); | ||
} | ||
}); | ||
await Promise.all(mtlPromises); | ||
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 { | ||
|
@@ -173,8 +191,7 @@ p5.prototype.loadModel = function(path) { | |
} else { | ||
p5._friendlyError('Error during parsing: ' + error.message); | ||
} | ||
} | ||
finally{ | ||
}finally{ | ||
|
||
if (normalize) { | ||
model.normalize(); | ||
|
@@ -202,52 +219,51 @@ 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( | ||
mtlPath, | ||
lines => { | ||
for (let line = 0; line < lines.length; ++line){ | ||
const tokens = lines[line].trim().split(/\s+/); | ||
if(tokens[0] === 'newmtl') { | ||
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]; | ||
} | ||
async function parseMtl(self,mtlPath){ //accepts mtlPath to load file | ||
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. Maybe we can call |
||
let materials= {}; | ||
let currentMaterial = null; | ||
self.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. It looks like this function completes without waiting for the result of const materials = {};
const doneLoading = new Promise((resolve, reject) => {
self.loadStrings(
mtlPath,
lines => {
// do parsing and add to materials here
resolve();
},
reject
)
});
await doneLoading;
return materials; 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. @davepagurek I changed my multiple mtl file support functionality to this:
now single mtl file' materials are fully loaded first and then only passed to parseObj but for multiple files, materials are still being passed before fully loading thus the error: p5.js says: Error during parsing: Cannot read properties of undefined (reading 'diffuseColor') In the earlier approach even after adding resolve, reject back and some other changes too, still the parseObj was called beforehand. where is the logic breaking in the current code that single mtl files are passed after materials fully loading but not multiple mtl files? I'm trying to still find since I used 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 tried using a counter to ensure parseObj is called after parsedMaterials are loaded like this:
and then,
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. A few little things:
Let me know if I can help elaborate on any of those points! 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. @davepagurek below is the parseMtl function:
|
||
mtlPath, | ||
lines => { | ||
for (let line = 0; line < lines.length; ++line){ | ||
const tokens = lines[line].trim().split(/\s+/); | ||
if(tokens[0] === 'newmtl') { | ||
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 | ||
); | ||
}); | ||
|
||
} | ||
}, | ||
error => { | ||
p5._friendlyError('Error during parsing: ' + error.message); | ||
} | ||
); | ||
return materials; | ||
} | ||
|
||
/** | ||
|
@@ -290,16 +306,6 @@ function parseObj(model, lines, materials= {}) { | |
if (tokens[0] === 'usemtl') { | ||
// Switch to a new material | ||
currentMaterial = tokens[1]; | ||
if (currentMaterial && materials[currentMaterial]) { | ||
const diffuseColor = materials[currentMaterial].diffuseColor; | ||
model.vertexColors.push([ | ||
diffuseColor[0], | ||
diffuseColor[1], | ||
diffuseColor[2] | ||
]); | ||
} else { | ||
model.vertexColors.push([1, 1, 1]); | ||
} | ||
}else if (tokens[0] === 'v' || tokens[0] === 'vn') { | ||
// Check if this line describes a vertex or vertex normal. | ||
// It will have three numeric parameters. | ||
|
@@ -308,6 +314,11 @@ function parseObj(model, lines, materials= {}) { | |
parseFloat(tokens[2]), | ||
parseFloat(tokens[3]) | ||
); | ||
const diffuseColor = | ||
currentMaterial && materials[currentMaterial] ? | ||
materials[currentMaterial].diffuseColor : [1, 1, 1]; // Default to white if no material | ||
model.vertexColors.push(diffuseColor); | ||
|
||
loadedVerts[tokens[0]].push(vertex); | ||
} else if (tokens[0] === 'vt') { | ||
// Check if this line describes a texture coordinate. | ||
|
@@ -399,6 +410,7 @@ function parseSTL(model, buffer) { | |
const lineArray = lines.split('\n'); | ||
parseASCIISTL(model, lineArray); | ||
} | ||
console.lof(model.vertexcolors); | ||
return model; | ||
} | ||
|
||
|
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.
I think this is a bit of a race condition, since we only push to the array after
await
ing an asynchronous function. Maybe you can synchronously push an object that just includes the path, and then afterawait
ing, add the materials to it? something like: