backbone.js - Having multiple instances of the same view - javascript

I am having problems having multiple instances in of the same view in different div elements. When I try to initialize them only the second of the two elements appear no matter what order I put them in.
Here is the code for my view.
var BodyShapeView = Backbone.View.extend({
thingiview: null,
scene: null,
renderer: null,
model: null,
mouseX: 0,
mouseY: 0,
events:{
'click button#front' : 'front',
'click button#diag' : 'diag',
'click button#in' : 'zoomIn',
'click button#out' : 'zoomOut',
'click button#on' : 'rotateOn',
'click button#off' : 'rotateOff',
'click button#wireframeOn' : 'wireOn',
'click button#wireframeOff' : 'wireOff',
'click button#distance' : 'dijkstra'
},
initialize: function(name){
_.bindAll(this, 'render', 'animate');
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 15, 400 / 700, 1, 4000 );
camera.position.z = 3;
scene.add( camera );
camera.position.y = -5;
var ambient = new THREE.AmbientLight( 0x202020 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.75 );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
var pointLight = new THREE.PointLight( 0xffffff, 5, 29 );
pointLight.position.set( 0, -25, 10 );
scene.add( pointLight );
var loader = new THREE.OBJLoader();
loader.load( "img/originalMeanModel.obj", function ( object ) {
object.children[0].geometry.computeFaceNormals();
var geometry = object.children[0].geometry;
console.log(geometry);
THREE.GeometryUtils.center(geometry);
geometry.dynamic = true;
var material = new THREE.MeshLambertMaterial({color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors });
mesh = new THREE.Mesh(geometry, material);
model = mesh;
// model = object;
scene.add( model );
} );
// RENDERER
renderer = new THREE.WebGLRenderer();
renderer.setSize( 400, 700 );
$(this.el).find('.obj').append( renderer.domElement );
this.animate();
},
Here is how I create the instances
var morphableBody = new BodyShapeView({ el: $("#morphable-body") });
var bodyShapeView = new BodyShapeView({ el: $("#mean-body") });
Any help would be really appreciated.
Thanks in advance.

In your initializemethod, you access global variables instead of instance variables: scene = new THREE.Scene(); will in fact reference window.scene.
Check this example
var BodyShapeView = Backbone.View.extend({
scene:null,
initialize:function(opts) {
scene=opts.scene;
}
});
var s1=new BodyShapeView({scene:'s1'});
var s2=new BodyShapeView({scene:'s2'});
console.log(window.scene); //outputs s2
console.log(s1.scene); //outputs null
http://jsfiddle.net/K8tjJ/1/
Change these references to this.scene, this.camera, etc.
var BodyShapeView = Backbone.View.extend({
scene:null,
initialize:function(opts) {
this.scene=opts.scene;
}
});
var s1=new BodyShapeView({scene:'s1'});
var s2=new BodyShapeView({scene:'s2'});
console.log(window.scene); //outputs undefined
console.log(s1.scene); //outputs s1
http://jsfiddle.net/K8tjJ/2/
Additionally, loader.load uses a callback to process its results, you will (probably) lose the reference to this in the function. Try
var _this=this;
loader.load( "img/originalMeanModel.obj", function ( object ) {
...
_this.scene.add( _this.mesh ); // or _this.model if you prefer, but beware
});
Note that this.model is a special variable in Backbone.View and should be treated with care if you ever want to pass a model to your view.

The el attribute only needs a jQuery style selector string. Try:
var morphableBody = new BodyShapeView({ el: "#morphable-body" });
var bodyShapeView = new BodyShapeView({ el: "#mean-body" });
UPDATE
Also, your problem may be that you're not using the this keyword when defining scene, camera, and renderer. It could be that the second view is overwriting the first view as a result. Try:
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera( 15, 400 / 700, 1, 4000 );
...
// RENDERER
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize( 400, 700 );
$(this.el).find('.obj').append( this.renderer.domElement );

Related

boundingSphere is null - TextGeometry, ThreeJS

I'm new at ThreeJS and trying to learn so I have basically create a text which is rendered 3D and I'm using TextGeometry and I need that object's size like width/height to always center the object.
I'm trying like this;
var objToCenter = scene.getObjectById(textGeoID);
var hey = objToCenter.geometry.boundingSphere.center.x;
console.log(hey);
First, I find the object and then assign boundingSphere.center.x value to new variable.
But I get "boundingSphere is null" error.
When I try to console.log objectToCenter, object is there and also boundingSphere is NOT null but when I try objectToCenter.boundingSphere it says null.
And interestingly when I go console and write these lines it works perfectly.
My full Code: (somehow fontloader not load the font from source url but it works in localhost,so pls try code in localhost or you can't see the text here)
// Scene, Camera, Renderer, GUI
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 } );
var gui = new dat.GUI({name: 'Control Panel'});
// Renderer and Camera Settings
renderer.setSize( window.innerWidth, window.innerHeight-4 );
renderer.shadowMap.enabled = false;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild( renderer.domElement );
camera.position.set( 10, 10, 500 );
// Axiss Helper and Orbit Controls
var axesHelper = new THREE.AxesHelper( 500 );
scene.add( axesHelper );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
// Variables for TextGeometry
var textData = {
text: "Yunus Emre Uzun",
size: 40,
height: 5,
curveSegments: 12,
font: "helvetiker",
weight: "regular",
bevelEnabled: false,
bevelThickness: 1,
bevelSize: 0.5,
bevelOffset: 0.0,
bevelSegments: 3
};
var textGeoID = null;
function generateTextGeometry() {
if (textGeoID!=null) {
console.log('ID: ' + textGeoID);
var object = scene.getObjectById(textGeoID);
//console.log('Object:');
//console.log(object);
object.geometry.dispose();
scene.remove(object);
}
var loader = new THREE.FontLoader();
loader.load( 'https://clofro.com/cdn/fonts/helvetiker_regular.typeface.json', function ( font ) {
var textGeometry = new THREE.TextGeometry( textData.text, {
font: font,
size: textData.size,
height: textData.height,
curveSegments: textData.curveSegments,
bevelEnabled: textData.bevelEnabled,
bevelThickness: textData.bevelThickness,
bevelSize: textData.bevelSize,
bevelOffset: textData.bevelOffset,
bevelSegments: textData.bevelSegments
} );
var textMaterial = new THREE.MeshBasicMaterial( { color: 0x444444, wireframe: true } );
var meshedObject = new THREE.Mesh( textGeometry, textMaterial );
meshedObject.position.set(-212, -15, 20 /* 15 */);
scene.add(meshedObject);
textGeoID = meshedObject.id;
centerTheText();
} );
}
function centerTheText() {
var objToCenter = scene.getObjectById(textGeoID);
console.log('Object bellow is objToCenter and its id is: ' + objToCenter.id);
console.log(objToCenter);
console.log('Error bellow is for: objToCenter.geometry.boundingSphere.center.x');
var hey = objToCenter.geometry.boundingSphere.center.x;
console.log(hey);
}
generateTextGeometry();
gui.add(textData, 'text').onChange(generateTextGeometry);
gui.add(textData, 'size', 5, 100).onChange(generateTextGeometry);
// Add Point Light
var pointLight = new THREE.PointLight(0xffffff, 0.3); pointLight.position.set(50, 0, 150);
pointLight.castShadow = true;
pointLight.shadow.mapSize.width = 2048;
pointLight.shadow.mapSize.height = 2048;
scene.add(pointLight);
// Random colors
//pointLight.color.setHSL(Math.random(), 1, 0.5);
// Add Ambiant Light - halogen ambient light
var ambientLight = new THREE.AmbientLight(0xFFF1E0, 0.4);
scene.add(ambientLight);
var width = 450;
var height = 60;
var intensity = 0.8;
var rectLight = new THREE.RectAreaLight( 0xff0000, intensity, width, height );
rectLight.position.set( 0, 0, 14 );
rectLight.rotation.y = 6.28;
rectLight.lookAt( 0,0,0 );
scene.add( rectLight )
gui.add(rectLight, 'intensity', 0,5);
rectLightHelper = new THREE.RectAreaLightHelper( rectLight );
rectLight.add( rectLightHelper );
// Create BackBox Shape
var backBoxGeo = new THREE.BoxGeometry(500, 75, 10);
// Create BackBox Material, color, texture
var backBoxMat = new THREE.MeshStandardMaterial( { color: 0xdaf1f9, wireframe: false, flatShading: false } );
var backBox = new THREE.Mesh( backBoxGeo, backBoxMat );
backBox.receiveShadow = true;
scene.add(backBox);
backBox.position.set(0, 0, 0);
// Resize Renderer Function
window.addEventListener('resize', function() {
renderer.setSize( window.innerWidth, window.innerHeight-4 );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
// Update scene
var update = function() {
controls.update();
};
// Draw scene
var render = function() {
renderer.render( scene, camera );
};
// Frame loop (update, render, repeat)
var frameLoop = function() {
requestAnimationFrame( frameLoop );
update();
render();
}
frameLoop();
* {
margin: 0;
padding: 0;
}
body { background-color: #000; }
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>threeJS</title>
</head>
<body>
<script src="https://clofro.com/cdn/three.js"></script>
<script src="https://clofro.com/cdn/dat.gui.min.js"></script>
<script src="https://clofro.com/cdn/OrbitControls.js"></script>
</body>
</html>
My explanations with SS;
Screenshot 1:
Screenshot 2:
Why it could be happening? or can I use something else to center my text.
(set position not a fix because 0,0,0 is different for box objects and texts)
When you create an instance of TextGeometry, the respective bounding sphere is not available yet. However, it is automatically computed by the renderer for view frustum culling.
So if you have to access the bounding sphere of the geometry right after its creation, call objToCenter.geometry.computeBoundingSphere();.
Live Demo: https://jsfiddle.net/zcn2tpqy/
three.js R107
I know this is too old to answer, but I just want to share my solution here.
First, I just added this code:
geometry.computeBoundingSphere()
Then, access the boundingSphere like so:
geometry.boundingSphere
Overall code
geometry.computeBoundingSphere()
console.log(geometry.boundingSphere.radius)

Change color of three.js mesh using gui.dat

I have a three.js mesh loaded from an STL file:
var loader = new THREE.STLLoader();
var materialmodel = new THREE.MeshPhongMaterial(
{
color: 0xFF0000,
specular: 0x222222,
shininess: 75
}
);
function model()
{
loader.load( 'models/stl/binary/model.stl', function ( geometry ) {
var meshMaterial = materialmodel;
var model = new THREE.Mesh( geometry, meshMaterial );
model.scale.set( 0.02, 0.02, 0.02 );
model.castShadow = true;
model.receiveShadow = true;
model.geometry.center();
scene.add(model);
render();
} );
}
model();
When I call the model function in my page, the model renders as expected.
I want to use dat.gui to as a lightweight interface for on the fly changes.
My first experiment is changing the color of the model.
The code I'm using is this:
var params = {
modelcolor: 0xff0000, //RED
};
var gui = new dat.GUI();
var folder = gui.addFolder( 'Model Colour' );
folder.addColor( params, 'modelcolor' )
.name('Model Color')
.listen()
.onChange( function() { materialmodel.MeshPhongMaterial.color.set( params.modelcolor); } );
folder.open();
DAT.GUIs color picker appears fine, and I can select a color from the picker and the new hex value will display.
However, the model/mesh itself doesn't update with the newly selected colour.
I'm wondering if it's something to do with how I'm changing the color materialmodel.MeshPhongMaterial.color.set( params.modelcolor); (I've tried different ways of doing this with no luck).
I've seen a post here (one of the answers) where they're doing this using model.material.color.set(params.color) in their example. My owen material properties are defined in a variable using a THREE.MeshPhongMaterial.....
Assuming this is where I've gone wrong, how can I change the color dynamically of a nested prroperty buried in a variable like this?
I didn't get why did you use .listen(), possibly there's a certain reason.
In .onUpdate function you're using materialmodel, which is a material itself, and then you're setting .MeshPhongMaterial property that doesn't exist. Looks like you simply overlooked it.
Here is a working example:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var materialmodel = new THREE.MeshPhongMaterial({
color: 0xFF0000,
specular: 0x222222,
shininess: 75
});
var geometrymodel = new THREE.SphereBufferGeometry(5, 32, 16);
var model = new THREE.Mesh(geometrymodel, materialmodel);
scene.add(model);
var params = {
modelcolor: "#ff0000"
};
var gui = new dat.GUI();
var folder = gui.addFolder('Model Colour');
folder.addColor(params, 'modelcolor')
.name('Model Color')
.onChange(function() {
materialmodel.color.set(params.modelcolor);
});
folder.open();
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>

three.js mtl loader renders black

I am trying to add a level .obj for my program but it renders black. The .mtl file requires several images placed everywhere (not one space is non-textured). I used to same object in my last project and it works, but it doesn't in my current project. When I remove the materials the lighting affects it, but when I add it, it is pitch black. The renderer renders continously. Also, there are no errors in the console.
Here is the code used in my current project: (MaterialLoader is an MTLLoader instance and ObjectLoader is an OBJLoader instance)
MaterialLoader.load("bbb/bbb.mtl",
function(materials) {
materials.preload()
ObjectLoader.setMaterials(materials)
ObjectLoader.load("bbb.obj",
function(model) {
let mesh = model.children[0]
scene.add(mesh)
}, null, function(error) {alert(error)}
)
}, null, function(error) {alert(error)}
)
Here is the code from my previous project (the loader variable is an OBJLoader instance, and the materials load successfully here.)
mtlLoader.load(
"bbb.mtl",
function(materials) {
materials.preload()
loader.setMaterials(materials)
loader.load("bbb.obj",
function(obj) {
level = obj.children[0]
scene.add(level)
}, null,
function(error) { alert(error) }
)
}, null,
function(error) { alert(error) }
)
https://discourse.threejs.org/t/objloader-mtlloader-not-loading-texture-image/2534
try change object material color, like this:
model.children[0].material.color.r = 1;
model.children[0].material.color.g = 1;
model.children[0].material.color.b = 1;
its work for me
Your code works when tested! Maybe it's an issue with the material export, uv unwrapping, the texture's path, do you have lighting added to the scene, etc. Here's my test code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,320/240,1,500);
camera.position.set( 0,2,2 );
camera.lookAt( scene.position );
var lightIntensity = 1;
var lightDistance = 10;
var light = new THREE.AmbientLight( 0xFFFFFF, lightIntensity, lightDistance );
light.position.set( 0, 5, 0 );
scene.add( light );
var grid = new THREE.GridHelper(10,10);
scene.add( grid );
var renderer = new THREE.WebGLRenderer({});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( 320,240 );
renderer.domElement.style.margin = '0 auto';
renderer.domElement.style.display = 'block';
renderer.domElement.style.backgroundColor = '#dddddd';
$(document.body).append(renderer.domElement);
function update(){
renderer.render( scene, camera );
requestAnimationFrame( update );
}
update();
mtl_loader = new THREE.MTLLoader();
mtl_loader.load("assets/doughnut.mtl",
function(materials) {
materials.preload()
var obj_loader = new THREE.OBJLoader();
obj_loader.setMaterials(materials)
obj_loader.load("assets/doughnut.obj",
function(object) {
let mesh = object.children[0]
scene.add(mesh);
}, null, function(error) {alert(error)}
)
}, null, function(error) {alert(error)}
);

Multiple scenes and multiple .obj models in Three.js

I am stuck with loading in two .obj models into two different div elements.
Currently, both objects end up in the last div element, as seen here:
https://casagroupproject.github.io/template1/test.html
My code is based on this example here:
https://threejs.org/examples/?q=mul#webgl_multiple_elements
I create an array with my models stored in:
var canvas;
var scenes = [], renderer;
var scene;
//external geometries
var models = {
tent: {
obj:"./assets/Tent_Poles_01.obj",
},
campfire: {
obj:"./assets/Campfire_01.obj",
}}
init();
animate();
I then load them in a loop in init():
for( var _key in models ){
scene = new THREE.Scene();
var element = document.createElement( "div" );
element.className = "list-item";
element.innerHTML = template.replace( '$', _key);
console.log('does this work', element.innerHTML);
scene.userData.element = element.querySelector( ".scene" );
content.appendChild( element );
var camera = new THREE.PerspectiveCamera( 50, 1, 1, 10 );
camera.position.z = 2;
scene.userData.camera = camera;
var objLoader = new THREE.OBJLoader();
objLoader.load(
models[_key].obj,
function ( object ) {
scene.add( object );
console.log(object);
},
);
}
And render them here:
renderer = new THREE.WebGLRenderer( { canvas: canvas, antialias: true } );
renderer.setClearColor( 0xffffff, 1 );
renderer.setPixelRatio( window.devicePixelRatio );
Why do both models end up in the last div?

I'm trying to make a skybox, but I must be missing something fundamental

I am trying to make a skybox, and every tutorial I have tried will not work. I thought I could make an array and pass it as a param for the material like I saw in an earlier example, but the method has apparently changed to TextureLoader() since then. Below is my code:
// Adds a skybox around the content
var skyBoxMaterials = [
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky1.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky2.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky3.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky4.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky5.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky6.jpg') }),
];
var skyBoxGeom = new THREE.CubeGeometry( 10000, 10000, 10000, 1, 1, 1);
skyBox = new THREE.Mesh( skyBoxGeom, skyBoxMaterials );
skyBox.position.set(0, 25.1, 0);
scene.add( skyBox );
When I run it currently, I get the error "Uncaught TypeError: Cannot read property 'x' of undefined" in the console infinitely looping until the server is killed. I could not find the exact answer in the examples, docs, or in another question, here. Any suggestions?
UPDATE: After some more digging, I finally found the example I needed in the docs under cubeGeometry, but it still does not render. My code is below:
// Adds a skybox around the content
var loader = new THREE.CubeTextureLoader();
loader.setPath( 'images/skybox/' );
var textureCube = loader.load( [
'sky1.jpg', 'sky2.jpg',
'sky3.jpg', 'sky4.jpg',
'sky5.jpg', 'sky6.jpg'
] );
var skyMaterials = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap:
textureCube } );
var skyBoxGeom = new THREE.CubeGeometry( 10000, 10000, 10000, 1, 1, 1);
skyBox = new THREE.Mesh( skyBoxGeom, skyMaterials );
skyBox.position.set(0, 25.1, 0);
scene.add( skyBox );
I do not have any error messages in the console, but the cube is not rendering at all. The other objects in the scene render normally.
You can use .background property of THREE.Scene() straight, as it accepts cube textures.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 0, 300 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var loader = new THREE.CubeTextureLoader();
loader.setCrossOrigin( "" );
loader.setPath( 'https://threejs.org/examples/textures/cube/skybox/' );
var cubeTexture = loader.load( [
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
] );
scene.background = cubeTexture;
render();
function render() {
requestAnimationFrame(render);
renderer.render( scene, camera );
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Have you downloaded the Three.js Master file? It has all the examples in working order. So all the examples you see on the Examples Page are there along with support files, textures assets etc. This way, you can start your project with a working example and build from there. You will need to run them from your local server (from your post, I gather you already know this).
There are a few examples that may help you like Panorama Cube. In the examples directory of the download, you will find a file called 'webgl_panorama_cube.html' that will be your local copy of this example.

Categories