I am digging into Three.js and am experimenting with vrml, and now with collada files.
Importing a collada file works. It works with webGL AND canvas as a fallback : my 3D model rotates, shows the model… and in webGL i can even have that wonderful effects like shadows, bumps, etc.
I did achieve loading another texture file, assigning it to the webGL renderer… but in this particular case, the canvas renderer completely fails : frames drop from 60fps to 2fps, and the texture "slides" on the polygons.
I guess i miss something in order to "fix" the texture to the model, or when importing the texture maybe do i miss some parameters ? Once again it is working fine without changing the texture… but i really need to do so :p
Here is a working preview : http://dokmixer.com/three-tests/
And here is the part where the magic fails :
//model loading
loader = new THREE.ColladaLoader();
loader.load('models/collada/7cm.005.dae',function colladaReady( collada ){
player = collada.scene;
skin = collada.skins [ 0 ];
player.scale.x = player.scale.y = player.scale.z = 0.10;
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var newskinTexture = new THREE.ImageUtils.loadTexture( 'models/collada/dokMixer.png' );
themodel = collada.scene.children[0];
themodel.material = new THREE.MeshBasicMaterial( { map: newskinTexture, overdraw: true} );
}
else {
var newskinTexture = new THREE.ImageUtils.loadTexture( 'models/collada/dokMixer.png' );
var bumpTexture = new THREE.ImageUtils.loadTexture( 'models/collada/noise.png' );
bumpTexture.anisotropy = 2;
player_material = collada.scene.children[0].material;
themodel = collada.scene.children[0];
themodel.material = new THREE.MeshPhongMaterial( { map: newskinTexture, bumpMap: bumpTexture, bumpScale: 0.05} );
}
//utile pour avoir les ombres
daemesh = player.children[0];
daemesh.castShadow = true;
daemesh.receiveShadow = true;
scene.add( player );
});
The part to look into is the first if statement (as i am testing canvas with Safari, before expanding to other canvas enabled devices). When assigning a new material, the renderer completely fails. You can test the effect by going to the page with Safari.
Note : i am working on OSX if that can be of any relevant information.
Any help appreciated :)
EDIT : i guess i'm setting here a new material, instead of replacing only the source image file ?
Okay, finally found a workaround !
The way i swapped texture was wrong for canvas, i assume it is a bug. I found a clue on this answer by psychok7.
So well, instead of loading and THEN changing a texture… i changed the code in the ColladaLoader.js file. Well, almost the same. Since i use "load" i added a couple times imageReload in the load function, and when calling the "parse" function. Then, in the parse function i did some changes too as the code given was wrong on their link. For those interested, a list of the changes, and my final code. Sadly i couldn't achieve the "same" functionnalities (sending an array of textures, doing the regExp thing, and replacing several textures at once), this part was buggy for me, and since i needed to change only one texture file…
So, long story short, here's the code where i call the collada
loader = new THREE.ColladaLoader();
newtextures = ['dokMixer.png'];
loader.load('models/collada/7cm.005.dae', newtextures,function colladaReady( collada ){
player = collada.scene;
skin = collada.skins [ 0 ];
player.scale.x = player.scale.y = player.scale.z = 0.10;
//i'll add code here later for extra bump mapping on webgl versions
//usefull for shadows on webgl version
daemesh = player.children[0];
daemesh.castShadow = true;
daemesh.receiveShadow = true;
scene.add( player );
});
And here's the code inside the colladaLoader. It is a replacement of the functions load, and parse.
function load ( url, imageReplace, readyCallback, progressCallback ) {
var length = 0;
if ( document.implementation && document.implementation.createDocument ) {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if( request.readyState == 4 ) {
if( request.status == 0 || request.status == 200 ) {
if ( request.responseXML ) {
readyCallbackFunc = readyCallback;
parse( request.responseXML, imageReplace, undefined, url );
} else if ( request.responseText ) {
readyCallbackFunc = readyCallback;
var xmlParser = new DOMParser();
var responseXML = xmlParser.parseFromString( request.responseText, "application/xml" );
parse( responseXML, imageReplace, undefined, url );
} else {
console.error( "ColladaLoader: Empty or non-existing file (" + url + ")" );
}
}
} else if ( request.readyState == 3 ) {
if ( progressCallback ) {
if ( length == 0 ) {
length = request.getResponseHeader( "Content-Length" );
}
progressCallback( { total: length, loaded: request.responseText.length } );
}
}
}
request.open( "GET", url, true );
request.send( null );
} else {
alert( "Don't know how to parse XML!" );
}
}
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( "library_images image", _Image, "image" );
for(var i in imageReplace) {
var iR = imageReplace[i];
for(var i in images) {
var image = images[i];
//added line, but no multiple textures !
image.init_from = iR;
//RegExp and patt.test not working
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( "library_materials material", Material, "material" );
effects = parseLib( "library_effects effect", Effect, "effect" );
geometries = parseLib( "library_geometries geometry", Geometry, "geometry" );
cameras = parseLib( "library_cameras camera", Camera, "camera" );
lights = parseLib( "library_lights light", Light, "light" );
controllers = parseLib( "library_controllers controller", Controller, "controller" );
animations = parseLib( "library_animations animation", Animation, "animation" );
visualScenes = parseLib( "library_visual_scenes visual_scene", VisualScene, "visual_scene" );
// 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;
}
Hope this helps someone ! Have fun ! :)