How should I make an aoMap work for a normal THREE.Geometry? Is there a demo?
var uvs = geometry.attributes.uv.array;
geometry.addAttribute('uv2', new THREE.BufferAttribute(uvs, 2));
Above code is for BufferGeometry.
An aoMap requires the 2nd set of UVs. You can create a 2nd set of UVs by duplicating the first set if you want.
This is how to do it for Geometry:
geometry.faceVertexUvs[ 1 ] = geometry.faceVertexUvs[ 0 ];
And this is how to do it for BufferGeometry:
var uvs = geometry.attributes.uv.array;
geometry.addAttribute( 'uv2', new THREE.BufferAttribute( uvs, 2 ) );
... or more simply:
geometry.attributes.uv2 = geometry.attributes.uv;
three.js r.88
Related
I have a problem with spotlight. I was using r.73 and had 50x simple Spotlights without shadows etc.. it works without problems, still 60fps also on mobile.
Now i was changed to r84 (The problem occurs above r73), and the spotlights are much better quality but also drop my frames. I know there was some changes with adding penumbra options in r74.. i not really understand how can i set down the quality..
On fiddle , you dont see qualityChanges, dont matter. but Frames will drope.
So my Question, is it possible to set up the spotlight of a way, i still have 60frames?
The mistake occurs only when the mesh (floor) is big enough.
var spotLightSize=50;
var spotLight=[];
var geometry = new THREE.BoxGeometry( 500, 1, 500 );
var material = new THREE.MeshPhongMaterial( {color: "blue"} );
var floor = new THREE.Mesh( geometry, material );
var renderer = new THREE.WebGLRenderer({precision:"lowp",alpha:true});
for (var i=0;i<spotLightSize;i++){
spotLight.push(new THREE.SpotLight("green" ,2,20,0.1,0,1));
spotLight[spotLight.length-1].position.set( 0, 5, 0 );
scene.add(spotLight[spotLight.length-1]);
var spotLightHelper = new THREE.SpotLightHelper( spotLight[spotLight.length-1] );
scene.add( spotLightHelper );
}
http://jsfiddle.net/killerkarnikel/hyqgjLLz/19/
I'm a beginner using three.js and I am trying to have two materials defined on one single object, and alternate between the two using a visibilty flag, but with no success.
Is there another way, or can this be done?
var materials = [
new THREE.MeshPhongMaterial( { color: 0x00ff00,visible:true, shininess: 1 } ),
new THREE.MeshPhongMaterial( { color: 0xff0000,visible:false, shininess: 1 } )
];
obj= THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
scene.add( obj);
scene.traverse(function (node){
if(node instanceof THREE.Mesh) {
node.visible =!node.visible;
}
});
I will entually aplly this to all objects in the scene that's why I'm using the scene.traverse
It looks like you're trying to apply visibility to the materials, yet you're checking the meshes during your traverse. Remove the visibility: true/false from your material definitions, and add the following line:
obj= THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
obj.children[1].visible = false; // add this line
scene.add( obj);
This will apply visibility = false to the second mesh created by createMultiMaterialObject. Your traverse will then correctly flip the visibility of the meshes.
As you get to know THREE.js better, you'll want to look into THREE.MultiMaterial and geometry groups for applying multiple materials to a single mesh.
I'm trying to define a model of the human body in THREE.js using the classes THREE.Bone, THREE.Skeleton and THREE.SkinnedMesh.
I defined a custom skeleton structure made of 12 body parts, each of which is a THREE.Bone instance, and used the .add() method to define parent / child relationships among them. Finally, I created a standard THREE.Object3D as the body root that is parent of the full skeleton.
Posting only part of the structure for conciseness:
// create person object
var body_root = new THREE.Object3D()
// create torso
var torso = new THREE.Bone();
torso.id = 1;
torso.name = "torso";
x_t = 0;
y_t = 0;
z_t = 0;
torso.position.set(x_t,y_t,z_t);
x_alpha = 0 * Math.PI;
y_alpha = 0 * Math.PI;
z_alpha = 0 * Math.PI;
torso.rotation.set(x_alpha,y_alpha,z_alpha);
// create right arm
var right_arm = new THREE.Bone();
right_arm.id = 2;
right_arm.name = "right_arm";
x_t = -TORSO_WIDTH / 2;
y_t = TORSO_HEIGHT;
z_t = 0;
right_arm.position.set(x_t,y_t,z_t);
x_alpha = 0 * Math.PI;
y_alpha = 0 * Math.PI;
z_alpha = 0 * Math.PI;
right_arm.rotation.set(x_alpha,y_alpha,z_alpha);
// add right_arm as child of torso
torso.add( right_arm );
This works just fine, and after loading the page I can access the model and traverse it correctly through the console.
However, when I try to render the skeleton in the scene things get tricky.
1. How can I add a THREE.SkinnedMesh for a custom skeleton structure?
In the documentation (check source code) a CylinderGeometry and a SkinnedMesh are created for all the bones jointly
var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 );
var mesh = THREE.SkinnedMesh( geometry, material );
and then the bone structure is binded:
// See example from THREE.Skeleton for the armSkeleton
var rootBone = armSkeleton.bones[ 0 ];
mesh.add( rootBone );
// Bind the skeleton to the mesh
mesh.bind( armSkeleton );
This works perfectly for the simple example in the documentation (5 bones each one parent of the next one), but how can I adapt this example to a more complex structure in which some bones have multiple children? And how can I implement bones with different geometry? For instance I would like to implement joints like shoulder and elbow with a sphere for which I can only change rotation and body parts like arm and forearm with cylinders having different base radius.
Is it possible to define a SkinnedMesh for each joint independently and for a more complex structure than the one in the example? If so how do you link them all together?
2. Can I add a THREE.SkeletonHelper to the scene without defining a skinned mesh but using only the bones?
Since I don't know the answer to question 1 I decided to simply try to render the skeleton structure. This is done in other examples (such as this one) by creating a THREE.SkeletonHelper instance and adding that to the scene.
I tried passing the body_root variable (instead of the SkinnedMesh) to the constructor and the helper is created, but not rendered.
helper = new THREE.SkeletonHelper( body_root );
helper.material.linewidth = 3;
scene.add( helper );
In order to visualize the helper it needs to be binded to a mesh, even if the mesh is not added directly to the scene, i.e. adding the line mesh.bind(armSkeleton) visualizes the skeleton helper.
Is this possible at all to visualize the skeleton helper without defining a mesh? If so how?
NOTE on question 2:
I believe this should be possible, since the THREE.SkeletonHelper class defines internally its own geometry and material, so it should be possible to render it without needing the mesh of the skeleton:
THREE.SkeletonHelper = function ( object ) {
this.bones = this.getBoneList( object );
var geometry = new THREE.Geometry();
for ( var i = 0; i < this.bones.length; i ++ ) {
var bone = this.bones[ i ];
if ( bone.parent instanceof THREE.Bone ) {
geometry.vertices.push( new THREE.Vector3() );
geometry.vertices.push( new THREE.Vector3() );
geometry.colors.push( new THREE.Color( 0, 0, 1 ) );
geometry.colors.push( new THREE.Color( 0, 1, 0 ) );
}
}
geometry.dynamic = true;
var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } );
THREE.LineSegments.call( this, geometry, material );
this.root = object;
this.matrix = object.matrixWorld;
this.matrixAutoUpdate = false;
this.update();
};
I've got a line "walking around my scene" (some kind of a 3D snake) randomly and the next thing I wish to achieve is set a box around its head.
The line bufferGeometry is set by
var positions1 = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
var positions2 = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
buffGeometry1.addAttribute( 'position', new THREE.BufferAttribute( positions1, 3 ) );
buffGeometry2.addAttribute( 'position', new THREE.BufferAttribute( positions2, 3 ) );
I chose to set a cube (boxGeometry object) around it, and I used the following code lines to try and achieve that:
var positioning = buffGeometry1.getAttribute('position');
cube.position.x = positioning[0];//(line1.geometry.attributes.position.array[drawCount]);
cube.position.y = positioning[1];//(line1.geometry.attributes.position.array[drawCount + 1]);
cube.position.z = positioning[2];
As I debug, I see that my positioning array is undefined. so I guess something there went wrong.
Thanks.
Try:
console.log(buffGeometry1.getAttribute('position'))
My THREE.BufferGeometry shows me that verticles are stored in positioning.array so you should acces them by:
positioning.array[0]
positioning.array[1]
positioning.array[2]
If you add let's say a point to your scene using BufferGeometry, you can also try accessing the coordinates like this :
/// X coordinate /////
console.log(point1.geometry.attributes.position.array[0]);
/// Y coordinate /////
console.log(point1.geometry.attributes.position.array[1]);
/// Z coordinate /////
console.log(point1.geometry.attributes.position.array[2]);
I have tried a few different lights now (Directional, Spot, Point), but none of them produce a nice shadow on MeshFaceMaterial objects. Instead, the entire MeshFaceMaterial object will become black.
My Test Website (please view with a grain of salt, constantly being changed).
How can I use lights to create shadows on MeshFaceMaterials? Does MeshFaceMaterial support shadows? The documentation says "Affects objects using MeshLambertMaterial or MeshPhongMaterial."
Here is sample code of how I am loading .json model.
loader.load('sample-concrete.js', function ( geometry, materials ) {
mesh1 = new THREE.Mesh(
geometry, new THREE.MeshFaceMaterial( materials )
);
mesh1.rotation.x = -Math.PI / 2;
scene.add( mesh1 );
});
and here is a sample of the material from my .json file.
"materials": [
{
"DbgIndex" : 0,
"DbgName" : "Steel",
"colorDiffuse" : [0.3059, 0.0471, 0.0471],
"colorAmbient" : [0.3059, 0.0471, 0.0471],
"colorSpecular" : [1.0000, 1.0000, 1.0000],
"transparency" : 1.0,
"specularCoef" : 25.0,
"vertexColors" : false
}
Thank you.
A MeshFaceMaterial is just a collection of materials. So if your materials variable contains MeshLambertMaterial or MeshPhongMaterial you should be fine. Shadows will be generated from a DirectionalLight or a SpotLight.
Just make sure your renderer has:
renderer.shadowMapEnabled = true;
your light has:
light.castShadow = true;
each one of your meshes:
mesh.castShadow = true;
and you have at least one object (a plane for example) where you do:
plane.receiveShadow = true;