Three.js: MTLLoader: Cannot read property 'elements' of undefined

Created on 14 Nov 2017  路  11Comments  路  Source: mrdoob/three.js

Uncaught TypeError: Cannot read property 'elements' of undefined

at Matrix3.copy (three.module.js?0371:3277)
at refreshUniformsCommon (three.module.js?0371:23180)
at setProgram (three.module.js?0371:22963)
at WebGLRenderer.renderBufferDirect (three.module.js?0371:21822)
at renderObject (three.module.js?0371:22575)
at renderObjects (three.module.js?0371:22548)
at WebGLRenderer.render (three.module.js?0371:22312)
at Object3D.draw (Object3D.js?2363:160)`

I have a 3D model (.obj) using three from npm. This is an ES6 project using Webpack.

I am using these dependencies:

import * as THREE from 'three';
import OBJLoader from 'three-obj-loader';
import MTLLoader from 'three-mtl-loader';
import OrbitControls from 'three-orbitcontrols';

The model is resolved and loaded. Texture files are resolved and loaded - the .mtl and the single .png

If I call:

mtlLoader.load(materialUrl, ( materials ) => {
    materials.preload();

    objLoader.setMaterials( materials );

The app crashes on the error listed above. On objLoader.setMaterials.

If I comment that out the App works.

Three.js version
  • [ ] Dev
  • [ ] r88
  • [x] npm latest
Browser
  • [x] All of them
  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
OS
  • [] All of them
  • [x] Windows
  • [ ] macOS
  • [ ] Linux
  • [ ] Android
  • [ ] iOS
Hardware Requirements (graphics card, VR Device, ...)

NVIDIA GTX 970 in Sli. Asus motherboard. Output over HDMI 2.0. Doesn't seem to be related to either hardware, or OS.

Most helpful comment

In case someone else lands here from google: there is a new combined OBJ/MTLloader npm package that has solved this problem for me: https://www.npmjs.com/package/three-obj-mtl-loader

All 11 comments

Can you please provide a live example for debugging? Or maybe a reduced test case in a zip file? At least, share your OBJ and MTL file with all respective textures. Otherwise it will be hard to investigate this issue.

Sorry, but the assets are under NDA. I can provide the mtl file. I have also investigated the issue a bit:

# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 05.10.2016 13:42:24

newmtl Material__3337
    Ns 10.0000
    Ni 1.5000
    d 1.0000
    Tr 0.0000
    Tf 1.0000 1.0000 1.0000 
    illum 2
    Ka 0.5880 0.5880 0.5880
    Kd 0.5880 0.5880 0.5880
    Ks 0.0000 0.0000 0.0000
    Ke 0.0000 0.0000 0.0000
    map_Ka <removed>_2048_Diff.png
    map_Kd <removed>_2048_Diff.png

The issue is with the Kd map, which, I believe, is the diffuse map. Kindly note that the mtl file has multiple textures (even if technically using the same bitmap).

To get the material and texture applied, I had to bind them manually.

mtlLoader.load(materialUrl, ( materials ) => {

    materials.preload();

    // Load object after materials
    // loadingManager.onLoad = function(){
    // objLoader.setMaterials( materials );

    objLoader.load(
        modelUrl,
        // called when resource is loaded
        ( object ) => {
            const bbox = new THREE.Box3().setFromObject(object);
            const cameraPos = new THREE.Vector3( );
            materials.materials['Material__3337'].map = texture;

            object.traverse(function ( child ) {
                if ( child instanceof THREE.Mesh ) {
                    child.material = materials.materials['Material__3337'];
                }
            });

            scene.add( object );

I tried waiting until all assets were loaded (loadingManager.onload); no go. No loading error, but the material was not applied. I was able to get rid of the initial error, and get the texture applied when loading it manually.

See snippet above.

I should add: in this setup, we use webpack's file-loader to load obj, mtl, and all image types.
Hence, when loading assets at runtime, we use require(assetPath) and webpack-dev-server emits a valid url for the asset.

So: in any case I had to properly "prepare" the asset, by ensuring its url was emitted (require..).

But even with that: the material AND texture were only applied when I bound them explicitly.

Hard to help fixing this one without access to the problematic assets...

I understand. Unfortunately, the assets themselves are truly locked down.

As far as I understand the issue, it seems to have something to do with multi-materials.

Again, if I load and set objects and textures individually, it works. In this case for both the diffuse and normal maps.

Somehow, we'll have to get to the bottom of this. By improving the webpack config (and not using file-loader), and/or by finding the issue, or (more likely) by working around the MTLLoader itself. I'll make sure to update this thread if I actually track the root cause.

UV (not set) on multi/normal maps, but why.

In essence:

uvScaleMap.matrix is undefined

The loader loads the diffuse and normal maps, and seems to extrapolate a uvScaleMap based on that. But it doesn't have a matrix associated.

I eventually managed to work around this issue; I had to enable my webpack config to pass static assets through (as well as load them internally, on-demand, using import or require syntax).

After that, I was able to dynamically reload textures, based on the information "salvaged" from the MTLLoader, and reapply them to their respective slot.

This is sufficient for us, but - it might be worth giving the uvScaleMap reasonable defaults in case something otherworldly happens. uvScaleMap.matrix in our case remained undefined until I sideloaded the textures, and reapplied them.

Hi everyone, I meet the very similar problem with @maurocolella, with almost the same TypeError and similar code.

In my case, the .mtl file have only one image (a Kd map). The object file in my project is not managed by webpack. The program crashes when calling renderer.render.

So there might be something happening around uvScaleMap.matrix I think. The only usage of uvScaleMap is in src/renderers/WebGLRenderer.js from line 1991. and goes into line 1995, finally crashes on line 2051.

In MTLLoader.js, I notice that the matrix.map is edited at function setMapForType( mapType, value ) with mapType = "map". Then the loadTexture function.

I noticed that there is a texture = loader.load( url, onLoad, onProgress, onError ); call, (onLoad, onProgress, onError are null), the texture.matrix is mission from here. So I suspect something wrong in this loader, and expose it to document.xloader. Then I got these information in console:

> (new THREE.TextureLoader).load(url).matrix
Matrix3 {elements: Array(9)}

> document.xloader.load(url).matrix
undefined

So I go into node_modules/three_mtl_loader and update its THREE to 0.88. The error disappears.

However. My model still invisible... Once I try to check it in Three.js Inspector, it crashes in this function InspectedWin3js.getThreeJSClassName and then reset the model. After everything works will with Three.js Inspector.

Quiet strange. Waiting for more information.

Hi @maurocolella , I figured out my problem and it might work for you.

This warning message "Uncaught TypeError: Cannot read property 'elements' of undefined" is produced because of the "three-mtl-loader" from npm uses a old THREE version and its TextureLoader won't add matrix parameter after loading.

The solution is ask the maintainer of this package update it's package.json. Temporary solution is enter node_modules/.1.0.2@three-mtl-loader and run npm install three@latest --save to update it.

Thank you so much @eastpiger. I ended up working around this, as mentioned, by reloading textures explicitly.

@mrdoob , is there any way you could please help unify the distributions on npm?

.obj files are easy to produce, easy to maintain/export materials for, so I think it's quite likely that (commercial) users would turn to them as a quick way to get some 3d displayed.

Unfortunately, at this time, objloader and mtlloader are not part of the main threejs release on npm.

Perhaps a modular release on npm?

9562

@eastpiger boss. Thank you this was driving me crazy.

In case someone else lands here from google: there is a new combined OBJ/MTLloader npm package that has solved this problem for me: https://www.npmjs.com/package/three-obj-mtl-loader

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fuzihaofzh picture fuzihaofzh  路  3Comments

makc picture makc  路  3Comments

filharvey picture filharvey  路  3Comments

jlaquinte picture jlaquinte  路  3Comments

seep picture seep  路  3Comments