three.js How to render a simple white dot/point/pixel - three.js

I'm using THREE.WebGLRenderer and I would like to draw a few same-sized white dots at specific positions in 3D space.
Should I use sprites, calculate the 2D screen coordinates and use SpriteMaterial.useScreenCoordinate?
Should I simply recalculate the size of the sprites using the distance of them to the camera?
Can I use SpriteMaterial.scaleByViewport or SpriteMaterial.sizeAttenuation? Is there any documentation for this?
Is there something like GL_POINTS? It would be nice to just define 1 vertex and get a colored pixel at that position. Should I experiment with PointCloud?
Thanks for any hints!
Edit: All points should have the same size on the screen.

Using .sizeAttenuation and a single-vertex PointCloud works, but it feels a bit… overengineered:
var dotGeometry = new THREE.Geometry();
dotGeometry.vertices.push(new THREE.Vector3( 0, 0, 0));
var dotMaterial = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add( dot );

For r125
The excerpt is taken from threejs official example. After some modification here how made it to work.
var dotGeometry = new BufferGeometry();
dotGeometry.setAttribute( 'position', new Float32BufferAttribute( [0,0,0], 3 ) );
var dotMaterial = new PointsMaterial( { size: 0.1, color: 0x00ff00 } );
var dot = new Points( dotGeometry, dotMaterial );
scene.add( dot );

Yet another update: The interface for attribute has changed somewhat:
For r139
const dotGeometry = new THREE.BufferGeometry();
dotGeometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array([0,0,0]), 3));
const dotMaterial = new THREE.PointsMaterial({ size: 0.1, color: 0xff0000 });
const dot = new THREE.Points(dotGeometry, dotMaterial);
scene.add(dot);

Related

Get center position of hole in ExtrudeGeometry

I trying to get position of hole in extruded geometry. I created plane and made hole in her geometry. I want get x,y,z coordinates in center of hole. Is there some methods to get it?
Here demo: https://codepen.io/DYDOI-NSK/pen/XWqJzXG?editors=0011
Here code:
I created shape of plane
let shape = new THREE.Shape();
let width = 30;
let height = 30;
shape.moveTo(-width, height);
shape.lineTo(-width, -height);
shape.lineTo(width, -height);
shape.lineTo(width, height);
shape.lineTo(-width, height);
I created hole path and add it to shape
let hole = new THREE.Path();
hole.absarc(20, 10, 10, 0, Math.PI * 2, false) //first two argumets is x,y coord of hole
shape.holes.push(hole)
I created plane add add extruded geometry
let geometry = new THREE.PlaneGeometry( 30, 30);
let material = new THREE.MeshBasicMaterial( {color: new THREE.Color('#cea6a6'), side: THREE.DoubleSide} );
let mesh = new THREE.Mesh( geometry, material );
let newGeometry = new THREE.ExtrudeGeometry(shape, settings);
mesh.geometry.dispose()
mesh.geometry = newGeometry;
After 4 days I understand how can do it. I simple created line from mesh center to hole config position. Applied quaternion to line and got x,y,z cords of hole.
Maybe there are more optimized solutions, but it only that I could create. I will be glad if someone share more optimized solution :D
Here codepen: https://codepen.io/DYDOI-NSK/pen/XWqJzXG?editors=0011
Here code:
/*
* findCoords - function to find hole coords in 3d space
* data - parameter that require x,y of hole
*/
let findCoords = function (data) {
let vertexes = [];
//Set coords where you was created hole
let hole = new THREE.Vector3(
data.x,
data.y,
0
);
vertexes.push( new THREE.Vector3() );
vertexes.push(hole)
//Create line
const material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
const geometry = new THREE.BufferGeometry().setFromPoints( vertexes );
const line = new THREE.Line( geometry, material );
scene.add(line)
//Set line to center of mesh
line.position.copy(mesh.position)
//Rotate line like rotated mesh
line.applyQuaternion(mesh.quaternion)
//Extract hole coords from second vertex of line
let holeCoord = new THREE.Vector3()
const positionAttribute = line.geometry.getAttribute( 'position' );
holeCoord.fromBufferAttribute( positionAttribute, 1);
return holeCoord;
}

Layer multiple materials onto SphereGeometry in three.js

I'm attempting to create a sphere in three.js with a base material and a transparent png material over the top. I found this answer helpful in understanding how to load multiple materials. However when I try to apply this to SphereGeometry rather than BoxGeometry as in the example, only the second material is visible, with no transparency.
http://jsfiddle.net/oyamg8n3/1/
// geometry
var geometry = new THREE.BoxBufferGeometry( 10, 10, 10 );
geometry.clearGroups();
geometry.addGroup( 0, Infinity, 0 );
geometry.addGroup( 0, Infinity, 1 );
geometry.addGroup( 0, Infinity, 2 );
geometry.addGroup( 0, Infinity, 3 );
// textures
var loader = new THREE.TextureLoader();
var splodge = loader.load( 'https://threejs.org/examples/textures/decal/decal-diffuse.png', render );
var cat = loader.load('https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1950&q=80.jpeg', render)
// materials
var catMat = new THREE.MeshPhongMaterial( {
map: cat,
} );
var splodgeMat = new THREE.MeshPhongMaterial( {
map: splodge,
alphaTest: 0.5,
} );
var materials = [ catMat, splodgeMat ];
// mesh
mesh = new THREE.Mesh( geometry, materials );
scene.add( mesh );
Can I use these same principles for
var geometry = new THREE.SphereGeometry( 5, 20, 20 );
It does work if you use SphereBufferGeometry and not SphereGeometry. Notice that both classes have a different super class. You want to work with the BufferGeometry version.
Demo: http://jsfiddle.net/r6j8otz9/
three R105

