So I've been trying to use the SkeletonHelper to render a basic skeleton for an animation visualizer, but can't figure out how to get SkeletonHelper to accept the Skeleton variable armSkeleton I pass into the constructor. The documentation states that the SkeletonHelper does accept Skeleton type objects, which is causing me much grief. The console error I get is "TypeError: object.children is undefined". Could anyone point me in the right direction as to fixing this?
var bones = [];
var shoulder = new THREE.Bone();
var elbow = new THREE.Bone();
var hand = new THREE.Bone();
shoulder.add( elbow );
elbow.add( hand );
bones.push( shoulder );
bones.push( elbow );
bones.push( hand );
shoulder.position.y = -5;
elbow.position.y = 0;
hand.position.y = 5;
armSkeleton = new THREE.Skeleton( bones );
var helper = new THREE.SkeletonHelper(armSkeleton); <Error at this line>
SkeletonHelper does not accept a skeleton as the constructor parameter. In your case, you have to pass in the top most bone. Have a look at the following example for more information:
https://jsfiddle.net/f2Lommf5/13483/
Related
I followed these examples to make the outline for objects when they are selected:
https://threejs.org/examples/?q=out#webgl_postprocessing_outline
https://github.com/scqilin/three-OutlinePass
No error is found, yet outline does not appear when the object is selected. The highlightSelectedObject function is correcly triggered when an object is selected. selectedObjects is not null.
In my case, THREE.js is installed in the project file. Scene, camera and renderer are instantiated elsewhere.
import * as THREE from "../../build/three.module.js";
import {OutlinePass} from "../../examples/jsm/postprocessing/OutlinePass.js";
import {RenderPass} from "../../examples/jsm/postprocessing/RenderPass.js";
import {EffectComposer} from "../../examples/jsm/postprocessing/EffectComposer.js";
Function:
function highlightSelectedObject(selectedObjects) {
if (selectedObjects != null) {
const scene = project.currentScene.scene;
const camera = project.currentScene.camera;
const renderer = project.renderer;
var composer = new EffectComposer(renderer);
var renderPass = new RenderPass(scene, camera);
var outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera, selectedObjects);
outlinePass.renderToScreen = true;
outlinePass.selectedObjects = selectedObjects;
composer.addPass(renderPass);
composer.addPass(outlinePass);
const params = {
edgeStrength: 2,
edgeGlow: 1,
edgeThickness: 1.0,
pulsePeriod: 0,
usePatternTexture: false
};
outlinePass.edgeStrength = params.edgeStrength;
outlinePass.edgeGlow = params.edgeGlow;
outlinePass.visibleEdgeColor.set(0xffffff);
outlinePass.hiddenEdgeColor.set(0xffffff);
composer.render(scene, camera);
}
}
The path to THREE.js should be correct. Is it a problem with render?
I had a similar issue. Upon looking at another example, I found that setting outlinePass.renderToScreen = true allowed it to work. It might not be there depending what version of the the outlinePass.js you are using. I looked at the code on the deployed example and it is there.
I'm trying to use line like this
myObject3D.children.forEach(
function(pChild){
return pChild.position.multiplyScalar(myMultiplier)
}
);
and this
myObject3D.children.forEach(
function(pChild){
pChild.position.copy(myVector3)
}
);
But for some reasons, functions in child elements of 'myObject3D' seems to be inexistent. ("Uncaught TypeError: pChild.position.multiplyScalar is not a function")
However, elements in 'myObject3D' are 'Mesh' objects.
Can anybody suggest what can I do?
Thanks
First, your forEach callback shouldn't return anything.
There doesn't appear to be anything wrong with your second code segment.
The code below runs without errors.
var group = new THREE.Object3D();
var geo = new THREE.BoxBufferGeometry(10, 10, 10);
var mat = new THREE.MeshBasicMaterial({
color: "red"
});
var mesh = new THREE.Mesh(geo, mat);
group.add(mesh);
group.add(mesh.clone());
group.add(mesh.clone());
group.add(mesh.clone());
group.add(mesh.clone());
var myVector3 = new THREE.Vector3();
group.children.forEach(function(pChild) {
pChild.position.multiplyScalar(5);
pChild.position.copy(myVector3)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.js"></script>
Please verify that you're populating your group with the correct kinds of objects. Also, you can always test if a function is available before using it:
if(obj.someFunction){
obj.someFunction();
}
I need to have multiple identical, animated models on a scene. If possible, I would like them to have a shared geometry and material, but if it is impossible, having them instanced per model will suffice too.
Unfortunately, the only way to achieve this result I found is to go through JSONLoader for every model instance.
SkinnedMesh does have a clone() method, but it seems not to be fully implemented yet. If used and both original and cloned mesh are present on the scene, only one will appear, and cloned one will be without animation.
I have attempted to use this example with shared skeletons:
https://github.com/mrdoob/three.js/pull/11666
...and indeed it works, but I need to be able to play different animations for every model instance, having them all play the same one is not sufficient, sadly. I hoped I could do similar hax and insert my own skeleton (made out of bones from the JSON file), but it behaves very much like if I just used clone() from SkinnedMesh.
I am using this code:
https://github.com/arturitu/threejs-animation-workflow/blob/master/js/main.js
Basically what I'd like to achieve is
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = character.someMagicalClone();
scene.add(character);
scene.add(character2);
(...)
I need any clue... and while I wait for help, I am busily deconstructing constructor for SkinnedMesh and JSONLoader for clues ;)
Thanks in advance!
I found a solution in this pull request:
https://github.com/mrdoob/three.js/pull/14494
in short, there are two functions added:
function cloneAnimated( source ) {
var cloneLookup = new Map();
var clone = source.clone();
parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
cloneLookup.set( sourceNode, clonedNode );
} );
source.traverse( function ( sourceMesh ) {
if ( ! sourceMesh.isSkinnedMesh ) return;
var sourceBones = sourceMesh.skeleton.bones;
var clonedMesh = cloneLookup.get( sourceMesh );
clonedMesh.skeleton = sourceMesh.skeleton.clone();
clonedMesh.skeleton.bones = sourceBones.map( function ( sourceBone ) {
if ( ! cloneLookup.has( sourceBone ) ) {
throw new Error( 'THREE.AnimationUtils: Required bones are not descendants of the given object.' );
}
return cloneLookup.get( sourceBone );
} );
clonedMesh.bind( clonedMesh.skeleton, sourceMesh.bindMatrix );
} );
return clone;
}
function parallelTraverse( a, b, callback ) {
callback( a, b );
for ( var i = 0; i < a.children.length; i ++ ) {
parallelTraverse( a.children[ i ], b.children[ i ], callback );
}
}
As I understand it rebinds cloned skeleton to the cloned mesh.
so topic example could look like:
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = cloneAnimated(character); // <-- used that new function
scene.add(character);
scene.add(character2);
(...)
Having problem understanding the class system in Three.js
I have a code in player.js :
function Player() {
var mesh = new THREE.Object3D();
this.player = null;
this.loader = new THREE.JSONLoader();
this.name = 'player';
this.loader.load(
'obj/models/minecraft_sole.json',
function ( geometry, materials ) {
var material = new THREE.MultiMaterial( materials );
this.player = new THREE.Mesh( geometry, material );
this.player.position.set(0, 0, 0);
this.player.scale.set(.5,.5,.5);
this.player.castShadow = true;
this.player.receiveShadow = false;
mesh.add( this.player );
}
);
Player.prototype.constructor = Player;
Player.prototype = Object.create(THREE.Object3D.prototype);
}
Player.prototype.updatePosition = function(){
this.mesh.position.y += 0.05;
}
And basically what I'm trying to achieve:
In main.js after all standard setup for init()/render()/animate() and all...
I create variable called johny:
var johny = new Player();
Now everything loads great and all, but in player.js i want to be able to define some prototype ? method, and in that method I want to listen for a click event. After that event is called I want my player mesh to animate to certain position or start rotating/scaling.
My pseudo code for better understanding is:
var Player = function(){
// define mesh and all
}
player.add.eventListener( 'click' ){
//code to animate player
}
Remember that all this; I want to be a part of player.js so that after calling:
var johny = new Player();
I don't have to add event listening functions to the main.js and all that.
And second of all I want my code to be modular, as You may already noticed :)
So I did managed to understand it.
I want to obtain vertixes for any given text. Text is created via TextGeometry and then PointCloud is instantiated:
var textGeo = new THREE.TextGeometry( "three.js", {...});
var textMaterial = new THREE.MeshBasicMaterial({
color:0x8080FF,
side:THREE.DoubleSide,
});
textObject = new THREE.PointCloud( textGeo, textMaterial)
The effect is following:
As you can see, the issue is that, points are not uniformely distributed, especially they are missing on straight lines.
Do you guys have any suggestions how to achieve a nicer effect?
I met the same problem. And I change the .JSON in THREE.FontLoader.load(),then I can see most of the points.
fontLoader.load('build/optimer_bold.typeface.json',
function (font) {
let fontOptions = {
font:font,
size:10
......
}
.....
}
);
Try the optimer_bold.typeface.json.