I am trying to load some simple keyframe animation (just positions) using the JSON loader.
Using the dev branch r80.
To load the entire scene (made and animated in softimage, exported to FBX, imported into blender, exported using the THREE JSON export script). The file looks good and loads ok.
But when i try to load the animation using:
object.traverse( function ( child ) {
switch(child.name) {
case "dae_scene:helium_balloon_model:helium_balloon_model":
//do anim
console.log(object.animations[0]);
animationClips.balloon1 = object.animations[0]; //
//animationClips.balloon1.weight = 1;
animationMixer = new THREE.AnimationMixer( child );
var sceneAnimation = animationMixer.clipAction(animationClips.balloon1);
sceneAnimation.play();
break;
}
}
it produces:
three.min.js?ver=4.5.4:712 Uncaught Error: cannot parse trackName at all: dae_scene:helium_balloon_model:helium_balloon_model.position
Anyone who can point me in the right direction?
Related
I'm trying to get a threeJS Mesh from Autodek Forge objects using the function
'viewer.impl.getRenderProxy(viewer.model, fragId)'.
The problem that I encounter is if I put this function in a loop routine to get Meshs of multiple objects, I get just a random Mesh.
To find out the problem's origin, I used a similar function that is :
'viewer.impl.getFragmentProxy(viewer.model, fragId)'
and it worked just fine.
Her is the routine code that I use and the result :
for(let i = 0, len = nodNamee.length; i < (len); i = i+3){
var instanceTree = viewer.model.getData().instanceTree;
var fragIds = [];
instanceTree.enumNodeFragments(nodNamee[i+1], function(fragId){
fragIds.push(fragId);
});
fragIds.forEach(function(fragId) {
var renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId);
fragtoMesh.push(renderProxy);
//var fragmentproxy = viewer.impl.getFragmentProxy(viewer.model, fragId);
//fragtoProxy.push(fragmentproxy);
});
}
Result :
Arry of fragtoMesh
This is because the getFragmentProxy method always returns the same instance of THREE.Mesh, just with different properties. Basically, the method works like this under the hood:
let cachedMesh = new THREE.Mesh();
// ...
getRenderProxy(model, fragId) {
// Find the geometry, material, and other properties of the fragment
cachedMesh.geometry = fragGeometry;
cachedMesh.material = fragMaterial;
// ...
return cachedMesh;
}
// ...
Note that this is a performance optimization because if the getFragmentProxy (which is only meant for internal use) function returned a new instance every time it's called by other parts of Forge Viewer, it would cause a huge memory churn.
So in your case, if you really need to store all the THREE.Mesh instances in an array, you'll need to clone them or copy their individual properties into separate THREE.Mesh objects.
We are trying to merge multiple GLTFs on server side and export the merged gltf as final result on server.
Things we have trued that worked and that didn't:
We have used three js GLTFLoader parse method to load multiple gltf files, merge the parent and children of the loaded objects and export the final model using GLTFExporter.
We have used jsdom to resolve the issues related to window, document etc.
Above mentioned points work for gltfs without textures
While Loading GLTF with textures the response gets stuck.
a) We tried hosting the files on server and use the GLTFLoader load method with "localhost:******" as loader path.
b) Internally TextureLoader invoked ImageLoader where the onLoad event was not getting triggered at all . May be jsdom was not invoking this.
c) To solve this we changed ImageLoader to have canvas image :
const { Image } = require("canvas");
const image = new Image();
image.onload = onImageLoad;
image.onerror = onImageError;
d) The load method got resolved after above change.
e) Next step - Exporting the GLTF - We got stuck due to ImageData not found error. We added ImageData from canvas and the GLTF was exported.
f) The exported GLTF is not viewable die to corrupted data in images
"images": [
{
"mimeType": "image/png",
"uri": "data:,"
}
],
If someone loaded and merged GLTfs with texture images purely server side, Please Help!
As three.js is primarily a 3D rendering library for the web, and relies on various web image and WebGL APIs, I'm not sure using THREE.GLTFLoader is the most efficient way to merge glTF files on a Node.js server. I'd suggest this, instead:
import { Document, NodeIO } from '#gltf-transform/core';
import { KHRONOS_EXTENSIONS } from '#gltf-transform/extensions';
const io = new NodeIO().registerExtensions(KHRONOS_EXTENSIONS);
const document = new Document();
const root = document.getRoot();
// Merge all files.
for (const path of filePaths) {
document.merge(io.read(path));
}
// (Optional) Consolidate buffers.
const buffer = root.listBuffers()[0];
root.listAccessors().forEach((a) => a.setBuffer(buffer));
root.listBuffers().forEach((b, index) => index > 0 ? b.dispose() : null);
io.write('./output.glb', document);
It's worth noting that this process will result in a glTF file containing multiple separate scenes. If you want to combine them into a single scene, arranged in some way, you'd need to use the scene API to do that. If the files are not on disk, there are other NodeIO APIs for processing binary or JSON files in memory.
I followed this tutorial
Wanting to generate SkinnedMesh and bind to bones with Script
public SkinnedMeshRenderer shirtMesh;
public SkinnedMeshRenderer targetMesh;
// Use this for initialization
void Start () {
//SkinnedMeshRenderer sm = Instantiate(shirtPrefab).GetComponent<SkinnedMeshRenderer>();
SkinnedMeshRenderer sm = Instantiate<SkinnedMeshRenderer>(shirtMesh);
sm.transform.parent = targetMesh.transform.parent;
sm.bones = targetMesh.bones;
sm.rootBone = targetMesh.rootBone;
}
As shown in the screen shot the blue mesh (shirt) is deformed incorrectly. (This mesh worked as expected if loaded in the editor when it gets imported)
Am I missing anythings?
I am trying to load an external model using ObjectLoader. I am using the following code
loader.load( 'teapot.obj', function ( object ) {
globalobject=object;
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
console.log(child);
child.position.x = 3;
child.position.y = -6;
child.position.z = -17;
child.scale.x=.04;
child.scale.y=.04;
child.scale.z=.04;
child.name='tea';
scene.add( child );
}
});
But when I try to access this object in my render method using the following code it shows error
scene.getObjectByName('tea').rotation.z+=.01;
I saw using console that scene.getObjectByName('tea') is undefined
I can use all other standard Mesh objects using the above command but what is the problem with my object loaded using loader?
Can anyone help me to get the way?
If you have multiple childs in one obj file then append some number to differentiate between multiple mesh.
Then this should work:
scene.getObjectByName( "objectName" );
This answer may help
I'm trying to remove a Google swiffy (v 5.2.0) animation and then readd it at a later date.
In terms of the running animation there doesn't seem to be any problem, but the code triggers an error: TypeError: Cannot redefine property: Animation_fla.MainTimeline at which point all AS3 in the movie stops working. This seems to be because the destroy method is not removing references to the AS3 code within the swiffy runtime. I've spent some time trying to step through the code but it's pretty incomprehensible.
Below is a stripped out version of all I'm doing with swiffy - calling init again after calling destroy will trigger this TypeError. I've tried to reinitialise the swiffy runtime itself but this causes a similar error.
var stage;
function init() {
stage = new swiffy.Stage(domElement, swiffyJson);
stage.start();
}
function destroy() {
stage.destroy();
stage = null;
}
The only solution I've come up with is a pretty horrible hack. It seem Swiffy really doesn't like to recreate animations after they've been destroyed. I've had some success with detaching the Swiffy from the DOM but retaining it's reference in memory. I then had to hack the runtime to enable pause and restart. I could then reattach the original Swiffy without having to destroy it. This is in v5.2.0 downloaded from https://www.gstatic.com/swiffy/v5.2/runtime.js, after putting the runtime through jsbeautifier.org
Around line 5640 after the M.releaseCapture function I added the following function:
M.hackPause = function (bool) {
if(this.hackPaused === bool) return;
if(this.hackPaused) {
bi(ef(this.qh.yl, this.qh));
}
this.hackPaused = bool;
};
The around line 7137, replace the AK[I].yl function with the following:
Ak[I].yl = function () {
if (this.bh) {
var a = Date.now();
a >= this.Mf && (this.tl.ei(), this.Mf += (s[Xb]((a - this.Mf) / this.sl) + 1) * this.sl);
this.tl.lc();
if(!this.tl.hackPaused) {
bi(ef(this.yl, this))
}
}
};
What this is doing is preventing the requestAnimationFrame or setTimeout from firing and therefore effectively pausing the animation.
I've tried to expose a gotoAndStop function within the runtime also, but I couldn't manage to find the scope amongst the code. In the meantime, using a hack from this post - Is it possible to pause/resume/manipulate a swiffyobject from JS? we can do this with a brute force approach by adding an enter frame event to the flash movie and testing for a change in Flashvars. Below is the Document Class we've been using for our animations. It's worth noting that Swiffy doesn't seem to like AS3 Classes that extend from the same base class, it throws the same cannot redefine property error, so we've duplicated the code from here in the Document class of each of our Flash animations. I've also got a method in there that allows dispatching events from the AS3 to a javascript function called onSwiffyEvent:
package {
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.net.navigateToURL;
import flash.events.Event;
import flash.utils.setTimeout;
public class BaseAnimation extends MovieClip {
private var _request:URLRequest;
private var _pageName:String;
private var _movieName:String;
public function BaseAnimation() {
_request = new URLRequest();
_pageName = getFlashVar('pageName');
_movieName = getFlashVar('movieName');
addEventListener(Event.ENTER_FRAME, jsListen);
}
private function getFlashVar(name:String):String {
var flashVar:String = stage.loaderInfo.parameters[name] || '';
stage.loaderInfo.parameters[name] = '';
return flashVar;
}
public function dispatchJSEvent(eventName:String, param:String = ''):void {
_request.url = "javascript:onSwiffyEvent('" + eventName + "', '" + param + "', '" + _movieName + "', '" + _pageName + "');";
navigateToURL(_request, "_self");
}
private function jsListen(e:Event):void {
var mode:String = getFlashVar('mode');
if(mode.length) {
switch(mode) {
case 'stop':
stop();
break;
case 'play':
play();
break;
case 'gotoStart':
gotoAndStop('start');
break;
}
}
}
}
}
Swiffy also doesn't seem to like gotoAndStop(0) so I've had to set a frame label of 'start' on the first frame of the animation.
With all this horrible hackery in place, we're able to remove and restart Swiffy animations. The only issue we've found is that detaching and reattaching has caused issues with embedded SVG fonts and we've ended up converting all text to outlines. The above is used like so:
You can call it on the swiffy stage like so:
var stage = new swiffy.Stage(domObject, swiffyObj);
stage.start();
// when reading to remove this element from the DOM do the following:
stage.setFlashVars('mode=gotoStart');
setTimeout(function () {
// timeout is required to ensure that the enterframe listener has time to run
stage.hackPause(true); // paused animation
}, 100);
// you can then remove the containing div from the DOM, but retain it in memory
// after you reattach the div to the DOM, ensuring we've kept hold of our stage variable in memory, you can restart it like this:
stage.hackPause(false); // resumes javascript requestAnimationFrame
stage.setFlashVars('mode=play'); // resumes flash animation
Hope this helps someone, but I also really hope Google start to expose some kind of JS API or ExternalInterface to the Swiffy runtime to give us more control over what is really a pretty great tool.
Try creating a copy of the swiffyobject before passing it to swiffy.Stage(). Swiffy is modifying the object upon instantiation, so with a copy you can simply recreate after destroy()