Associate loaded JSON files with a name for later access - three.js

I would like to load multiple JSON files and control the visibility of their meshes. To achieve this, I associated them with their JSON file names. I got it working, but the solutions doesn't please me.
I modified the THREE.JSONLoader and passed a new parameter to the callback function. So with every new release of three.js, I would have to patch the three.js file again.
Here is my working solution (client side). See the new third parameter of loader.load(filename, callback, meshname).
Is there a better solution, which doesn't need a patched three.js library?
Thanks
// Load the JSON files
var meshes = new Object();
var jsonFileNames = ['assembly/part1.json', 'assembly/part2.json', 'assembly/part3.json'];
for(var i = 0; i < jsonFileNames.length; i++){
var loader = new THREE.JSONLoader();
var meshName = jsonFileNames[i].split("/")[1].split(".")[0];
loader.load(jsonFileNames[i], function(geometry, meshName){
mesh = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({vertexColors: THREE.FaceColors}));
mesh.scale.set(0.2, 0.2, 0.2);
mesh.doubleSided = true;
scene.add(mesh);
meshes[meshName] = mesh;
}, meshName);
}
// ....
// Access their meshes
meshes[meshName].visible = true;

You could create a callback factory like below. It will work around the problem with closures when created inside loops.
function makeHandler(meshName) {
return function(geometry) {
mesh = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({vertexColors: THREE.FaceColors}));
mesh.scale.set(0.2, 0.2, 0.2);
mesh.doubleSided = true;
scene.add(mesh);
meshes[meshName] = mesh;
};
}
// Load the JSON files
var meshes = new Object();
var jsonFileNames = ['assembly/part1.json', 'assembly/part2.json', 'assembly/part3.json'];
for(var i = 0; i < jsonFileNames.length; i++){
var loader = new THREE.JSONLoader();
var meshName = jsonFileNames[i].split("/")[1].split(".")[0];
loader.load(jsonFileNames[i], makeHandler(meshName));
}
// ....
// Access their meshes
meshes[meshName].visible = true;

A variant of Tapio's great answer. This variant avoids the need to create and manage the meshes object. It does this by creating each new mesh object with the desired object name directly in the made handler function. As before the desired name meshName for each mesh is defined by the user and passed to the handler. But then the new mesh is created with the desired name by using the javascript eval function.
function makeHandler(meshName) {
return function(geometry) {
material = new THREE.MeshPhongMaterial({vertexColors: THREE.FaceColors})
eval (meshName + "= new THREE.Mesh(geometry, material);" ); //***NEW ***
eval ( "var mesh = " + meshName +";" ); //*** NEW ***
mesh.scale.set(0.2, 0.2, 0.2);
mesh.doubleSided = true;
scene.add(mesh);
//*** NOT REQUIRED *** meshes[meshName] = mesh;
};
}
// Load the JSON files
var meshes = new Object();
var jsonFileNames = ['assembly/part1.json', 'assembly/part2.json', 'assembly/part3.json'];
for(var i = 0; i < jsonFileNames.length; i++){
var loader = new THREE.JSONLoader();
var meshName = jsonFileNames[i].split("/")[1].split(".")[0];
loader.load(jsonFileNames[i], makeHandler(meshName));
}
// ....
The various meshes can subsequently (when loading is completed) be referenced by their object names:-
// Access the meshes
//*** OLD *** meshes["part1"].visible = true;
//*** OLD *** meshes["part2"].visible = true;
//*** OLD *** meshes["part3"].visible = true;
part1.visible = true;//*** NEW ***
part2.visible = true;//*** NEW ***
part3.visible = true;//*** NEW ***

Related

Cocos Creator js animate sprite

I have animated a sprite using a sprite sheet and the update function,
like so:
Note: I have dragged the plist into the atlas field of the sprite node (the same node the monster.js script is attached to) in the Ccos Creator UI.
//monster.js
onLoad: function(){
// change monsters face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
}
update: function (dt) {
this.timekeep += dt;
if(this.timekeep > 0.1){
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
self.getComponent(cc.Sprite).spriteFrame = atlas.getSpriteFrame(self.faces[self.monstersN]);
});
this.timekeep = 0;
this.monstersN++;
if(this.monstersN > 4){
this.monstersN = 1;
}
}
It actually works fine. I have already thought I should export the cc.loader.loaderRes into the onLoad function and save the atlas as a global var instead of loading every time the update is called.
However…seeing that there are built in animation functions, this can’t be the correct solution. So I tried this:
onLoad: function () {
// change monster face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
var sprite = self.getComponent(cc.Sprite);
var animFrames = [];
for (var i = 1; i < 4; i++) {
var spriteFrame = atlas.getSpriteFrame(self.faces[i]);
var animFrame = new cc.AnimationFrame();
animFrame.initWithSpriteFrame(spriteFrame, 1, null);
animFrames.push(animFrame);
}
var animation = sprite.Animation.create(animFrames, 0.2, 100);
var animate = sprite.Animate.create(animation);
sprite.runAction(animate);
});
},
I get this error:
cc.AnimationFrame is not a constructor
So then I tried this:
onLoad: function () {
// change monster face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
self.atlasA = atlas;
});
var sprite = this.getComponent(cc.Sprite);
var animFrames = [];
for (var i = 1; i < 4; i++) {
var spriteFrame = this.atlasA.getSpriteFrame(this.faces[i]);
var animFrame = new cc.AnimationFrame();
animFrame.initWithSpriteFrame(spriteFrame, 1, null);
animFrames.push(animFrame);
}
var animation = sprite.Animation.create(animFrames, 0.2, 100);
var animate = sprite.Animate.create(animation);
sprite.runAction(animate);
},
I get this error:
Cannot read property ‘getSpriteFrame’ of undefined
How can I use cc.animate to change the sprite using the spritesheet I have. All I want to achieve is to move through the plist in the order the images are in the plist, repeated until the monster is put back into the pool it came from.
Here is the solution for anyone who may still be looking.....
cc.AnimationClip.createWithSpriteFrames([sf1, sf2, ...], fps)

