Applying skeleton to procedural skinned mesh - javascript

In this fiddle I'm trying to create a procedural worm (or snake or caterpillar) character, based on the basic bones example at threejs.org/docs/scenes/bones-browser, but with an extra four bones and two spheres for eyes added on; the added/altered code shown here...
function eyeBall() {
function eyeBall( ) {
var faceIndices = [ 'a', 'b', 'c' ];
var color, f, i, j, p, vertexIndex, radius = 1;
var geometry = new THREE.SphereGeometry( radius, 18, 5 );
for ( i = 0; i < geometry.faces.length; i ++ ) {
f = geometry.faces[ i ];
for( j = 0; j < 3; j++ ) {
vertexIndex = f[ faceIndices[ j ] ];
p = geometry.vertices[ vertexIndex ];
f.color = new THREE.Color( 0xffffff );
if( p.y < -0.9 ) {
f.color = new THREE.Color( 0x000000 );
}
}
}
return geometry;
}
function createBones ( sizing ) {
function createBones ( sizing ) {
bones = [];
var prevBone = new THREE.Bone();
bones.push( prevBone );
prevBone.position.z = - sizing.halfLength;
for ( var i = 0; i < sizing.segmentCount; i ++ ) {
var bone = new THREE.Bone();
bone.position.z = sizing.segmentLength;
bones.push( bone );
prevBone.add( bone );
prevBone = bone;
}
//add more bones
var lHdBone = new THREE.Bone();
lHdBone.position.set( 1.4, 0, 2.8 );
lHdBone.name = 'lHdBone';
bones.push( lHdBone );
prevBone.add( lHdBone );
var rHdBone = new THREE.Bone();
rHdBone.position.set( -1.4, 0, 2.8 );
rHdBone.name = 'rHdBone';
bones.push( rHdBone );
prevBone.add( rHdBone );
var lEyeBone = new THREE.Bone();
lEyeBone.position.set( 0, 0, 1 );
lEyeBone.name = 'lEyeBone';
bones.push( lEyeBone );
lHdBone.add( lEyeBone );
var rEyeBone = new THREE.Bone();
rEyeBone.position.set( 0, 0, 1 );
rEyeBone.name = 'rEyeBone';
bones.push( rEyeBone );
rHdBone.add( rEyeBone );
return bones;
}
function initBones () {
function initBones () {
var segmentLength = 8;
var segmentCount = 4;
var length = segmentLength * segmentCount;
var halfLength = length * 0.5;
var sizing = {
segmentLength : segmentLength,
segmentCount : segmentCount,
length : length,
halfLength : halfLength
};
var geometry = createGeometry( sizing );
var bones = createBones( sizing );
mesh = createMesh( geometry, bones );
var lEye = eyeBall();
var rEye = eyeBall();
lEye.rotateX( -Math.PI * 0.5);
rEye.rotateX( -Math.PI * 0.5);
lEye.translate( 1.4, 0, sizing.halfLength + 2.8 );
rEye.translate( -1.4, 0, sizing.halfLength + 2.8 );
var lEyeMesh = new THREE.Mesh( lEye, material );
var rEyeMesh = new THREE.Mesh( rEye, material );
mesh.add( lEyeMesh );
mesh.add( rEyeMesh );
mesh.scale.multiplyScalar( 1 );
scene.add( mesh );
}
The animation in the fiddle moves the spheres in the same general direction but the spheres are clearly not tied to the skeleton as desired. The eyes should be looking forward throughout. I haven't found any comparable questions for this since most modelling is done in Blender, but I am sure this should be possible in three.js alone.
I feel I'm missing something simple!
This is another fiddle with merged geometries. Now one eye seems to act correctly, but the other eye is evidently a child bone; i.e. bones[6] is a child of bones[5], while they should both be children of bones[4].

Related

ThreeJS: applying edge geometry to ArrowHelper

I'm trying to create an arrow using ArrowHelper in ThreeJS:
let arrow = new THREE.ArrowHelper(direction.normalize(), new THREE.Vector3(), length, color, headLength, headWidth);
Also I want to use a separate color for edges. I realize that I need to use THREE.EdgesGeometry, but how to apply it I don't quite understand. Could anybody help me?
Update
sorry for confusion, I thought the arrow uses pyramid, not cone. Is there a way to replace cone with pyramid and use different color for edges?
Update
Thank you all for your answers, they were really helpful. I ended up with creating custom arrow class (copied most of the code from ArrowHelper):
class CustomArrow extends THREE.Object3D {
constructor( dir, origin, length, color, edgeColor, headLength, headWidth ) {
super();
// dir is assumed to be normalized
this.type = 'CustomArrow';
if ( dir === undefined ) dir = new THREE.Vector3( 0, 0, 1 );
if ( origin === undefined ) origin = new THREE.Vector3( 0, 0, 0 );
if ( length === undefined ) length = 1;
if ( color === undefined ) color = 0xffff00;
if ( headLength === undefined ) headLength = 0.2 * length;
if ( headWidth === undefined ) headWidth = 0.2 * headLength;
if ( this._lineGeometry === undefined ) {
this._lineGeometry = new THREE.BufferGeometry();
this._lineGeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
this._coneGeometry = new THREE.ConeBufferGeometry( 0.5, 1, 6);
this._coneGeometry.translate( 0, - 0.5, 0 );
this._axis = new THREE.Vector3();
}
this.position.copy( origin );
this.line = new THREE.Line( this._lineGeometry, new THREE.LineBasicMaterial( { color: color, toneMapped: false, linewidth: 4 } ) );
this.line.matrixAutoUpdate = false;
this.add( this.line )
// base material
this.cone = new THREE.Mesh( this._coneGeometry, new THREE.MeshBasicMaterial( { color: color, toneMapped: false } ) );
this.add(this.cone);
// wire frame
this.wireframe = new THREE.Mesh( this._coneGeometry, new THREE.MeshBasicMaterial( {
color: edgeColor,
toneMapped: false,
wireframe: true,
wireframeLinewidth: 2 } ) );
this.add(this.wireframe);
this.setDirection( dir );
this.setLength( length, headLength, headWidth );
}
setDirection( dir ) {
// dir is assumed to be normalized
if ( dir.y > 0.99999 ) {
this.quaternion.set( 0, 0, 0, 1 );
} else if ( dir.y < - 0.99999 ) {
this.quaternion.set( 1, 0, 0, 0 );
} else {
this._axis.set( dir.z, 0, - dir.x ).normalize();
const radians = Math.acos( dir.y );
this.quaternion.setFromAxisAngle( this._axis, radians );
}
}
setLength( length, headLength, headWidth ) {
if ( headLength === undefined ) headLength = 0.2 * length;
if ( headWidth === undefined ) headWidth = 0.2 * headLength;
this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
this.line.updateMatrix();
this.cone.scale.set( headWidth, headLength, headWidth );
this.cone.position.y = length;
this.cone.updateMatrix();
this.wireframe.scale.set( headWidth, headLength, headWidth );
this.wireframe.position.y = length;
this.wireframe.updateMatrix();
}
setColor( color ) {
this.line.material.color.set( color );
// this.cone.material.color.set( color );
// this.wireframe.material.color.set( color );
}
copy( source ) {
super.copy( source, false );
this.line.copy( source.line );
this.cone.copy( source.cone );
this.wireframe.copy( source.wireframe );
return this;
}
}
For some reason linewidth and wireframeLinewidth don't affect lines widths. Any idea why?
edit: A pyramid is a cone with 4 radial segments, if you want that, look at how the arrowhelper constructs it's cone (which is with a tapered CylinderGeometry) and line based on the parameters and replace it with a cone geometry constructed as follows:
original:
_coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
new:
_coneGeometry = new ConeBufferGeometry( 0.5, 1, 4);
Then you don't have to use the EdgesGeometry, but use the wireframe material option (per #prisoner849's comment):
let wireframeMaterial = new THREE.MeshBasicMaterial({color: "aqua", wireframe: true});
let coneEdgeMesh = new THREE.Mesh(_coneGeometry, wireframeMaterial);
Original answer:
THREE.ArrowHelper consists of 2 Object3Ds: one THREE.Line for the line and one THREE.Mesh for the cone of the arrow. The Line geometry only consists of 2 points and has no edges because it is a line, but for the cone you can use:
let coneEdgeGeometry = new THREE.EdgesGeometry(arrow.cone.geometry);
Then you construct a LineSegments object with the edge geometry and the color you want:
let line = new THREE.LineSegments( coneEdgeGeometry, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
arrow.add(line);
If the cone edge is not showing, try setting the renderOrder of the THREE.LineSegments to -1 (this might give other issues)
You can change the colour of arrow's cone like this:
body {
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight,
1, 100);
camera.position.set(0, 5, 10);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
new OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper());
// different colors
let ah = new THREE.ArrowHelper(
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(-4, 0, 0),
5,
"magenta" /* default colour */);
ah.cone.material.color.set("red"); // change color of cone
scene.add(ah);
// colourful pyramid
let cg = new THREE.SphereBufferGeometry(0.5, 4, 2).toNonIndexed();
let pos = cg.attributes.position;
for (let i = 0; i < pos.count; i++){
if (pos.getY(i) < 0) pos.setY(i, 0);
}
console.log(cg);
let cls = [
new THREE.Color("red"),
new THREE.Color("green"),
new THREE.Color("blue"),
new THREE.Color("yellow")
]
let colors = [];
for(let i = 0; i < 2; i++){
cls.forEach( (c) => {
colors.push(c.r, c.g, c.b);
colors.push(c.r, c.g, c.b);
colors.push(c.r, c.g, c.b);
});
}
cg.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
let cm = new THREE.MeshBasicMaterial({vertexColors: true});
let co = new THREE.Mesh(cg, cm);
co.scale.set(1, 5, 1);
scene.add(co);
renderer.setAnimationLoop(()=>{
renderer.render(scene, camera);
});
</script>

three js - raycaster failing

I have a mesh defined which is at the origin.
var textureCanvas = new THREE.CanvasTexture( imageCanvas );
textureCanvas.repeat.set( 4, 4 );
textureCanvas.wrapS = THREE.RepeatWrapping;
textureCanvas.wrapT = THREE.RepeatWrapping;
var materialCanvas = new THREE.MeshBasicMaterial( { map: textureCanvas }
);
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(-4,-4,0),
new THREE.Vector3(-4,4,0),
new THREE.Vector3(4,4,0),
new THREE.Vector3(4,-4,0),
);
geometry.faces.push(
new THREE.Face3(3, 1, 0),
new THREE.Face3(3, 2, 1)
);
var vertexMappings = [];
vertexMappings[0] = new THREE.Vector2(0,1);
vertexMappings[1] = new THREE.Vector2(0,0);
vertexMappings[2] = new THREE.Vector2(1,0);
vertexMappings[3] = new THREE.Vector2(1,1);
var vm = vertexMappings;
geometry.faceVertexUvs[ 0 ] = [];
geometry.faceVertexUvs[0][0] = [ vm[3], vm[1], vm[0] ];
geometry.faceVertexUvs[0][1] = [ vm[3], vm[2], vm[1] ];
meshCanvas = new THREE.Mesh( geometry, materialCanvas );
meshCanvas.rotation.x = - Math.PI / 3;
meshCanvas.rotation.z = - Math.PI / 2.5;
meshCanvas.scale.set( 80, 80, 80 );
scene.add( meshCanvas );
I also have a line which goes through the mesh. It was originally passing through the origin but I moved it a bit (See github issue below).
var linegeo = new THREE.Geometry();
linegeo.vertices.push(
new THREE.Vector3(55, 300, 0),
new THREE.Vector3(-10, -300, 32)
);
scene.add(linemesh);
I want to get the position where the line intersects the mesh, but the intersections result is always empty:
getInersectionPosition(linemesh, meshCanvas);
function getInersectionPosition(linemesh, meshCanvas) {
linemesh.updateMatrixWorld();
meshCanvas.updateMatrixWorld();
var p1 = linemesh.geometry.vertices[0].clone(),
p2 = linemesh.geometry.vertices[1].clone();
p1.applyMatrix4(linemesh.matrixWorld);
p2.applyMatrix4(linemesh.matrixWorld);
//console.log(`p1: ${JSON.stringify(p1)}, p2: ${JSON.stringify(p2)}`);
//console.log(`canvas position: ${JSON.stringify(meshCanvas.position)}`);
var raycaster = new THREE.Raycaster(p1, p2);
raycaster.linePrecision = 10;
//var intersections = raycaster.intersectObjects([meshCanvas]);
var intersections = raycaster.intersectObjects(scene.children, true);
if (intersections.length > 0)
console.log(`intersections: ${ intersections.length}`);
}
Full sample: https://jsfiddle.net/mribbons/103wwsda/
Is it possible that I have this issue?
https://github.com/mrdoob/three.js/issues/11449
The raycaster.intersectObjects() call seems to fail here, with very large values for distance (2.7 million or so, while sphere.radius is ~450).
https://github.com/mrdoob/three.js/blob/dev/build/three.js#L9761
intersectsSphere: function ( sphere ) {
var distance = this.distanceToPoint( sphere.center )
return distance <= sphere.radius;
},
My mistake, raycaster expects a point and a normal, this resolves the issue:
var normal = new THREE.Vector3();
normal.subVectors(p2, p1).normalize();
var raycaster = new THREE.Raycaster(p1, normal);
var intersections = raycaster.intersectObjects(scene.children, true);
if (intersections.length > 0)
console.log(`intersections: ${ intersections.length}`); // outputs "intersections: 2"

Error in Morphing Vertices using JSON Loader

I've read other articles about morphing vertices, particularly my other post. Then I came up with this code, but still there are errors and I can't find the answer to my current problem.
I've read this example on https://github.com/mrdoob/three.js/blob/master/src/loaders/JSONLoader.js and used the codes there. Yet there are still problems that I can't even know what seems the problem.
Code:
<script src="js/three.min.js"></script>
<script type=text/javascript>
var camera, scene, renderer;
var geometry, material, mesh, loader;
//decalaration of javascript variables thru PHP Declaration
var customHeight = "<?php $height = ($_POST['height'])*20; print $height; ?>";
var customWidth = "<?php $width = ($_POST['width'])*20; print $width; ?>";
var init = function() {
//camera
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 10, 10000 );
camera.position.z = 1000;
//scene
scene = new THREE.Scene();
//renderer
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040 , 10);
document.body.appendChild( renderer.domElement );
customHeightWidth(customWidth, customHeight);
function customHeightWidth(width, height){
//loader
loader = new THREE.JSONLoader();
//material
material = new THREE.MeshBasicMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
overdraw: false,
morphTargets: true,
wireframe: true
});
//loader function
loader = function ( showStatus ) {
THREE.Loader.call( this, showStatus );
this.withCredentials = false;
};
THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {
var scope = this;
// todo: unify load API to for easier SceneLoader use
texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url );
this.onLoadStart();
this.loadAjaxJSON( this, url, callback, texturePath );
};
var xhr = new XMLHttpRequest();
var json = JSON.parse( xhr.responseText );
THREE.JSONLoader.prototype.parse = function ( json, texturePath ) {
var scope = this,
geometry = new THREE.Geometry(),
scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
parseMorphing( scale );
function parseMorphing( scale ) {
if ( json.morphTargets !== undefined ) {
var i, l, v, vl, dstVertices, srcVertices;
for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {
geometry.morphTargets[ i ] = {};
geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
geometry.morphTargets[ i ].vertices = [];
dstVertices = geometry.morphTargets[ i ].vertices;
srcVertices = json.morphTargets [ i ].vertices;
for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
var vertex = new THREE.Vector3();
vertex.x = srcVertices[ v ] * scale;
vertex.y = srcVertices[ v + 1 ] * scale;
vertex.z = srcVertices[ v + 2 ] * scale;
dstVertices.push( vertex );
}
}
}
mesh = new THREE.Mesh(geometry, material);
scene.add( mesh );
}
};
var animate = function() {
requestAnimationFrame(animate);
//mesh.rotation.x += 0.01;
//mesh.rotation.y -= 0.05;
renderer.render(scene, camera);
}
init();
animate();
</script>
This is nothing like what you were trying to do before. Now it looks like you are trying to parse a JSON file directly, in which you should be now referencing http://threejs.org/examples/#webgl_morphtargets_horse
I see loads of problems in this script. You should refer to the source code of that link because there isn't much there and it pretty straight forward.
The block I shared with you before won't work on its own. It was simply an example of how you populate the geometry.morphTargets, you still have other things to do like setup MorphAnimation class (which the source code of the link demonstrates)

