ColladaLoader can't load two different models - javascript

If I run the example below it gives me this error:
Uncaught TypeError: Cannot read property 'x' of undefinedt # three.min.js:462renderBuffer # three.min.js:549k # three.min.js:450render # three.min.js:561render # loaderTest.html:46
This is the last line where it calls render()
If I load two times the same model with loader.load(..) the error does not happen, it only occurs when I choose different models.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var light = new THREE.AmbientLight( 0xFFFFFF );
scene.add( light );
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load("models/model1.dae", function(colladaModel){
var model = colladaModel.scene;
model.position.set(0,0,0);
scene.add(model);
});
loader.load("models/model2.dae", function(colladaModel){
var model = colladaModel.scene;
model.position.set(20,0,0);
scene.add(model);
});
camera.position.z = 100;
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();

You're trampling on the model variable. The callback that you've provided doesn't run until the model is loaded, but it has already started loading the other one as well.
model = colladaModel.scene;
You didn't declare your variable model, which makes it a global variable which is thus shared browser-wide and between those two callbacks). It's actually window.model that you're using there.
Change them to:
var model = colladaModel.scene;

Related

ThreeJS Upload multiple textures for .obj

So I'm trying to upload a .obj file that also has multiple .png and .jpg files that are it's textures. The problem is I'm not sure how to even handle all these textures when they are uploaded.
Heres my code so far:
var loader = new THREE.OBJLoader(manager);
loader.load(obj_path, function (obj) {
model = obj;
modelWithTextures = true;
model.traverse( function ( child ) {
if ( child.isMesh ) child.material.map = texture;
} );
var textureLoader = new THREE.TextureLoader( manager );
var i;
for (var i = 0; i < files.length; i++) {
file = files[i];
console.log('Texture Files:' + files[i].name);
var texture = textureLoader.load(files[i].name);
}
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
setCamera(model);
setSmooth(model);
model.position.set(0, 0, 0);
setBoundBox(model);
setPolarGrid(model);
setGrid(model);
setAxis(model);
scaleUp(model);
scaleDown(model);
fixRotation(model);
resetRotation(model);
selectedObject = model;
outlinePass.selectedObjects = [selectedObject];
outlinePass.enabled = false;
renderer.render( scene, camera );
scene.add(model);
});
As you can see I'm using the textureLoader but just not sure what to do.
I'm very new to threeJS and 3d models.
Any help or advice would be much appreciated.
Thank you.
In your code, you probably won't see very much, because you render the scene before you add the model to the scene. You should render the scene after you did any changes (unless you have a render loop with requestAnimationFrame). Loading textures also is asynchronous. Use the callback of the .load method to better react when things are finished loading, e.g. trigger render().
I would load the textures within model.traverse() callback. But you have to determine which texture belongs to which mesh. This depends on how your data is structured.
var files = ['mesh1_tex.jpg', 'mesh2_tex.jpg'];
var loader = new THREE.OBJLoader( manager );
var textureLoader = new THREE.TextureLoader( manager );
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 0, -100); // depends on the size and location of your loaded model
var renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
var scene = new THREE.Scene();
loader.load(obj_path, function ( model ) {
model.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
// here you have to find a way how to choose the correct texture for the mesh
// the following is just an example, how it could be done, but it depends on your data
const file = files.find( f => f === child.name + '_tex.jpg');
if (!file) {
console.warn(`Couldn't find texture file.`);
return;
}
textureLoader.load(file, ( texture ) => {
child.material.map = texture;
child.material.needsupdate = true;
render(); // only if there is no render loop
});
}
} );
scene.add( model );
camera.lookAt( model ); // depends on the location of your loaded model
render(); // only if there is no render loop
});
function render() {
renderer.render( scene, camera );
}
Disclaimer: I just wrote down this code without testing.

In threejs, the value for setClearColor is white But it render black, when i call external html file?

In Three.js, the value for setClearColor is white But it render black, when i call external html file:
enter image description here
External file codes:
<div id="3d-modal"></div>
<script src="juicer/js/three.js"></script>
3D-modal scripts:
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,
window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({antialias : true});
// renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Appending Webgl to the "container" Div...
// document.body.appendChild( renderer.domElement );
var container = document.getElementById("3d-modal");
var canvas_width = 290;
var canvas_height = 165;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(canvas_width , canvas_height);
container.appendChild(renderer.domElement);
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
</script>
How can i solve this?
I came across this when I started using three.js as well. It's actually a javascript issue:
Update: Thanks to HdN8 for the updated solution:
renderer.setClearColor( 0xffffff, 0);
(note: syntax => setClearColor ( color, alpha ))
Update #2: As pointed out by WestLangley in another similar question - you must now use the below code when creating a new WebGLRenderer instance in conjunction with the setClearColor() function:
var renderer = new THREE.WebGLRenderer({ alpha: true });
Update #3: Mr.doob points out that since r78 you can alternatively use the code below to set your scene's background colour:
var scene = new THREE.Scene(); // initialising the scene
scene.background = new THREE.Color( 0xff0000 );
Update #4: G Dog
If the background color doesn't change, try changing alpha to 1 from 0.

