ThreeJs and Blender (using colladaLoader): first contact - three.js

How can I render an exported scene (with many objects, each with different colors and different properties, such as rotation aroung an axis in the scene) from Blender (with colladaLoader -->.dae) in ThreeJs?

So, the first step is to learn how to create a scene in threeJs and learn some feature with Blender. When you are ready, create your first model and before exporting keep this in mind:
you need to an object with vertices, so if you just create a text with Blender, you have to convert it to a mesh, otherwise threeJs will not render it
be sure to choose the Blender render option and not the Cycles,
otherwise the .dae you export will not be rendered in threeJs
when applying a texture, use just colors and basic materials (basic, phong and lambert) - the others will not work using the colladaLoader
to see if the object will be rendered with color in threeJs with
colladaLoader just look at object in Blender with object mode
(solid) - if it's gray and not colored of the color you choose, it
will be rendered in threeJs the same way
if you apply the 'solidify' modifier to the object and then on threeJs set it to transparent, it will be rendered as wireframed
if you append multiple objects in the scene and 'join' them, the
respective positions and rotations will be respected in threeJs,
otherwise not: for example, if you want to renderize a flower in the
bottle (and thoose objects are different blender files which are
appended/linked in the scene), the flower will not fit in the bottle
in threeJs, but would have a different position and rotation than
the bottle
grouping the objects will not solve this: to see the scene as you see it in Blender you have to 'join' the objects (with the consequences that this entails) or manually change position and rotation on threeJs
the .dae export options don't matter for the rendering of the object in threeJs
and now, the part that regards threeJs:
be sure to import the colladaLoader with:
<script src="jsLib/ColladaLoader.js"></script>
insert this code into your init() function so the loader will load your .dae model:
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( 'model.dae', function ( collada ) {
// with this you can get the objects of the scene; the [0] is not the first object
// you display in blender in case of many objects (which means you didn't join them)
var obj1 = collada.scene.children[0];
// you can name the object so you can use it even out of the function, if you want
// animate it for example obj1.name = "daeObj1";
// you can set here some material properties as trasparency
obj1.material.needsUpdate = true;
obj1.material.transparent = true;
obj1.material.opacity = 0.5;
obj1.hearth.material.wireframe = false;
// and now some position and rotation for good visualization
obj1.position.set(0, -5, -0.6); //x,z,y
obj1.rotation.set(0, 45, 0);
// and add the obj to the threeJs scene
scene.add(obj1);
});
and some code to the animate() function if you want to update some of your objects, with rotation for example
scene.traverse (function (object) {
if (object.name === 'daeObj1') {
object.rotation.z -= 0.01;
}
});
I hope someone will benefit from this post

Related

ColladaLoader horizontal vector

I use blender and three.js to read the .dae file respectively, the blender shows parallel to the x and z axes, but three.js shows that it is tilted 90 degrees to the y axis.
Example file(1b03f03d-88a2-4c12-9c75-82539a48c081)
blender:
three.js:
let loaderDae = new ColladaLoader();
loaderDae.load('assets/1b03f03d-88a2-4c12-9c75-82539a48c081/untitled.dae', (dae: any) => {
this.model = dae.scene.children[0];
this.model.position.multiplyScalar(0);
this.scene.add(this.model);
});
I don't know if it's a problem with the vector in the original file, or with three.js reading it, should I modify the original file or adjust the vector through three.js?
How can I flip the model if it is through three.js?
this.model = dae.scene.children[0];
Since you are doing this, you skip a transformation of the root object that performs the up axis conversion. So just do this:
this.model = dae.scene;
In general, you should really consider the usage of Collada (as well as OBJ and FBX) since the more modern glTF is better in so many ways. At least when exporting a glTF asset from Blender, it will automatically care about proper up axis conversion.

Three.js parenting mesh to bone