an error when I used ammo.js and physi.js , what should I do for it?

I want to use Physi.js to make a car , but there has some error, I view my demo at Chrome, and I don't know the error is caused by the file named ammo.js or physi.js ,and following are my codes:
var phymaterial = Physijs.createMaterial(new THREE.MeshStandardMaterial({color:0xff0000,wireframe:true}),0,1);
//create a wall
var wall1 = new Physijs.BoxMesh(new THREE.CubeGeometry(50,10,2),meshGray);
wall1.position.set(0,5,35);
scene.add(wall1);
var cubegeo = new THREE.CubeGeometry(31.6,6,13.6);
//create a cube as car's body
var carPhy = new Physijs.BoxMesh(cubegeo,phymaterial,0);
carPhy.position.set(0,5,0)
car.position.set(0.6,-3,0)
scene.add(carPhy);
//create four wheels use Physijs
var wheelfl = new Physijs.CylinderMesh(new THREE.CylinderGeometry(4,4,1,30),phymaterial,100);
wheelfl.rotation.x = Math.PI/2;
wheelfl.position.set(10,4,-8)
scene.add(wheelfl);
var wheelfr = new Physijs.CylinderMesh(new THREE.CylinderGeometry(4,4,1,30),phymaterial,100);
wheelfr.rotation.x = Math.PI/2;
wheelfr.position.set(10,4,8)
scene.add(wheelfr);
var wheelbl = new Physijs.CylinderMesh(new THREE.CylinderGeometry(4,4,1,30),phymaterial,100);
wheelbl.rotation.x = Math.PI/2;
wheelbl.position.set(-10,4,-8)
scene.add(wheelbl);
var wheelbr = new Physijs.CylinderMesh(new THREE.CylinderGeometry(4,4,1,30),phymaterial,100);
wheelbr.rotation.x = Math.PI/2;
wheelbr.position.set(-10,4,8)
scene.add(wheelbr);
//create constraint with Physijs.DOFConstraint
var fl = new Physijs.DOFConstraint(wheelfl,carPhy,new THREE.Vector3(10,4,-10));
scene.addConstraint(fl);
var fr = new Physijs.DOFConstraint(wheelfr,carPhy,new THREE.Vector3(10,4,10));
scene.addConstraint(fr);
var bl = new Physijs.DOFConstraint(wheelbl,carPhy,new THREE.Vector3(-10,4,-10));
scene.addConstraint(bl);
var br = new Physijs.DOFConstraint(wheelbr,carPhy,new THREE.Vector3(-10,4,10));
scene.addConstraint(br);
And the error information like following:
Uncaught ReferenceError: _emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_4 is not defined
at new btGeneric6DofConstraint (ammo.js:22)
at Object.public_functions.addConstraint (physijs_worker.js:873)
at self.onmessage (physijs_worker.js:1412)
I wanna know how can I resolve it?

How to change the wall color or image in Three js?

i have created wall using path in three js. I want change the color option buttion automatically need to change the color onclick event.
Below my color any one help me.
// wall 1 inside
item_count = 1;
var wall_x1 = 69;
var wall_y1 = 55;
var wall_x2 = 366;
var wall_y2 = 52;
var wall_z = 0;
var wall_width = 5;
var wall_height = default_height;
var wall_wall_width = 5;
if(!wall_wall_width) { wall_wall_width = 5; }
var wall_wall_elevation = planner_default_height;
if(!wall_wall_elevation) { wall_wall_elevation = default_height; }
var wall_top_filltype = 'texture';
var wall_top_fill = 'default_wall.jpg';
var wall_side_filltype = 'texture';
var wall_side_fill = 'wall5.jpg';
if ( item_count == 0 )
{
starting_x_value = wall_x1;
starting_y_value = wall_y1;
}
path = generate_path_byline(wall_x1,wall_y1,wall_x2,wall_y2,default_depth);
path_type ="wall";
x=starting_x_value-wall_x1; y=starting_y_value-wall_y1;
// z=default_height/2;
path_transform = transformSVGPath(path);
create_surface(1,1,path_type,path_transform,starting_x_value,starting_y_value,x,y,z,default_height,wall_wall_elevation,wall_top_filltype,wall_top_fill,wall_side_filltype,wall_side_fill);
I see no clear way of defining the material at your sample code, or at least the way three.js does it:
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
If you use as a material a texture with an image, you have many ways to change its color... one easy trick could be to change the light color that lightens the scene or this object.

