I am currently playing with ThreeJS decals. I have been able to put a beautiful stain on my sphere.
Here is the piece of code I use to "apply" the decal on my sphere. (I have some custom classes, but don't worry about this.
// Create sphere
var mainMesh = new THREE.Mesh(
new THREE.SphereGeometry(7, 16, 16),
new THREE.MeshBasicMaterial({ color: 0x00a1fd })
);
// Declare decal material
var decalMaterial = new THREE.MeshPhongMaterial({
color : 0xff0000,
specular : 0x444444,
map : TextureLoader.instance.getTexture('http://threejs.org/examples/textures/decal/decal-diffuse.png'),
normalMap : TextureLoader.instance.getTexture('http://threejs.org/examples/textures/decal/decal-normal.jpg'),
normalScale : new THREE.Vector2( 1, 1 ),
shininess : 30,
transparent : true,
depthTest : true,
depthWrite : false,
polygonOffset : true,
polygonOffsetFactor : -4,
wireframe : false
});
// Create decal itself
var decal = new THREE.Mesh(
new THREE.DecalGeometry(
mainMesh,
new THREE.Vector3(0, 2.5, 3),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(8, 8, 8),
new THREE.Vector3(1, 1, 1)
),
decalMaterial.clone()
);
// Add mesh + decal + helpers
scene.add(
mainMesh,
new THREE.HemisphereLight(0xffffff, 0, 1),
decal,
new THREE.WireframeHelper(decal, 0xffff00)
);
decal.add(new THREE.BoxHelper(decal, 0xffff00));
Now, I woud like to move this stain on my sphere, and thus, update the geometry of my decal.
Unfortunately, when I call decal.geometry.computeDecal(), the mesh of the decal does not update. I can't find any solution about this.
function moveDecal()
{
decal.translateX(1);
decal.geometry.computeDecal();
};
According to the DecalGeometry class, the function computeDecal already set to true various members required to update vertices, colors, UVs, ....
this.computeDecal = function() {
// [...]
this.verticesNeedUpdate = true;
this.elementsNeedUpdate = true;
this.morphTargetsNeedUpdate = true;
this.uvsNeedUpdate = true;
this.normalsNeedUpdate = true;
this.colorsNeedUpdate = true;
};
Thank you for your help ! :D
PS : ThreeJS r80
You are trying to update vertices of your geometry.
You can change the value of a vertex componnent,
geometry.vertices[ 0 ].x += 1;
but you can't add new veritices
geometry.vertices.push( new THREE.Vector3( x, y, z ) ); // not allowed
or assign a new vertex array
geometry.vertices = new_array; // not allowed
after the geometry has been rendered at least once.
Similalry, for other attributes, such as UVs.
For more info, see this answer: verticesNeedUpdate in Three.js.
three.js r.80
Related
I want to draw a triangle and i know only all angles (Alpha,Beta,Gamma) and all side length (10).
For drawing a triangle i need to set 3 vertices to geometry with absolute Vector3 values.
Is in THREE.js any integrated tool or practice fit for this?
geometry.vertices.push(
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( -10, -10, 0 ),
new THREE.Vector3( 10, -10, 0 ),
);
geometry.faces.push( new THREE.Face3( 0, 1, 2 ));
var material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } );
var mesh = new THREE.Mesh( geometry, material );
Only THREE method i can imagine is to create a 2 vector geometry with vector distance of side lengths, use matrix translation to set rotation pivot on vector[0] and change its position and rotation, each time set globalToWorld() for its vector[1]. But I think this is not a good solution.
I used this:
var length = 10;
var aplpha = 0.3;//rad
var beta= 1;//rad
geometry.vertices.push(
new THREE.Vector3(),
new THREE.Vector3(length ,0,0).applyAxisAngle(new THREE.Vector3(0,1,0),aplpha ),
new THREE.Vector3(length ,0,0).applyAxisAngle(new THREE.Vector3(0,1,0),beta ),
new THREE.Vector3(),
);
https://threejs.org/docs/#api/en/math/Vector3
THREE.JS r 96
In three.js I have created an ellipseCurve for which I want to extrude and make 3d.
CODE USE TO MAKE THIS:
var curve = new THREE.EllipseCurve(
0, 0, // ax, aY
10, 13.3, // xRadius, yRadius
0, 2 * Math.PI, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
);
var path = new THREE.Path( curve.getPoints( 100 ) );
var geometrycirc = path.createPointsGeometry( 50 );
var materialcirc = new THREE.LineBasicMaterial( {
color : 0xff0000
} );
// Create the final object to add to the scene
var ellipse = new THREE.Line( geometrycirc, materialcirc );
this.scene.add( ellipse );
I want to use this ellipseCurve as a basis to create an extruded shape similar to these examples.
https://threejs.org/examples/#webgl_geometry_extrude_splines
These examples seem to use vectors to do this, so I assume I need to convert the curve into one.
I am not sure how to do this since I have been unable to find references on this matter.
Any help to do this?
UPDATE: 22/03/2017
Right so I tried to implement the same method of extrusion as found on:
https://threejs.org/examples/#webgl_geometry_extrude_splines
I was able to but this spline into my scene:
HERE IS THE CODE TO DO THIS:
/////////////////////////////////////////////////////////////////////////
// My line curve //
/////////////////////////////////////////////////////////////////////////
var curve = new THREE.EllipseCurve(
0, 0, // ax, aY
10, 13.3, // xRadius, yRadius
0, 2 * Math.PI, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
);
var path = new THREE.Path( curve.getPoints( 100 ) );
var geometrycirc = path.createPointsGeometry( 50 );
var materialcirc = new THREE.LineBasicMaterial( {
color : 0xff0000
} );
// Create the final object based on points and material
var ellipse = new THREE.Line( geometrycirc, materialcirc );
this.scene.add( ellipse );
////////////////////////////////////////////////////////////////////////
// Example of sample closed spine //
////////////////////////////////////////////////////////////////////////
var sampleClosedSpline = new THREE.CatmullRomCurve3( [
new THREE.Vector3( 0, -40, -40 ),
new THREE.Vector3( 0, 40, -40 ),
new THREE.Vector3( 0, 140, -40 ),
new THREE.Vector3( 0, 40, 40 ),
new THREE.Vector3( 0, -40, 40 )
] );
sampleClosedSpline.type = 'catmullrom';
sampleClosedSpline.closed = true;
//////////////////////////////////////////////////////////////////////////////
// Extrusion method to covert the spline/vector data into 3d object //
//////////////////////////////////////////////////////////////////////////////
// I used this method and have tried the following properties but these do not work
//
// var tube = new THREE.TubeBufferGeometry( curve, 12, 2, 20, true);
//
// 1. ellipse.clone()
// 2. geometrycirc.clone()
// 3. materialcirc.clone()
// 4. path.clone()
// 5. curve
//
// Therefore I am either doing something wrong or there must be a further process that needs
// to be implemented.
// this works as standard
var tube = new THREE.TubeBufferGeometry( sampleClosedSpline, 12, 2, 20, true);
var tubeMesh = THREE.SceneUtils.createMultiMaterialObject( tube, [
new THREE.MeshLambertMaterial( {
color: 0xffffff
} ),
new THREE.MeshBasicMaterial( {
color: 0xff00ff,
opacity: 0.3,
wireframe: true,
transparent: true
} ) ] );
tubeMesh.scale.set( .2, .2, .2 );
this.scene.add( tubeMesh );
///////////////////////////////////////////////////////////////////////////////
So when I place the spline property for the one that I have created i get a black screen and the following error msgs:
var curve;
and the other variables used (refer to code to see what I have tried)
EDIT: 23/03/2017
WestLangley's method was the ideal solution
You want to create a TubeGeometry or TubeBufferGeometry in the shape of an ellipse.
Here is one way to do it that is general enough for others to use, too.
First, create a new class that defines your path:
// Ellipse class, which extends the virtual base class Curve
class Ellipse extends THREE.Curve {
constructor( xRadius, yRadius ) {
super();
// add radius as a property
this.xRadius = xRadius;
this.yRadius = yRadius;
}
getPoint( t, optionalTarget = new THREE.Vector3() ) {
const point = optionalTarget;
var radians = 2 * Math.PI * t;
return new THREE.Vector3( this.xRadius * Math.cos( radians ),
this.yRadius * Math.sin( radians ),
0 );
}
}
Then create the geometry from the path.
// path
var path = new Ellipse( 5, 10 );
// params
var pathSegments = 64;
var tubeRadius = 0.5;
var radiusSegments = 16;
var closed = true;
var geometry = new THREE.TubeBufferGeometry( path, pathSegments, tubeRadius, radiusSegments, closed );
Super easy. :)
Fiddle: http://jsfiddle.net/62qhxags/
three.js r.129
Got the following problem:
im trying to make rings around saturn, but it seems they are somehow rendered in wrong order:
The thing is how each planet is created. Each planet is a child of different root object (THREE.Object3d), which contains a bodyContainer (THREE.Object3d). BodyContainer contains the planet mesh. When I add the rings mesh to body or bodycontainer it is rendered as on the picture above.
For tests ive created a 'free' sphere and rings, which ive added. to the scene and everything works as supposed for objects added directly to the scene.
Even if I add rings as a child of the sphere which is added to the scene it works fine.
Here is the code I use to generate the planet body:
export default function generateBody(radius, basic, name) {
var geometry = new THREE.SphereGeometry( radius, 24, 24 );
var material;
if(basic) {
material = new THREE.MeshBasicMaterial({color: 0xFBE200});
} else {
material = new THREE.MeshLambertMaterial({
//depthWrite: false,
//depthTest: true,
});
if(textures[name].hasOwnProperty('map')) material.map = THREE.ImageUtils.loadTexture(textures[name].map);
if(textures[name].hasOwnProperty('bump')) material.bumpMap = THREE.ImageUtils.loadTexture(textures[name].bump);
if(textures[name].hasOwnProperty('specular')) material.specularMap = THREE.ImageUtils.loadTexture(textures[name].specular);
if(textures[name].hasOwnProperty('normal')) material.normalMap = THREE.ImageUtils.loadTexture(textures[name].specular);
}
var mesh = new THREE.Mesh( geometry, material )
mesh.scale.set( params.bodyScale, params.bodyScale, params.bodyScale );
mesh.rotateX(Math.PI / 2);
mesh.renderOrder = 0;
return mesh;
}
and how i add the rings:
var circlemesh = new THREE.XRingGeometry(1.2 * (def && def.diameter || 139822000) * M_TO_AU / 2, 2 * (def && def.diameter || 139822000) * M_TO_AU / 2, 2 * 64, 5, 0, Math.PI * 2);
var circleMaterial = new THREE.MeshLambertMaterial( {
map: THREE.ImageUtils.loadTexture('../img/planet-textures/saturn/saturnringcolor.jpg'),
alphaMap: THREE.ImageUtils.loadTexture('../img/planet-textures/saturn/saturnringpattern.gif'),
//transparent: true,
side: THREE.DoubleSide,
//depthWrite: false,
//depthTest: true
});
var mesh = new THREE.Mesh(circlemesh, circleMaterial);
mesh.renderOrder = 1;
this.body.add(mesh);
furtheron:
this.bodyContainer.add(this.body)
this.root.add(this.bodyContainer)
scene.add(this.root)
For testing on a sphere added directly to the scene i use just a plain sphere geometry and the same mesh for rings used here.
var circlemesh = new THREE.XRingGeometry(1.2 * 5, 2 * 5, 2 * 64, 5, 0, Math.PI * 2);
var circleMaterial = new THREE.MeshLambertMaterial( {
map: THREE.ImageUtils.loadTexture('../img/planet-textures/saturn/saturnringcolor.jpg'),
alphaMap: THREE.ImageUtils.loadTexture('../img/planet-textures/saturn/saturnringpattern.gif'),
transparent: true,
side: THREE.DoubleSide,
//depthWrite: false,
//depthTest: true
});
var ringmesh = new THREE.Mesh(circlemesh, circleMaterial);
//ringmesh.renderOrder = 1;
//scene.add(ringmesh);
var SPHEREgeometry = new THREE.SphereGeometry( 5, 32, 32 );
var SPHEREmaterial = new THREE.MeshLambertMaterial( {color: 0xffff00} );
var sphere = new THREE.Mesh( SPHEREgeometry, SPHEREmaterial );
//sphere.renderOrder = 0;
scene.add( sphere );
sphere.add( ringmesh );
What fixed the problem was increasing the near of the camera.
No extra parameters in material weren't needed.
Here's how you can use Object3D in a parent child setup in THREE:
Object3D Parent Child Fiddle
var root = new THREE.Object3D();
var rootcontainer = new THREE.Object3D();
root.parent = rootcontainer;
mesh = new THREE.Mesh( geometry, material );
root.add( mesh );
rootcontainer.add(root);
scene.add(rootcontainer);
I am trying to understand how to add decals to a mesh using THREE.DecalGeometry
I am adding decals to the vertex on each face - face.a, I've tried using the face normal and arbitrary Vector3 to define the direction for the decal.
I cannot understand why all the decals are not being created correctly. Where am I go wrong with the direction? Is the face normal not correct?
function addObjects(){
var geometry = new THREE.BoxGeometry(200, 200, 200, 8, 8, 8);
var material = new THREE.MeshLambertMaterial({color: 0xff0000});
cube = new THREE.Mesh(geometry, material);
// addWireframeHelper(cube, 0xffffff, 1);
scene.add(cube);
THREE.ImageUtils.crossOrigin = 'Anonymous';
var texture = THREE.ImageUtils.loadTexture( 'http://i.imgur.com/RNb17q7.png' );
geometry.faces.forEach(function(face){
var index = face.a;
var vertex = geometry.vertices[index];
var direction = new THREE.Vector3(0,1,0);
addDecal(cube, vertex, direction, texture);
})
}
function addDecal(mesh, position, direction, texture){
var size = 16;
var decalGeometry = new THREE.DecalGeometry(
mesh,
position,
direction,
new THREE.Vector3(size,size,size),
new THREE.Vector3(1,1,1)
);
var decalMaterial = new THREE.MeshLambertMaterial( {
map: texture,
transparent: true,
depthTest: true,
depthWrite: false,
polygonOffset: true,
polygonOffsetFactor: -4,
});
var m = new THREE.Mesh( decalGeometry, decalMaterial );
mesh.add(m);
}
This is the hotspot 64px x 64px
This is how they are getting mapped...
Why are some decals stretched?
I have setup a JSFIDDLE
EDIT:
Using SphereBufferGeometry suggested by WestLangley, I am now happy that this solution will work for me.
Rather than using THREE.DecalGeometry, for your use case a sector of a SphereGeometry will be sufficient, and computationally less-expensive.
var geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength );
three.js r.143
I had created a shape using extrude geometry , and now with the extrude settings i need to increase the thickness i had used bevelThickness it increases the thickness along y axis , but need to increase it along x and z axis.
Here my working jsfiddle
Below is my code for extrude settings ,
var extrusionSettings = {
curveSegments:5,
steps: 10,
amount: 10,
bevelEnabled: true,
bevelThickness: 120,
bevelSize: 0,
bevelSegments: 8,
material: 0,
extrudeMaterial: 1
};
var geometry1 = new THREE.ExtrudeGeometry( shape1, extrusionSettings );
var materialLeft = new THREE.MeshLambertMaterial({
color: 0xd6d6d6,// red
transparent:true,
side: THREE.DoubleSide,
ambient: 0xea6767,
opacity:-0.5
});
var materialRight = new THREE.MeshLambertMaterial({
color: 0xcc49c3,//violet
side: THREE.DoubleSide,
ambient: 0xcc49c3
});
var materials = [ materialLeft, materialRight
];
var material = new THREE.MeshFaceMaterial( materials );
var mesh1 = new THREE.Mesh( geometry1, material );
object.add( mesh1 );
object.rotation.x = Math.PI / 2;
scene.add( object );
Below is sample image
is there any setting to increase it ? Can any one guide me ?
Finally i did the trick to fix it, What i did is just i cloned a Mesh add added the position to cloned mesh, so i got the wall nearby another inner wall, by this way i have added multiple clone with the loop, multiple inner wall nearby other created the wall thickens,
Demo : Fiddle
//outer wall mesh
var mesh1 = new THREE.Mesh( geometry1, material );
object.add( mesh1 );
var mesh_arr=new Array();
for(i=0.1;i<15;i++)
{
//cloned mesh,add position to the cloning mesh
mesh_arr[i] = mesh1.clone();
mesh_arr[i].position.set(i,i,i);
mesh_arr[i].updateMatrix();
object.add( mesh_arr[i] );
}