Three.js mesh based on BufferGeometry not appearing

I'm working on a WebGL game using Three.js & I've decided to switch to a THREE.BufferGeometry implementation from my (working) regular THREE.Geometry solution. I'm messing something up, because the mesh does not draw. I've given the relevant parts of my code below. If I switch to a regular geometry, everything works fine.
It's a voxel based game and I've pre-created each face of each cube as a regular THREE.Geometry. The positionVertices function takes the vertices and faces from each face geometry, positions them so that they correspond to the voxel, and generates the buffer data for the THREE.BufferGeometry. There are no errors or warnings, the final mesh just doesn't appear. I suspect my problem has less to do with Three.js and more with my limited understanding of 3D graphics programming. My best guess right now is that it has something to do with the indexes not being correct. If I remove the indexes, the object appears, but half of the triangles have their normals in the opposite direction.
Chunk.prototype.positionVertices = function( position, vertices, faces, vertexBuffer, indexBuffer, normalBuffer, colorBuffer ) {
var vertexOffset = vertexBuffer.length / 3;
for( var i = 0; i < faces.length; ++i ) {
indexBuffer.push( faces[i].a + vertexOffset );
indexBuffer.push( faces[i].b + vertexOffset );
indexBuffer.push( faces[i].c + vertexOffset );
normalBuffer.push( faces[i].vertexNormals[0].x );
normalBuffer.push( faces[i].vertexNormals[0].y );
normalBuffer.push( faces[i].vertexNormals[0].z );
normalBuffer.push( faces[i].vertexNormals[1].x );
normalBuffer.push( faces[i].vertexNormals[1].y );
normalBuffer.push( faces[i].vertexNormals[1].z );
normalBuffer.push( faces[i].vertexNormals[2].x );
normalBuffer.push( faces[i].vertexNormals[2].y );
normalBuffer.push( faces[i].vertexNormals[2].z );
}
var color = new THREE.Color();
color.setRGB( 0, 0, 1 );
for( var i = 0; i < vertices.length; ++i ) {
vertexBuffer.push( vertices[i].x + position.x );
vertexBuffer.push( vertices[i].y + position.y );
vertexBuffer.push( vertices[i].z + position.z );
colorBuffer.push( color.r );
colorBuffer.push( color.g );
colorBuffer.push( color.b );
}
};
// This will need to change when more than one type of block exists.
Chunk.prototype.buildMesh = function() {
var cube = new THREE.Mesh();
var vertexBuffer = []; // [0] = v.x, [1] = v.y, etc
var faceBuffer = [];
var normalBuffer = [];
var colorBuffer = [];
for( var k = 0; k < this.size; ++k )
for( var j = 0; j < this.size; ++j )
for( var i = 0; i < this.size; ++i ) {
// Iterates over all of the voxels in this chunk and calls
// positionVertices( position, vertices, faces, vertexBuffer, indexBuffer, normalBuffer, colorBuffer ) for each face in the chunk
}
var bGeo = new THREE.BufferGeometry();
bGeo.attributes = {
index: {
itemSize: 1,
array: new Uint16Array( faceBuffer ),
numItems: faceBuffer.length
},
position: {
itemSize: 3,
array: new Float32Array( vertexBuffer ),
numItems: vertexBuffer.length
},
normal: {
itemSize: 3,
array: new Float32Array( normalBuffer ),
numItems: normalBuffer.length
},
color: {
itemSize: 3,
array: new Float32Array( colorBuffer ),
numItems: colorBuffer.length
}
}
var mesh = new THREE.Mesh( bGeo, VOXEL_MATERIALS["ROCK"]);
return mesh;
}
I needed to set a single offset on the geometry.
bGeo.offsets = [
{
start: 0,
index: 0,
count: faceBuffer.length
}
];
Fixed it. The triangles are still displaying wrong, so I guess the faces are messed up, but I can figure that out easily enough.

