I am trying to use Points object in threejs. I am trying to display a point, but it is not showing up. Browser does not give any error. Let me know what needs to be done. Thanks
let pointGeometry:any = new BufferGeometry();
let positionAttribute = new BufferAttribute( new Float32Array([10,5,10]), 10 );
pointGeometry.setAttribute( 'position', positionAttribute );
pointGeometry.attributes.position.needsUpdate = true;
pointGeometry.setDrawRange(0,10);
let pointMaterial = new PointsMaterial( { color: 0x03F9E7, size: 10 } );
this.point = new Points( pointGeometry, pointMaterial );
this.point.name = 'point';
this.point.scale.copy( new Vector3(10,10,10) );
this.scene.add( this.point );
The itemSize of BufferAttribute should be 3.
let positionAttribute = new BufferAttribute( new Float32Array([10,5,10]), 3 );
pointGeometry.setAttribute( 'position', positionAttribute );
itemSize -- the number of values of the array that should be associated with a particular vertex. For instance, if this attribute is storing a 3-component vector (such as a position, normal, or color), then itemSize should be 3.
[Docs] BufferAttribute
Another reason may be that the camera looks to the wrong position. If you set a scale of 10 the final position of the point will be at [100,50,100].
Related
I have a basic three.js game working and I'd like to add particles. I've been searching online, including multiple questions here, and the closest I've come to getting a 'particle system' working is using a THREE.BufferGeometry, a THREE.BufferAttribute and a THREE.Points mesh. I set it up like this:
const particleMaterial = new THREE.PointsMaterial( { size: 10, map: particleTexture, blending: THREE.AdditiveBlending, transparent: true } );
const particlesGeometry = new THREE.BufferGeometry;
const particlesCount = 300;
const posArray = new Float32Array(particlesCount * 3);
for (let i = 0; i < particlesCount; i++) {
posArray[i] = Math.random() * 10;
}
const particleBufferAttribute = new THREE.BufferAttribute(posArray, 3);
particlesGeometry.setAttribute( 'position', particleBufferAttribute );
const particlesMesh = new THREE.Points(particlesGeometry, particleMaterial);
particlesMesh.counter = 0;
scene.add(particlesMesh);
This part works and displays the particles fine, at their initial positions, but of course I'd like to move them.
I have tried all manner of things, in my 'animate' function, but I am not happening upon the right combination. I'd like to move particles, ideally one vertex per frame.
The current thing I'm doing in the animate function - which does not work! - is this:
particleBufferAttribute.setXYZ( particlesMesh.counter, objects[0].position.x, objects[0].position.y, objects[0].position.z );
particlesGeometry.setAttribute( 'position', particleBufferAttribute );
//posArray[particlesMesh.counter] = objects[0].position;
particlesMesh.counter ++;
if (particlesMesh.counter > particlesCount) {
particlesMesh.counter = 0;
}
If anyone has any pointers about how to move Points mesh vertices, that would be great.
Alternatively, if this is not at all the right approach, please let me know.
I did find Stemkoski's ShaderParticleEngine, but I could not find any information about how to make it work (the docs are very minimal and do not seem to include examples).
You don't need to re-set the attribute, but you do need to tell the renderer that the attribute has changed.
particleBufferAttribute.setXYZ( particlesMesh.counter, objects[0].position.x, objects[0].position.y, objects[0].position.z );
particleBufferAttribute.needsUpdate = true; // This is the kicker!
By setting needsUpdate to true, the renderer knows to re-upload that attribute to the GPU.
This might not be concern for you, but just know that moving particles in this way is expensive, because you re-upload the position attribute every single frame, which includes all the position data for every particle you aren't moving.
I have model far away from the origin, and I want a directional light to hit the model like sunlight would do.
I set a position and a target for my DirectionalLight:
export const dirLight = getDirectional();
function getDirectional() {
const dirLight = new DirectionalLight( 0xffffff, 1 );
dirLight.position.set( 585000 + 10000, 6135000 + 10000, -500 + 5000);
return dirLight;
};
const helper = new THREE.DirectionalLightHelper( dirLight, 1000 );
let t = new THREE.Object3D();
t.translateX(585000);
t.translateY(6135000);
t.translateZ(1000);
dirLight.target = t;
scene.add(dirLight);
scene.add(dirLight.target);
scene.add(t);
helper.update();
scene.add( helper );
I would expect the light direction now to be parallel to vector between light position and light target, but apparently the light direction is still towards the origin of the scene. What am I doing wrong ?
A running example can be seen here
The documentation states that the target needs to be added to the scene so that the world coordinates are calculated. However, that does not seem to work.
So, instead I tried manually updating the world coordinates, and that worked. Probably that will only work with a static target.
In your case that would be adding
dirLight.target.updateMatrixWorld();
Considering a scene and 3 BoxBufferGeometries, I don't want to re-render the scene (drawObjects is called once, the 'first' time), but rather update it (updateScene is called on user action for example), the following code sucessfully updates the color and texture material attributes for all the objects of the scene, but only seems to affect one of the 3 objects when it comes to mesh.geometry transformation (one becomes as sphere, the 2 other remains squares), why? (live example)
drawObjects = (options) ->
map = (new (THREE.TextureLoader)).load(options.texture)
map.wrapS = map.wrapT = THREE.RepeatWrapping
map.anisotropy = 16
material = new (THREE.MeshToonMaterial)(
color: options.color
map: map
transparent: true
side: THREE.DoubleSide)
geometry = new THREE.BoxBufferGeometry( 20, 20, 20 )
i = 0
while i < 3
object = new (THREE.Mesh)(geometry, material, (color: Math.random() * 0xffffff))
object.position.x = Math.random() * 800 - 400
object.position.y = Math.random() * 800 - 400
object.position.z = Math.random() * 800 - 400
object.setGeometry = ->
geometry = new THREE.SphereGeometry(20)
object.geometry = geometry
return
object.setTexture = (texture) ->
object.material.map = new THREE.TextureLoader().load( texture )
return
object.setColor = (color) ->
object.material.color = new THREE.Color(color)
return
scene.add object
i++
updateScene = (options) ->
#scene.traverse (object) ->
if object.isMesh == true
object.setColor(options.color)
object.setTexture(options.texture)
object.setGeometry()
return
I tried few other approches aswell, the first was about updating vertices (like indicated here) but it doesn't work since BoxGeometry do no have vertices. Then I tied to add a few options such as, but without success.
# object.geometry.dynamic = true
# object.geometry.buffersNeedUpdate = true
# object.updateMatrix()
The second one was using object dispose basically making a clone of the original, like advised here dispose the original mesh and replace it with its clone such as but it didn't work in my case since I have functions attached to this object I'll need to re-use. Maybe I did it wrong:
object.geometry.dispose();
object.geometry = geometry.clone();
I bet there is a way to achieve this kind mesh.geometry transformation and apply it to every object while traversing the scene, but can't find how.
Kind regards
Ended up doing it with a function out of the object itself:
setGeometries = (geometry) ->
#scene.traverse (object) ->
if object
object.geometry = geometry
object.geometry.buffersNeedUpdate = true
return
return
return
Where geometry is something like new THREE.[Primitive]BuffferGeometry. Works for me.
I'm trying to inject hole to the shape that is already added to the scene, but some thing going wrong...
so in details: the shape
var well,
vertices = [],
wellShape,
wellMaterial = new THREE.MeshLambertMaterial({color: this.params.wellsColor});
vertices.push(new THREE.Vector2(0,3000));
vertices.push(new THREE.Vector2(4000,3000));
vertices.push(new THREE.Vector2(4000,0));
vertices.push(new THREE.Vector2(0,0));
wellShape = new THREE.Shape(vertices);
well = new THREE.Mesh( new THREE.ShapeGeometry(wellShape), wellMaterial);
scene.add(well);
well.geometry.dynamic = true;
var hole = [
new THREE.Vector3(300,300,0),
new THREE.Vector3(1000,300,0),
new THREE.Vector3(1000,1000,0),
new THREE.Vector3(300,1000,0)
];
well.geometry.vertices = well.geometry.vertices.concat(hole);
well.geometry.faces = [];
var triangles = THREE.Shape.Utils.triangulateShape ( well.geometry.vertices, hole );
for( var i = 0; i < triangles.length; i++ ){
well.geometry.faces.push( new THREE.Face3( triangles[i][0], triangles[i][1], triangles[i][2] ));
well.geometry.faceVertexUvs[ 0 ][i] = THREE.ExtrudeGeometry.WorldUVGenerator.generateTopUV(well.geometry, triangles[i][0], triangles[i][1], triangles[i][2]);
}
but as result i got something strange: in console output "Infinite Loop! Holes left:4, Probably Hole outside Shape!" and on desktop i got https://yadi.sk/i/WHRzH7c2jnaRm
could someone tell me what is wrong in my code?
after few days play around I found what is wrong:
1. THREE.Shape.Utils.triangulateShape expect vertices and holes to be parts of same shape.
2. hole should be not the array of points but array of path.
3. vertices should be concated after triangulation.
so correct result is:
....
var holePoints = [
new THREE.Vector3(300,300,0),
new THREE.Vector3(1000,300,0),
new THREE.Vector3(1000,1000,0),
new THREE.Vector3(300,1000,0)
],
hole = new THREE.Path();
hole.fromPoints(holePoints);
var shape = new THREE.Shape(well.geometry.vertices);
shape.holes = [hole];
var points = shape.extractPoints();
well.geometry.faces = [];
var triangles = THREE.Shape.Utils.triangulateShape ( points.vertices, points.holes );
....
Hope someone will find this info helpful.
I have Vector3 in position.
I have scene childs:
planet = new THREE.Object3D();
city= new THREE.Object3D();
street= new THREE.Object3D();
scene.add(planet);
planet.add(city);
city.add(street);
how can i get correct world position of vector in each object(planet,city and street individually), with respect to position,scale and rotation of each object..
i try planet.worldToLocal(new THREE.Vector3( vector.x,vector.y,vector.z ) but it seem to work only from global to child object, not for recalculating from planet to city.
example:
planet.position.set(10,0,0);
city.position.set(10,0,0);
street.position.set(10,0,0);
if myVector is new THREE.Vector3(0,10,0), i need to get the same position in street object, that should be (30,10,0) how to get it by THREE functions??
You can get the world position of an object like so:
var position = object.getWorldPosition(); // creates a new THREE.Vector3()
or
var position = new THREE.Vector3();
object.getWorldPosition( position ); // reuses your existing THREE.Vector3()
Note: If you have modified the position/rotation/scale of any of the objects in the hierarchy since the last call to render(), then you will have to force an update to the world matrices by calling scene.updateMatrixWorld(). The renderer calls this for you, otherwise.
three.js r.71
I guess you want to use Vector3.add in combination with getWorldPosition():
planet.position.set(10,0,0);
city.position.set(10,0,0);
street.position.set(10,0,0);
myVector = new THREE.Vector3( 0, 10, 0 );
myVector.add( street.getWorldPosition() );
console.log( myVector ); // 30, 10, 0