My goal is to attach separate objects (eg: wearable items) to an animated model, so that the bound objects are controlled by the models animation.
I have found these, but all seems outdated.
Three.js attaching object to bone
https://github.com/mrdoob/three.js/issues/3187
I experimenting with a character imported from blender that is skinned & rigged & animated.
My problem is: As I add a new mesh to a specific bone of the model (the commented out part in the code), the current animation clip is switched to the first one (t-pose), and the skinning get broken (model turns white).
However the object is connects to the bone, and moves with it.
const {scene, animations} = await Utils.loadModel('model/someName.gltf');
const model = scene.children[0];
const material = new THREE.MeshBasicMaterial();
material.alphaTest = 0.5;
material.skinning = true;
model.traverse((child) => {
if (child.material) {
material.map = child.material.map;
child.material = material;
child.material.needsUpdate = true;
}
if (child.isBone && child.name === 'RightHand') {
// child.add(createMesh());
}
});
gScene.add(model);
It dosen't work correctly, even if a simple cube is added, but it would be nice if I could add boots to a character, that is moves as its foot.
Looks like I have found a solution.
I updated the demo (It's only a PoC) https://github.com/tomo0613/3d-animated-char-test
first (in blender):
add bones to the shoe that should move with the character. (i guess these should heave the same bones [positions, rotations, sizes]; there are differences in the demo)
then is JS code:
add the shoe (entire mesh) as a child mesh to the leg bone.
before every render, copy the characters bone properties to the shoe bone properties [position & quaternion]
I'm still curious, is there any intended /or better way doing this.?

Applying different textures on a THREE.js OBJLoader loaded object

I have a square shape .obj model and 2 textures. How do I apply one texture on it's top face and another on rest of faces?
There are a ton of ways to do what you're asking all with varying complexity depending on your needs. It looks like you want to apply two materials to your object and not two textures.
It looks this way because it seems you want the textures to be interchangeable so there's no way you're going to combine the images and keep resolution and OBJ & THREE.Material only support one set of uv attributes so you can't use a single material and multiple textures. So multiple materials it is...
Multiple materials
If you have two materials (2 THREE.Materials which correlate to 2 WebGL programs) then each face needs to know what material it's assigned to.
While the THREE.js multi material API has been in flux for quite a while and there are differences between THREE.Geometry and THREE.BufferGeometry, fortunately for you THREE.OBJLoader supports material groups out of the box. To get this into THREE.js, you want to apply multiple materials in your 3D editor to your object and then export the OBJ to get everything. Doing it by hand is a little harder and requires calling addGroup as shown in the docs/the link above.
In THREE.js you simply pass in all the materials as an array to your object demonstrated in this answer. I also updated your fiddle to do the same thing. Relevant code shown below
var loadingManager = new THREE.LoadingManager();
var ObjLoader = new THREE.OBJLoader(loadingManager);
var textureLoader = new THREE.TextureLoader(loadingManager);
//Material 1 with first texture
var material = new THREE.MeshLambertMaterial({map: textureLoader.load('https://dl.dropboxusercontent.com/s/nvnacip8fhlrvm4/BoxUV.png?dl=0')});
//Material 2 with second texture
var material2 = new THREE.MeshLambertMaterial({map:
textureLoader.load('https://i.imgur.com/311w7oZ.png')});
ObjLoader.load(
'https://dl.dropboxusercontent.com/s/hiazgei0rxeirr4/cabinet30.obj?dl=0',
function ( object ) {
var geo = object.children[0].geometry;
var mats = [material, material2];
//These are just some random groups to demonstrate multi material, you need to set these up so they actually work for your object, either in code or in your 3D editor
geo.addGroup(0,geo.getAttribute("position").count/2,0);
geo.addGroup(geo.getAttribute("position").count/2,
geo.getAttribute("position").count/2,1);
//Mesh with multiple materials for material parameter
obj = new THREE.Mesh(geo, mats);
obj.position.y = 3;
});

How to set camera coordinates to object in three.js? Using example "webgl obj + mtl loader"

I have a 3D model in .obj format. However the coordinates for this 3D model are not (0,0,0). This a 3D render of drone imagery so the coordinates are actual georeferenced coordinates.
I'm following the example in Three.js on how to load an obj with its mtl on webgl. I use the original HTML except that I simply replace the obj listed as male02 by CerroPelaoLow and the files are placed in the obj directory. Firefox displays the model correctly but the position is the problem.
Note that this render is generated by a program this way and even though I can manipulate the model with a program such as Meshlab I'd still prefer the minimum manipulation possible.
So how can I use local coordinates of my object or focus the camera and then use a different set of controls?
You can use the boundingSphere or boundingBox of your object's geometry to determine the position and of your camera. I have already implemented a functionality to focus an object or a set objects. So, here I share some code:
// assuming following variables:
// object -> your obj model (THREE.Mesh)
// camera -> PerspectiveCamera
// controls -> I'm also using OrbitControls
// if boundingSphere isn't set yet
object.computeBoundingSphere();
var sphere = object.geometry.boundingSphere.clone();
sphere.applyMatrix4( object.matrixWorld );
// vector from current center to camera position (shouldn't be zero in length)
var s = new THREE.Vector3().subVectors( camera.position, controls.center );
var h = sphere.radius / Math.tan( camera.fov / 2 * Math.PI / 180 );
var newPos = new THREE.Vector3().addVectors( sphere.center, s.setLength(h) );
camera.position.copy( newPos );
controls.center.copy( sphere.center );

Stretch image texture to fit mesh face in Three.js

I'm trying to make the following in three.js:
I made the model in sketchup with some simple coloured textures and used the collader importer, the result looks like this:
Now I want to dynamically load some photographs onto each of the different planes, however what I end up with is this:
So as you can see, each image is loaded but they are very small and repeated across the rest of the surface.
This is how I load the textures: (preloadTexture() is just a simple preloader)
for(i in cubeSidesArray)
{
preloadTexture(modelThumbsArray[i]);
var newTexture = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture(modelThumbsArray[i]) } );
cubeSidesArray[i].material = newTexture;
}
How do I get the textures to fill the surface?
Thanks!
Edit - I played with the model in sketchup and managed to get it a little better, but not much!
Edit 2 - Still no luck, I'm starting to think building it in code from scratch would be simpler
Option 1: I would advise you to do or next.
1 -.Import the model blender
2 -.Export blender to threejs
3 -.Use this method of charging.
AgregarModeloBlender function (geometry, materials) {
console.log(materials);
material = new THREE.MeshFaceMaterial( materials );
modelo3d_ = new THREE.Mesh( geometry,material );
escenario.add(modelo3d_);
modelo3d_.add(camera);
modelo3d_.scale.set(5,5,5);
modelo3d_.position.set(-900,25,850);
modelo3d_.rotation.y=Math.PI;
}
4 -. Subsequently trabajr with textures independently.
Example: http://all.develoteca.com/builder/
Option 2: I would advise you to do or this:
1 -. Create the geometric shape (vertices) to modify each of the faces of the texture.
Example: http://develoteca.com/Panel/
Greetings.

Resources