Changing texture and color on Three.js collada object

I recently got three.js example from the official site working with my collada objects (.dae) using the ColladaLoader.js.
Now my question is, how do i change the loaded collada object color attribute and add a custom texture?? I tried adding the texture with no luck yet.
Here is my code (slightly changed from the original example):
function load_model(el) {
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, scene, renderer, objects;
var particleLight, pointLight;
var dae, skin;
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( '/site_media/models/model.dae', function ( collada ) {
dae = collada.scene;
skin = collada.skins[ 0 ];
dae.scale.x = dae.scale.y = dae.scale.z = 0.90;
dae.updateMatrix();
init(el);
animate();
} );
function init(el) {
container = document.createElement( 'div' );
el.append( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set( 2, 2, 3 );
scene = new THREE.Scene();
scene.add( dae );
particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
scene.add( particleLight );
// Lights
scene.add( new THREE.AmbientLight( 0xcccccc ) );
var directionalLight = new THREE.DirectionalLight(/*Math.random() * 0xffffff*/0xeeeeee );
directionalLight.position.x = Math.random() - 0.5;
directionalLight.position.y = Math.random() - 0.5;
directionalLight.position.z = Math.random() - 0.5;
directionalLight.position.normalize();
scene.add( directionalLight );
// pointLight = new THREE.PointLight( 0xffffff, 4 );
// pointLight.position = particleLight.position;
// scene.add( pointLight );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth/2, window.innerHeight/2 );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth/2, window.innerHeight/2 );
}
//
var t = 0;
var clock = new THREE.Clock();
function animate() {
var delta = clock.getDelta();
requestAnimationFrame( animate );
if ( t > 1 ) t = 0;
if ( skin ) {
// guess this can be done smarter...
// (Indeed, there are way more frames than needed and interpolation is not used at all
// could be something like - one morph per each skinning pose keyframe, or even less,
// animation could be resampled, morphing interpolation handles sparse keyframes quite well.
// Simple animation cycles like this look ok with 10-15 frames instead of 100 ;)
for ( var i = 0; i < skin.morphTargetInfluences.length; i++ ) {
skin.morphTargetInfluences[ i ] = 0;
}
skin.morphTargetInfluences[ Math.floor( t * 30 ) ] = 1;
t += delta;
}
render();
stats.update();
}
function render() {
var timer = Date.now() * 0.0005;
camera.position.x = Math.cos( timer ) * 10;
camera.position.y = 2;
camera.position.z = Math.sin( timer ) * 10;
camera.lookAt( scene.position );
particleLight.position.x = Math.sin( timer * 4 ) * 3009;
particleLight.position.y = Math.cos( timer * 5 ) * 4000;
particleLight.position.z = Math.cos( timer * 4 ) * 3009;
renderer.render( scene, camera );
}
}
You can override your collada scene materials recursively with this kind of function. It goes through the whole hierarchy and assigns a material.
var setMaterial = function(node, material) {
node.material = material;
if (node.children) {
for (var i = 0; i < node.children.length; i++) {
setMaterial(node.children[i], material);
}
}
}
Use it like setMaterial(dae, new THREE.MeshBasicMaterial({color: 0xff0000}));
You could probably adapt that to modify the existing material properties instead of assigning a new one, if needed.
After many problems, we wrote a small hack in ColladaLoader.js taking the idea from #gaitat
witch basically replaces the old path to the textures from the images, passing some new ones in an array, and using regular expressions to parse the xml for the .png or .jpg under images tag. Not sure if there is an easier way but since support was limited we had to come up with a fix somehow
function parse( doc, imageReplace, callBack, url ) {
COLLADA = doc;
callBack = callBack || readyCallbackFunc;
if ( url !== undefined ) {
var parts = url.split( '/' );
parts.pop();
baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
}
parseAsset();
setUpConversion();
images = parseLib( "//dae:library_images/dae:image", _Image, "image" );
for(var i in imageReplace) {
var iR = imageReplace[i];
for(var i in images) {
var image = images[i];
var patt=new RegExp('[a-zA-Z0-9\-\_]*\/'+iR.name,'g');
//if(image.id==iR.id)
if(patt.test(image.init_from))
image.init_from = iR.new_image;
}//for
}
materials = parseLib( "//dae:library_materials/dae:material", Material, "material" );
effects = parseLib( "//dae:library_effects/dae:effect", Effect, "effect" );
geometries = parseLib( "//dae:library_geometries/dae:geometry", Geometry, "geometry" );
cameras = parseLib( ".//dae:library_cameras/dae:camera", Camera, "camera" );
controllers = parseLib( "//dae:library_controllers/dae:controller", Controller, "controller" );
animations = parseLib( "//dae:library_animations/dae:animation", Animation, "animation" );
visualScenes = parseLib( ".//dae:library_visual_scenes/dae:visual_scene", VisualScene, "visual_scene" );
morphs = [];
skins = [];
daeScene = parseScene();
scene = new THREE.Object3D();
for ( var i = 0; i < daeScene.nodes.length; i ++ ) {
scene.add( createSceneGraph( daeScene.nodes[ i ] ) );
}
// unit conversion
scene.position.multiplyScalar(colladaUnit);
scene.scale.multiplyScalar(colladaUnit);
createAnimations();
var result = {
scene: scene,
morphs: morphs,
skins: skins,
animations: animData,
dae: {
images: images,
materials: materials,
cameras: cameras,
effects: effects,
geometries: geometries,
controllers: controllers,
animations: animations,
visualScenes: visualScenes,
scene: daeScene
}
};
if ( callBack ) {
callBack( result );
}
return result;
};
One thing you can do is modify your collada model (dae file) locate the texture reference there and change it to your liking.
if ( url !== undefined ) {
var parts = url.split( '/' );
parts.pop();
baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
}
parseAsset();
setUpConversion();
images = parseLib( "//dae:library_images/dae:image", _Image, "image" );
for(var i in imageReplace) {
var iR = imageReplace[i];
for(var i in images) {
var image = images[i];
var patt=new RegExp('[a-zA-Z0-9\-\_]*\/'+iR.name,'g');
//if(image.id==iR.id)
if(patt.test(image.init_from))
image.init_from = iR.new_image;
}//for
}

Categories

Resources