Hi everybody,
I want to create a circle that is made up of individual particles which are randomly positioned on the edge.
Most of the particles are close to the edge of the circle but some are spread more far away.
Just like this image.
I’ve created a CircleGeometry
with made up of individual points using the PointsMaterial
but they’re all located on the circles segments obviously. I don’t know how to position them rather roughly on the circle.
Also I’m not sure if I should rather use the SphereGeometry than the Circle but I guess the Circle is more correct since I’m only interested in the outer edge and I dont want points everywhere on a sphere.
It would be nice if someone could give some recommendations on how to archive a result like on the image.
Thanks a lot,
Alex
hofk
September 22, 2021, 3:55pm
2
I took the example @looeee How move all points to sphere - #2 by looeee ( see also discourse.threejs.hofk.de ) and changed it a bit. It’s not quite what you want yet. You still have to add a random distribution function for the distance from the center of the circle.
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/how-move-all-points-to-sphere/1836/2 -->
<!-- https://codepen.io/looeee/pen/LQLQRd -->
<head>
<title> Points to Sphere </title>
<meta charset="utf-8" />
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> </body>
<script src="../js/three.min.89.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author looeee --- changed by hofk
let camera, renderer, scene;
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 100, 0, 100 );
const controls = new THREE.OrbitControls( camera );
}
const v = new THREE.Vector3();
function randomPointInSphere( radius ) {
const x = THREE.Math.randFloat( -1, 1 );
const y = THREE.Math.randFloat( -1, 1 );
//const z = THREE.Math.randFloat( -1, 1 );
const normalizationFactor = 1 / Math.sqrt( x * x + y * y );
v.x = x * normalizationFactor * THREE.Math.randFloat( 0.5 * radius, 1.2 * radius );
v.y = y * normalizationFactor * THREE.Math.randFloat( 0.5 * radius, 1.2 * radius );
v.z = 0; // z * normalizationFactor * radius;
return v;
}
function initPoints() {
const geometry = new THREE.BufferGeometry();
var positions = [];
for (var i = 0; i < 50000; i ++ ) {
var vertex = randomPointInSphere( 50 );
positions.push( vertex.x, vertex.y, 0 );
}
geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
material = new THREE.PointsMaterial( { color: 0xff00ff, size: 0.1 } );
particles = new THREE.Points(geometry, material);
scene.add( particles );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
window.addEventListener( 'resize', onWindowResize );
init();
initPoints();
animate();
</script>
</html>
3 Likes
hofk
September 22, 2021, 4:32pm
3
As a module version for current three.js
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/create-circle-with-fuzzy-edge-made-of-individual-random-particles/30150 -->
<!-- see also
https://discourse.threejs.org/t/how-move-all-points-to-sphere/1836/2
and
https://codepen.io/looeee/pen/LQLQRd
-->
<head>
<title> PointsToCircleRandom </title>
<meta charset="utf-8" />
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> </body>
<script type="module">
// @author looeee - changed by hofk
import * as THREE from "../jsm/three.module.132.js";
import { OrbitControls } from "../jsm/OrbitControls.132.js";
let camera, renderer, scene;
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 1, -1, 3 );
const controls = new OrbitControls( camera, renderer.domElement );
}
const v = new THREE.Vector2();
function randomPointCircle( radius ) {
const x = THREE.Math.randFloat( -1, 1 );
const y = THREE.Math.randFloat( -1, 1 );
const r = THREE.Math.randFloat( 0.5 * radius, 1.2 * radius );
const normalizationFactor = 1 / Math.sqrt( x * x + y * y );
v.x = x * normalizationFactor * r;
v.y = y * normalizationFactor * r;
return v;
}
function initPoints() {
const geometry = new THREE.BufferGeometry();
var positions = [];
for (var i = 0; i < 50000; i ++ ) {
var vertex = randomPointCircle( 1 );
positions.push( vertex.x, vertex.y, 0 );
}
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
const material = new THREE.PointsMaterial( { color: 0xff00ff, size: 0.001 } );
const particles = new THREE.Points(geometry, material);
scene.add( particles );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
window.addEventListener( 'resize', onWindowResize );
init();
initPoints();
animate();
</script>
</html>
1 Like
One more option: Edit fiddle - JSFiddle - Code Playground
And the thing you need is:
let pts = [];
let POINT_COUNT = 10000;
let mainR = 5;
let outerLimit = 1;
let innerLimit = 5;
for(let i = 0; i < POINT_COUNT; i++){
let inout = (Math.random() - 0.5) * 2;
let lim = (inout >= 0 ? outerLimit : innerLimit);
let rand = mainR + Math.pow(Math.random(), 3) * lim * inout;
pts.push(
new THREE.Vector3().setFromCylindricalCoords(
rand,
Math.PI * 2 * Math.random(),
0
)
)
}
let g = new THREE.BufferGeometry().setFromPoints(pts);
let m = new THREE.PointsMaterial({size: 0.05, color: "aqua"});
let p = new THREE.Points(g, m);
scene.add(p);
6 Likes
hofk
September 22, 2021, 6:32pm
5
This function
function randomPointCircle( radius ) {
const r = THREE.Math.randFloat( 0.5 * radius, 1.2 * radius );
const phi = THREE.Math.randFloat( 0, Math.PI * 2 );
v.x = r * Math.cos( phi );
v.y = r * Math.sin( phi );
return v;
}
gives
3 Likes
hofk
September 22, 2021, 7:24pm
6
Another strongly modified variant.
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/create-circle-with-fuzzy-edge-made-of-individual-random-particles/30150/5 -->
<!-- see also
https://discourse.threejs.org/t/how-move-all-points-to-sphere/1836/2
and
https://codepen.io/looeee/pen/LQLQRd
-->
<head>
<title> PointsToCircleRandom </title>
<meta charset="utf-8" />
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> </body>
<script type="module">
// @author looeee - strongly changed by hofk
import * as THREE from "../jsm/three.module.132.js";
import { OrbitControls } from "../jsm/OrbitControls.132.js";
let camera, renderer, scene;
const v = new THREE.Vector2();
let r;
window.addEventListener( 'resize', onWindowResize );
init();
randomPoints();
animate();
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 1, -1, 3 );
const controls = new OrbitControls( camera, renderer.domElement );
}
function randomPoints() {
const geometry = new THREE.BufferGeometry();
var positions = [];
for ( let i = 0; i < 50000; i ++ ) {
const phi = Math.random( ) * Math.PI * 2;
r = Math.pow( Math.random( ), 1 / 6 ) + 0.2;
v.x = r * Math.cos( phi );
v.y = r * Math.sin( phi );
positions.push( v.x, v.y, 0 );
}
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
const material = new THREE.PointsMaterial( { color: 0xffff34, size: 0.001 } );
const particles = new THREE.Points(geometry, material);
scene.add( particles );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
</script>
</html>
UPDATE: There you can experiment nicely.
Of course, you can also derive the required functions theoretically.
Try it out.
In the Collection of examples from discourse.threejs.org
2021 >>> PointsToCircleRandom
function randomPoints() {
const geometry = new THREE.BufferGeometry();
var positions = [];
for ( let i = 0; i < 3000; i ++ ) {
const phi = Math.random( ) * Math.PI * 2;
const rnd = Math.random( )
r = 0.2 + ( rnd < 0.6 ? Math.pow( Math.random( ), 1 / 6 ) : Math.pow( ( 3 + 5 * Math.random( ) ) * Math.random( ), 1 / 6 ) );
v.x = r * Math.cos( phi );
v.y = r * Math.sin( phi );
positions.push( v.x, v.y, 0 );
}
3 Likes
hofk
September 23, 2021, 6:19pm
7
If one superimposes several rings of points, it is even easier to create different structures.
For this purpose I have changed the code again.
See live PointsToCircleRandomMultiple
const distributionA = n => Math.pow( n, 1 / 4 );
const distributionB = n => 0.2 * Math.pow( n, 1 / 2 );
const distributionC = n => 0.6 * Math.pow( Math.random( ), 2 );
function randomPoints() {
// count, rMin, distribution
pushpos( 1200, -0.1, distributionA );
pushpos( 2000, 0.8, distributionB );
pushpos( 300, 1.05, distributionC );
const geometry = new THREE.BufferGeometry( );
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
const material = new THREE.PointsMaterial( { color: 0xffff34, size: 0.001 } );
const particles = new THREE.Points(geometry, material);
scene.add( particles );
}
function pushpos( count, rMin, distribution ) {
for ( let i = 0; i < count; i ++ ) {
const phi = Math.random( ) * Math.PI * 2;
const rnd = Math.random( )
r = rMin + distribution( rnd );
v.x = r * Math.cos( phi );
v.y = r * Math.sin( phi );
positions.push( v.x, v.y, 0 );
}
}
A different distribution
UPDATE
When transferring the example ParticleVhangeByDistance(Shader) to the collection, it occurred to me that this method would be appropriate here. Otherwise, the intensity of the point cloud is much too intense at greater distance.
drcmda
September 24, 2021, 7:55am
8
and to get that fuzzy look you can also add a tiny bit of DOF
vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
gl_Position = projectionMatrix * mvPosition;
vDistance = abs(uFocus - -mvPosition.z);
gl_PointSize = (step(1.0 - (1.0 / uFov), position.x)) * vDistance * uBlur;
in the video it’s not very subtle, but dialing it down should get something close to that first image. anyway, that was the demo: GPGPU Curl-noise + DOF - CodeSandbox
1 Like
Wow, thank you very much that is exactly what I was looking for. Especially since the individual particles are also moving.
hofk
December 21, 2022, 2:18pm
10
What works with the circle, works a bit more complicated with the sphere.
You have to distribute the angles evenly and then multiply the unit sphere by rand.
try SphereWithRandomPointsl
see also GitHub - hofk/threejsResources: Resources for three.js
function PointsSphere( n, dri, r, dro ) {
// n: points count, dri: inner difference , r: radius main, dro: outer difference
const pts = [];
for( let i = 0; i < n ; i++){
const inout = ( Math.random( ) - 0.5 ) * 2;
const lim = ( inout >= 0 ? dro : dri );
const rand = r + Math.pow( Math.random( ), 3 ) * lim * inout;
const θ = Math.PI * 2 * Math.random( );
const φ = Math.acos( 2 * Math.random( ) - 1 );
const ps = new THREE.Vector3( Math.cos( θ ) * Math.sin( φ ), Math.sin( θ ) * Math.sin( φ ), Math.cos( φ ) );
pts.push( ps.multiplyScalar( rand ) );
}
const geometry = new THREE.BufferGeometry( ).setFromPoints( pts );
return geometry;
}
1 Like