Skip to content

Commit 1f1b4ed

Browse files
authored
Merge pull request #9110 from Nixxx19/fix/single-material-maps
GSOC 26: apply mtl material state to single-material models
2 parents 7e34b03 + d7df5cb commit 1f1b4ed

4 files changed

Lines changed: 50 additions & 3 deletions

File tree

src/webgl/loading.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,21 @@ async function loadMaterialTextures(materials, modelPath, instance) {
190190
// as the aggregate; each part gets its own localised verts with faces re-indexed
191191
// against them, plus its material's state.
192192
function buildMaterialParts(model, faceMaterials, materials) {
193-
// only split when there are genuinely multiple materials. a single material
194-
// (or none) stays as the geometry's own part and renders as before. one group
195-
// per material, plus a null group for faces before any usemtl so none drop.
193+
// one group per material, plus a null group for faces before any usemtl so
194+
// none drop.
196195
const names = [...new Set(faceMaterials)];
196+
197+
// one material covering every face. the geometry is already its own part, so
198+
// hand it the state directly: splitting would duplicate every vertex to say
199+
// the same thing, and would stop parts[0] being the geometry itself. without
200+
// this a single material model never receives its maps at all.
201+
if (names.length === 1 && names[0] != null) {
202+
Object.assign(model.partState, mtlToPartState(materials[names[0]]));
203+
return;
204+
}
205+
206+
// nothing to split on: no materials, or one material alongside faces that
207+
// were declared before any usemtl and so have none.
197208
if (names.filter(name => name != null).length < 2) return;
198209

199210
const hasUvs = model.uvs.length > 0;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
newmtl only
2+
Kd 1.000 1.000 1.000
3+
Ks 0.500 0.500 0.500
4+
Ns 60
5+
map_Kd cat.jpg
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
mtllib single_material_textured.mtl
2+
v 0 0 0
3+
v 1 0 0
4+
v 1 1 0
5+
v 0 1 0
6+
vt 0 0
7+
vt 1 0
8+
vt 1 1
9+
vt 0 1
10+
usemtl only
11+
f 1/1 2/2 3/3
12+
f 1/1 3/3 4/4

test/unit/io/loadModel.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,25 @@ suite('loadModel', function () {
159159
assert.equal(model.parts[0], model, 'the geometry is its own single part');
160160
});
161161

162+
test('a single-material OBJ still receives its maps', async function () {
163+
const fakeImage = { width: 1, height: 1 };
164+
mockP5Prototype.loadImage = async () => fakeImage;
165+
try {
166+
const model = await mockP5Prototype.loadModel(
167+
'/test/unit/assets/single_material_textured.obj'
168+
);
169+
// one material, so no split: the geometry stays its own only part
170+
assert.equal(model.parts.length, 1);
171+
assert.equal(model.parts[0], model);
172+
// and it carries the material's state rather than dropping it
173+
assert.equal(model.partState.texture, fakeImage);
174+
assert.equal(model.partState.shininess, 60);
175+
assert.deepEqual(model.partState.specularColor, [0.5, 0.5, 0.5]);
176+
} finally {
177+
delete mockP5Prototype.loadImage;
178+
}
179+
});
180+
162181
test('a 12-material OBJ splits into 12 parts', async function () {
163182
const model = await mockP5Prototype.loadModel(
164183
'/test/unit/assets/multi_material_12.obj'

0 commit comments

Comments
 (0)