Load & Display Image in ActionScript

I am typing with very green fingers, so, please excuse the question. Learning from examples, I have been trying to load and display an image in ActionScript. This is from the original example that I am working on:
...
...
var bmd2:BitmapData = bmd.clone();
var infoBM:Bitmap = new Bitmap(bmd2);
var back:MovieClip = new MovieClip();
back.name = "back";
back.rotationX = -90;
var bSurface:MovieClip = new MovieClip();
bSurface.y = int(...
bSurface.z = int(...
bSurface.addChild(infoBM);
var overlay:Sprite = new Sprite();
overlay.graphics.beginFill(...);
overlay.graphics.drawRect(0, 0, bSurface.width, bSurface.height);
overlay.graphics.endFill();
bSurface.addChild(overlay);
back.addChild(bSurface);
var tf:TextField = new TextField();
tf...
tf...
tf...
bSurface.addChild(tf);
...
...
I am trying to place an image onto the bSurface instead of the text block, as above. So far, I've come up with:
var iSprite:Sprite = new Sprite();
var iMatrix:Matrix = new Matrix();
var bmData:BitmapData;
bmData = new BitmapData(surface.width, surface.height, true, 123);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.load(new URLRequest("c:\pixlr.png"));
function onComplete (event:Event):void
{
bmData = Bitmap(LoaderInfo(event.target).content).bitmapData;
}
iMatrix.tx = 0;
iMatrix.ty = 0;
iSprite.graphics.beginBitmapFill(bmData, iMatrix, false, true);
iSprite.graphics.drawRect(0, 0, surface.width, surface.height);
iSprite.graphics.endFill();
surface.addChild(iSprite);
...and:
var bmData:BitmapData;
bmData = new BitmapData(surface.width, surface.height, true, 123);
var loader:Loader = new Loader();
var location:URLRequest = new URLRequest("c:\pixlr.png");
loader.load(location);
bmData = Bitmap(loader.content).bitmapData;
surface.addChild(bmData);
but to no success. I've been failing miserably for days now, and would greatly appreciate some help.
Thanking you in advance,
Sofia
You're making this more complicated than it needs to be. A Loader is a DisplayObject. So when you want to load an image you can simply do this:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.load(new URLRequest("c:\pixlr.png"));
addChild(loader);
You can use the onComplete event to handle any sizing or positioning, or fading in you might want to do.

Three js camera movement

i dont have the code here so i hope you can understand, i'l edit and add the code when i get home.
I have built a class move that once initialized adds a jquery event (keyDown) to the rendered dom element.
the event checks what key is down in a switch case,
if the key is one of the cases the camera will be moved accordingly.
The camera does move, but for some reason it flickers a bit, like little jumps.
the speed for each camera move is 0.05;
when i did this in anouter app but via a javascript keydown event from the main script (no special class) it worked fine..
any idea why would it do this ?
edit: code
main script :
<script>
var moveMec = null;
var loopProg = null;
var renderer = null;
var scene = null;
var camera = null;
var mesh = null;
var earth = null;
var sun = null;
$(document).ready(
function() {
var container = document.getElementById("container");
renderer = new THREE.WebGLRenderer({ antialias: true } );
renderer.setSize(container.offsetWidth,container.offsetHeight);
container.appendChild(renderer.domElement)
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45,
container.offsetWidth / container.offsetHeight, 1, 4000 );
earth = new Earth();
sun = new Sun({x:-10,y:0,z:20});
scene.add(earth.getEarth);
scene.add(sun.sunLight);
camera.position.set( 0, 0, 3 );
moveMec = new moveMechanics(camera,renderer.domElement)
loopProg = new loopProgram();
loopProg.add(function(){earth.update()});
//loopProg.add(function(){renderer.render( scene, camera );});
loopProg.solarLoop();
}
);
</script>
move script :
var moveMechanics = function (camera,domElement,speed)
{
moveMechanics.camera = camera;
moveMechanics.speed = speed != undefined ? speed : 0.01;
moveMechanics.domElement = domElement;
$(document).keydown(function(event)
{
switch(event.which)
{
case KeyEvent.DOM_VK_W:
camera.position.z -= moveMechanics.speed;
break;
case KeyEvent.DOM_VK_S:
camera.position.z += moveMechanics.speed;
break;
case KeyEvent.DOM_VK_D:
camera.position.x += moveMechanics.speed;
break;
case KeyEvent.DOM_VK_A:
camera.position.x -= moveMechanics.speed;
break;
}
});
}
loop code :
function loopProgram()
{
this.functionsToRun = new Array();
this.solarLoop= function()
{
jQuery.each(loopProg.functionsToRun, function(index,value)
{
value ? value() : null;
});
requestAnimationFrame(loopProg.solarLoop);
}
this.add = function(func)
{
this.functionsToRun[this.functionsToRun.length] = func;
}
}

Resources