Threejs How to assign different color for top face of a cylinder?

I would like to create a simple cylinder and color its top face differently. I can create the cylinder and assign a material. My recent code:
var zylinder = {};
zylinder._width = 1;
zylinder._height = 1;
zylinder._color = 0xFF666e;
var cyl_material = new THREE.MeshLambertMaterial({
color: zylinder._color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.9,
// map: THREE.ImageUtils.loadTexture( "texture-stone-wall.jpg" ),
});
var cylGeometry = new THREE.CylinderGeometry(zylinder._width, zylinder._width, zylinder._height, 20, 1, false);
var cylinder = new THREE.Mesh(cylGeometry, cyl_material);
cylinder.position.y = zylinder._height/2+0.001;
scene.add(cylinder);
Using console.log( cylGeometry.faces ); I see that there are about 80 objects.
I tried changing the face colors by:
cylGeometry.faces[0].color.setHex( 0xffffff );
cylGeometry.faces[1].color.setHex( 0xffffff );
// ...
but it does not work, maybe due to THREE.MeshLambertMaterial.
Recent version (includes shading): Zylinder: Volumen berechnen online - Formel interaktiv
How can I assign a different color for the top face? Do I need to use another material?
You can use another material for the end caps, but you don't have to.
Instead, you can use this pattern: For each end cap face, set
geometry.faces[ faceIndex ].color.set( 0x00ff00 );
...
And then set
material.vertexColors = THREE.FaceColors;
You can indentify the end cap faces by their face.normal, which is parallel to the y-axis.
If you want to use a separate material for the end caps, you need to set for each end cap face, face.materialIndex = 1 ( the default is 0 ), and then create your mesh using this pattern:
var materials = [ new THREE.MeshBasicMaterial( { color: 0xff0000 } ), new THREE.MeshBasicMaterial( { color: 0x00ff00 } ) ];
var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
three.js r.68

Check if point is inside a custom mesh geometry

What would be the easiest way to check if a point is inside a custom (irregular) mesh geometry?
If your mesh is close-up. You can use the THREE.js built-in ray-caster. Sample code is as
const point = new THREE.Vector3(2,2,2) // Your point
const geometry = new THREE.BoxBufferGeometry( 5, 5, 5 )
const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } )
const mesh = new THREE.Mesh( geometry, material )
const raycaster = new THREE.Raycaster()
raycaster.set(point, new THREE.Vector3(1,1,1))
const intersects = raycaster.intersectObject(mesh)
if( intersects.length %2 === 1) { // Points is in objet
console.log(`Point is in object`)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script>
Just raycast once from the point to any direction, then check the intersects num, if is odd, the point is in the geometry, here is the demo
This is a computational geometry problem. You can look at Finding if point is inside geometry. Since your geometry is irregular the problem is much harder.
But if precision is not too important you can check if the point is inside the bounding box of the geometry.
Its better to check it using the dot product of ray direction and face normal
tested on three.js (r103)
const point = new THREE.Vector3(2, 2, 2) // Your point
const direction = new THREE.Vector3(1, 1, 1);
const geometry = new THREE.BoxGeometry(5, 5, 5)
const material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material)
const raycaster = new THREE.Raycaster()
raycaster.set(point, direction)
const intersects = raycaster.intersectObject(mesh);
if (intersects.length && direction.dot(intersects[0].face.normal) > 0) {
console.log(`Point is in object`);
} else {
console.log(`Point is out of object`);
}
In rare cases you can get even number of interections with point located inside the mesh
(try point = new THREE.Vector3(0, 0, 0), that should give 4 intersections)

Visualizing Raycaster

I am trying to detect an intersection by using a raycast. My current problem is that I am not sure about my raycast aiming into the desired direction. So my general question is: Is there a way to make a raycast visible? And if so: How is it done? This would help me a lot.
Michael
Here is another method to show your raycsters:
scene.add(new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 300, 0xff0000) );
Why dont you draw a line from your origin to the direction of the ray.
To be more specific (using r83):
// Draw a line from pointA in the given direction at distance 100
var pointA = new THREE.Vector3( 0, 0, 0 );
var direction = new THREE.Vector3( 10, 0, 0 );
direction.normalize();
var distance = 100; // at what distance to determine pointB
var pointB = new THREE.Vector3();
pointB.addVectors ( pointA, direction.multiplyScalar( distance ) );
var geometry = new THREE.Geometry();
geometry.vertices.push( pointA );
geometry.vertices.push( pointB );
var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
var line = new THREE.Line( geometry, material );
scene.add( line );
Codepen at: https://codepen.io/anon/pen/evNqGy

Resources