Memory leak when updating material index in function animate() - three.js r84

Inspired by ParametricGeometries ( #author zz85 ), I have programmed an addon for three.js (named THREEf, updated 22.03.) to produce with only 9 properties, 18 functions and 1 array almost infinite many time-varying geometries:
geometry = new THREE.Geometry();
geometry.createMorphGeometry = THREEf.createMorphGeometry; // insert the methode from THREEf.js
geometry.createMorphGeometry(); // apply the methode ( here without parameters: all default )
After a while I noticed a memory leak. I thought I had made a mistake and searched the entire code. But nothing found! The error then suddenly disappeared when some code blocks were removed. The error occurs when the material index is renewed in the animate function.
geometry.faces[ index ].materialIndex = geometry.materialCover( .. , .. , t ); // in THREEf
respectively ( in animate() )
t = clock.getElapsedTime();
geometry.elementsNeedUpdate = true; // sufficient
// geometry.colorsNeedUpdate = true;
// material.needsUpdate = true;
geometry.faces[ 0 ].materialIndex = Math.floor( 5 * t ) % 3;
in the following very simple example that results in a fairly slow memory allocation.
'use strict'
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.set( 10, 20, 30 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xdddddd, 1 );
var container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var orbit = new THREE.OrbitControls( camera, renderer.domElement );
orbit.enableZoom = true;
var clock = new THREE.Clock( true );
var t; // time
var materials = [
new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide } ), // red
new THREE.MeshBasicMaterial( { color: 0x00ff00, side: THREE.DoubleSide } ), // green
new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide } ) // blue
];
var material = new THREE.MultiMaterial( materials );
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( -10, -10, -10 ) );
geometry.vertices.push( new THREE.Vector3( 10, -10, 0 ) );
geometry.vertices.push( new THREE.Vector3( 10, 10, 10 ) );
var face = new THREE.Face3( 0, 1, 2 );
geometry.faces.push( face );
scene.add( new THREE.Mesh( geometry, material ) );
animate();
//...............
function animate() {
requestAnimationFrame( animate );
t = clock.getElapsedTime();
geometry.elementsNeedUpdate = true;
//geometry.colorsNeedUpdate = true;
//material.needsUpdate = true;
geometry.faces[ 0 ].materialIndex = Math.floor( 5 * t ) % 3;
renderer.render( scene, camera );
controls.update();
}
<!DOCTYPE html>
<!-- memory leak -->
<html lang="de"><head><title> memory leak </title> <meta charset="utf-8" /></head>
<body> memory leak when updating material index in function animate()</body>
<script src="../js/three.min.84.js"></script>
<script src="../js/OrbitControls.js"></script>
See under http://threejs.hofk.de/memoryleak/memoryLeak.html
In my "function geometry", the browser crashes faster. You can try this at http://sandbox.threejs.hofk.de/ (currently only with Firefox)
and there is a way to basic examples - also other browsers.
There is a library of forms in progress.
I have looked in three.js but this is really great and I have too little knowledge to recognize something there.
How to fix the memory leak?
After WestLangley had answered my Question ( to change the face colors ) I have looked for many examples.
I have found the following:
https://github.com/mrdoob/three.js/blob/master/examples/webgl_objects_update.html
And in this example the answer is.
To change the faces you need
geometry.elementsNeedUpdate = true;
but to change the material index is used
geometry.groupsNeedUpdate = true;
This update is not available in the documentation
"How to update things" where I've looked.
There is the enumeration
object.updateMatrix();
...
geometry.elementsNeedUpdate = true;
...
texture.needsUpdate = true;
Then I looked in three.js revision 84 to the function DirectGeometry ().
I found this.groupsNeedUpdate = ...
It can be seen that the material index is related to the group.
Conclusion:
I just had to change a single command instead
geometry.elementsNeedUpdate = true;
now
geometry.groupsNeedUpdate = true;
and the sandbox has no memory leak anymore.
But if I want to change the faces as in the example https://github.com/mrdoob/three.js/blob/master/examples/webgl_objects_update.html
there is still a problem.
I used the test 50 (given 1000 slowly)
function animate() { setTimeout( animate, 50 ); ...
Then the memory leak occurs:
function randomizeFaces( object ) { ... geometry.elementsNeedUpdate = true; ...
I think then you have to use shader.

Error in loading physi.js and ammo.js

I'm trying to develop a project with physijs. I have encountered this type of error (from mozilla firefox console):
NetworkError: Failed to load worker script at "js/libs/ammo.js"
I'm trying to fix it but with no results. This is my code snippet on physijs setup:
<script src="build/three.js"></script>
<script src="js/libs/physi.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/Detector.js"></script>
<script>
'use strict';
Physijs.scripts.worker = 'js/libs/physijs_worker.js';
Physijs.scripts.ammo = 'js/libs/ammo.js';
All javascript files are in js directory, except for Three.js building files (that are in build directory). I have no idea what's wrong in my code, I create only lights, ground (compoud shapes following Physijs rules) and a bag (that I want to apply a cone-twist constaint but for previous reasons doesn't work).
I add even the code that I use to initialize the scene (if in case there is something wrong):
function createScene() {
var container = document.getElementById( 'container' );
//stats = new Stats();
//container.appendChild( stats.dom );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.x = 0;
camera.position.z = 17;
camera.position.y = 12;
//scene = new THREE.Scene();
scene = new Physijs.Scene;
scene.setGravity(new THREE.Vector3( 0, -10, 0 ));
renderer = new THREE.WebGLRenderer();
renderer.physicallyCorrectLights = true;
//renderer.gammaInput = true;
//renderer.gammaOutput = true;
renderer.shadowMap.enabled = true;
//renderer.shadowMapType = THREE.PCFSoftShadowMap;
//renderer.toneMapping = THREE.ReinhardToneMapping;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.target.set( 0, 0, 0 );
controls.noPan = true; //disable panning of orbit control
controls.noKeys = true; //disable arrow keys of orbit control
controls.update();
window.addEventListener( 'resize', onWindowResize, false );
window.addEventListener( 'keydown', onKeyDown, false );
window.addEventListener( 'keyup', onKeyUp, false );
}
How can I fix this problem and import correctly Physi.js?
SOLVED I used a local web server (Three.js's reference)and changed this:
Physijs.scripts.worker = 'js/libs/physijs_worker.js';
Physijs.scripts.ammo = 'ammo.js';

Three.js update scale object-size via view

i'm new in three.js and have a problem by scaling a object. I already looked at the documentation (https://github.com/mrdoob/three.js/wiki/Updates), but i don't really understand it at all.
My Problem: By changing a HTML-select-element the CubeGeometry should be scaled in the x-direction. That is already working BUT the "old" Cube do not disappear. So i have 2 Cubes. But i want only one Cube with the current size. I hope you can understand my problem ;-)
So here is my Code from the View:
$(document).on('change',".configurator > form select",function(event){
// update 3D-object - is that a nice way???
$.getScript("/javascripts/3D-animation.js.erb", function(){
// here comes the update
OBJECT3D.updateObject();
});
})
And here is my 3D-animation.js.erb:
var drawing_area;
var renderer;
var camera;
var obj;
var scene;
var OBJECT3D = {};
$(function() {
// get drawing_area
drawing_area = document.getElementById("canvas_wrapper");
// initialize renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(drawing_area.clientWidth, drawing_area.clientHeight);
renderer.setClearColor( 0xffffff, 1);
// add renderer to drawing_area
drawing_area.appendChild(renderer.domElement);
// initialize camera
camera = new THREE.PerspectiveCamera(45, drawing_area.clientWidth/drawing_area.clientHeight, 1, 100000);
camera.position.z = 1000;
camera.position.y = 100;
camera.position.x = 300;//-0.78;
// create texture
var texture = THREE.ImageUtils.loadTexture( "/images/materials/texture_1.jpg" );
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1, 1 );
// create object
var obj_form = new THREE.CubeGeometry(250,250,250);
var obj_material = new THREE.MeshLambertMaterial( { map: texture,ambient: 0x999999 } );
OBJECT3D.obj = new THREE.Mesh(obj_form, obj_material);
// so what do i need here?
OBJECT3D.obj.geometry.dynamic = true;
// OBJECT3D.obj.geometry.__dirtyVertices = true;
// OBJECT3D.obj.geometry.__dirtyNormals = true;
// OBJECT3D.obj.geometry.verticesNeedUpdate = true;
// create scene
scene = new THREE.Scene();
scene.add(camera);
scene.add(OBJECT3D.obj);
// create lights
pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.x = 400;
pointLight.position.y = 200;
pointLight.position.z = 1300;
scene.add(pointLight);
ambientLight = new THREE.AmbientLight( 0xffffff);
scene.add( ambientLight );
requestAnimationFrame(render);
function render(){
requestAnimationFrame(render);
OBJECT3D.obj.rotation.y += 0.005;
OBJECT3D.obj.rotation.z += 0.005;
renderer.render(scene, camera);
};
// update object
OBJECT3D.updateObject = function () {
console.log("in update");
OBJECT3D.obj.scale.x = 2.5; // SCALE
OBJECT3D.obj.geometry.needsUpdate = true;
//render();
}
});
Sorry, if the Code is not the best one, but i'm really new in this stuff! :) hope you can help me!
Thanks!
I think it is because you are using $.getScript method. This will load your script each time again and create a new instance of OBJECT3D.
I propose that you make sure that your code in 3D-animation.js.erb will be included and called only once upon the load of a page (include it just like any other regular javascript file) and then call your update directly like this:
$(document).on('change',".configurator > form select", function(event) {
OBJECT3D.updateObject();
});
also, I believe you can drop following lines of code:
OBJECT3D.obj.geometry.needsUpdate = true;
and
OBJECT3D.obj.geometry.dynamic = true;

Categories