-
-
Notifications
You must be signed in to change notification settings - Fork 36.2k
Fixed undefined attribute causing error with some GLTF models + meshes #14367
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
Conversation
|
Just want to double check... |
|
Hi @mrdoob this could very well be possible, and seems to be what causes the error. A simple undefined check fixes this, and the models load absolutely fine. What's strange, is that this bug does not occur just by loading the GLTF models themselves, I must additionally create a standard Plane mesh before the error occurs. |
Oh! I would prefer to understand exactly what is happening before blindly adding a undefined check... |
|
I understand your concern @mrdoob, and I can assure you that my code is not changing anything to undefined. So whilst I am not sure how this is happening when the GLTF model is loaded and another standard mesh is created purely with Three.js, this simple undefined check does fix it without any other symptoms. Please feel free to investigate the "why", but in the mean time if this fix could be implemented with at least a warning instead of an error that would be great! If you want to investigate further, whilst I couldn't create a JSFiddle demonstrating the bug, the project files at https://github.com/mrdoob/three.js/files/1372366/test.zip do demonstrate the problem and should be relatively easy for you to debug. |
|
@donmccurdy @takahirox any ideas guys? |
|
Sorry, I've been a bit busy. I'll look into soon. |
|
I can't see a problem with that model, even after adding a mesh with a PlaneGeometry to the scene. The model contains 86 meshes, all with |
|
Hi @donmccurdy, Well, this issue has happened to at least 2 of your users... if a simple undefined check fixes it, I don't see the harm in implementing this fix and at the very least just throwing up a warning if it isn't defined. This issue is definitely occurring for me, I'm unable to get it to occur with JSFiddle, but that doesn't mean it isn't happening. I'm happy to provide a video recording of the error occurring if that helps. It's going to be a lot of trouble for us to continue using Three.js for our project if we have to manually apply this fix every time we update. Please let me know any other way I can help to demonstrate the problem to you, if that's what it takes to get this check merged in. It's very important to us as we are very excited about the prospect of using Three.js for our upcoming project. Many thanks! |
I'm sorry, we can't just add checks just in case. If we did that kind of things the code would be much harder to read and understand.
If you can't reproduce with JSFiddle it may be a bug in your own code.
Anything helps. |
|
I will try to get a video of it tomorrow at work, I don't think it's a bug in my own code because but it might be environmental. For example the original reporter of this bug included his project and it was producing the error for him, similarly the error produces on my machine with the same code I tried putting into JSFiddle. This is on Chrome. Just to be clear, everything works fine with GLTF loading, until I add this code... The GLTF model is also added to "this.threeLayer.scene3D". For some reason having both causes that error to occur, I can have one or the other, but both at the same time doesn't work. So I don't see how my code could be causing the bug. I can also tell you from my logging that I iterate through every single BufferGeometry that gets loaded and they all have
The attributes (WebGLAttributes) It would seem to me that you guys are far more likely to be able to investigate this with good measure than I am, seeing as how this is your code base :) Thanks again! Edit: Where do the attributes even get added to the WebGLAttributes.buffers WeakMap for the renderer? |
|
@kurozael any chance you can create a jsfiddle? |
|
Hi @mrdoob, I created a JSFiddle, however the issue does not manifest itself there. What I cannot explain, and maybe you guys can help, is why even when .index is set to valid BufferAttribute values, sometimes the WebGLAttributes.get method can return undefined when passed in a value that is valid. Leads me to believe that in some circumstances, the WebGLAttributes are not properly updated or in sync. It would be good practice to throw in a check to ensure that the returned value is not undefined, at the very least, to prevent this bug from occuring. I appreciate that you are unable to reproduce it, but my team is unable to use Three.js to complete our project while this bug persists and it is a serious blocker for us. We can use a patched version, but this will present problems for us down the line. Edit: I've updated my local to use the newly release r94 and the bug no longer occurs. Very strange. |
I see... Should this be closed then? |
|
Sure @mrdoob, if the issue comes up again in a future version we can re-evaluate it. Thanks! |
|
I am having the same problem with R97 (attributes.get returning undefined). I made a video of the behaviour |
|
I made a second video to show more camera movement / culling? related behaviour. |
|
Also I just noticed getting this error: |
|
@DerKorb Please try to isolate the issue in a live example for debugging. Besides, I think it's better if you open a new issue which is focused on the view-dependent rendering problem. Your code seems a bit confusing to me. You declare |
|
You are right, i just pasted the second vis object into the same block. In my original code I had it in two different places. I found the reason for all the problems. I am using webpack to load some of my code from a custom npm module. Now when I imported THREE once in the module code and once in my app, webpack did create two instances of THREE. Without deep knowledge of THREE I assume both instances did have their own WebGL Context/Handle/whatever. So when I handed over geometries that had been allocated in one context to the renderer from the second context, attributes.get would somehow either get undefined or a reference to some random other geometry created in the same context as the renderer. |
|
@DerKorb Thanks for sharing your fix -- just saved me some time on similar behavior! |
|
@DerKorb thanks so much for this - seriously. In short - don't ever use two instances of
Uncaught TypeError: Cannot read property 'type' of undefined
at WebGLIndexedBufferRenderer.setIndex (three.js:15321)
at WebGLRenderer.renderBufferDirect (three.js:22689)
at renderObject (three.js:23343)
at renderObjects (three.js:23313)
at WebGLRenderer.render (three.js:23120)I did a small experiment to export And everything works. I would be very curious to know what is happening here, any ideas @mrdoob? Some kind of WebGL context confusion? |
No idea... Having a hard time to follow what it is you're trying to do. Any chance you can create a jsfiddle that shows the issue? |
|
As far as I see it:
|
|
😵 |
|
@DerKorb interesting. My use case is similar but perhaps slightly different,
import { AdditiveBlending } from 'three';
export const DEFAULT_MATERIAL_PROPERTIES = {
color: 0xff0000,
blending: AdditiveBlending,
fog: true,
};
/*global __dirname, require, module*/
const path = require('path');
let libraryName = 'ParticleSystemEngine';
let plugins = [],
outputFile;
outputFile = 'particle-system-engine.js';
const config = {
entry: __dirname + '/src/index.js',
devtool: 'source-map',
output: {
path: __dirname + '/build',
filename: outputFile,
library: libraryName,
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
loader: 'babel-loader',
exclude: /(node_modules)/,
},
{
test: /(\.jsx|\.js)$/,
loader: 'eslint-loader',
exclude: /node_modules/,
},
],
},
resolve: {
modules: [path.resolve('./src'), path.resolve('./node_modules')],
extensions: ['.json', '.js'],
},
plugins: plugins,
};
module.exports = config;
I do this because I need to create a
import * as THREE from 'three';
import { ParticleSystemEngine } from './core';
export * from './behaviour';
export * from './debug';
export * from './ease';
export * from './emitter';
export * from './initializer';
export * from './math';
export * from './renderer';
export * from './utils';
export * from './zone';
export { ParticleSystemEngine, Particle, Pool } from './core';
export default ParticleSystemEngine;
export { THREE }; // note this exportThen in my example, instead of using a script tag to load <script src="../js/particle-system-engine.js"></script>
<script>
let particleSystem;
const { THREE } = ParticleSystemEngine; // this works because it was exported from my module
const scene = new THREE.Scene();
ParticleSystemEngine.fromJSONAsync(jsonContainingTexturesToLoad)
.then(engine => {
particleSystem = engine;
})
.catch(console.error);
</script>This resolves the error. But I am confused as to why. I do not set up a Sorry for the essay! I think webpack is definitely at fault here, but I also am wondering about the internals of three and how this kind of error could occur. |
|
For another simple case I've seen fail: if ( object instanceof Mesh ) {
// ...
}If there are two copies of three.js in the page, there are two copies of Mesh, Texture, and other classes. This will cause |
|
@mrdoob Here's some codesandboxes
I tried switching out my module bundler from webpack to parcel and it didn't resolve the issue. Also, would #12380 be a better place to track this? At the moment my only resolution is to drop script tag support for my module, which I am uncomfortable with, but can make do for now. This will mean that consumers will simply have to be in a transpile targeting environment in order to use my code. |
|
Okay I had a hunch about this and was able to fix it. Posting the solution here for anyone else who comes across this error. I created an internal compatibility module that conditionally requires const isBrowser = typeof window !== 'undefined' ? true : false;
const THREE = isBrowser && window.THREE ? window.THREE : require('three');
export const {
BoxGeometry,
Euler,
Geometry,
Mesh,
MeshBasicMaterial,
MeshLambertMaterial,
OctahedronGeometry,
SphereGeometry,
Sprite,
SpriteMaterial,
Texture,
TextureLoader,
Vector3,
AdditiveBlending,
CustomBlending,
MultiplyBlending,
NoBlending,
NormalBlending,
SubtractiveBlending,
} = THREE;My tests pass in a node environment and my issue is now fixed if you use script tags. |
|
Thanks to everyone sharing their experience here! I had the same issue, which boiled to a forgotten |
|
I just debugged my app for a whole night. ReasonAs @donmccurdy and @rohan-deshpande have said, the whole thing fails when there are multiple threes on the scene. So I'm using a library https://github.com/vue-gl/vue-gl which in the package.lock has declared its SolutionI replaced all my P.S. This reminded me of a similar problem I had with |
|
I found another solution for my react app (create-react-app without eject) with typescript.
import * as THREE from 'three';
window.THREE = THREE;
const exportTHREE = window.THREE;
export default exportTHREE;
const threeModulesToConnect = [import('three/examples/js/loaders/GLTFLoader')];
Promise.all(threeModulesToConnect).then(() => {
ReactDOM.render(<App />, document.getElementById('root'));
});
declare module 'modules/three-exp' {
import * as THREE from 'three';
const GLTFLoader: any;
export = {...THREE, GLTFLoader};
} |
|
Experienced the same issue here when using aframe. We have a React app that:
This caused the exact same issue as described by others in this thread. We fixed it similarly to @rohan-deshpande's solution and use only Annoyingly we can't completely remove the extra Many thanks to everyone in this thread for figuring this out! |
This small fix makes sure that some loaded GLTF models work with other basic mesh types without causing the strange error referenced in this issue: #12380