The following code(the most important part) can achieve the programming effect I want

``````// params.count  ： Number of points
// params.branch : Number of lines

const generateGalaxy = () => {
geometry = new THREE.BufferGeometry();
const positions = new Float32Array(params.count * 3);
const colors = new Float32Array(params.count * 3);

for (let i = 0; i < params.count; i++) {
const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch);
const distance = Math.random() * params.radius;
const current = i * 3;
// Calculate coordinates
positions[current] = Math.cos(branchAngel + distance) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel + distance) * distance;
}

``````

Running result：

My question is why distance needs to be added after branchAngel in trigonometric functions to achieve bending effect when calculating coordinates

When there is only branchAngel in the function, the line drawn is a straight line
Like this

``````    positions[current] = Math.cos(branchAngel) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel) * distance;
``````

When I add a constant,the result is still a straight line
Like this

``````    positions[current] = Math.cos(branchAngel + 3) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel + 3) * distance;
``````

When I add a random variable

``````    const r = Math.random() * 8;

positions[current] = Math.cos(branchAngel + r) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel + r) * distance;
``````

The result

I looked up a rotation matrix in advanced algebra, but I haven’t figured out the relationship between this formula and the addition of distance after branchAngel when calculating coordinates here.

So, in order to generate a curve, do we need to add a number related to distance after branchAngel? Why?

It’s kinda a coincidence in this case. Look at the value of distance - in the center it’s `0.0`, so it won’t have any effect on the trigonometric functions - but as you move further away, it’ll start increasing, causing the trigonometric functions to shift (and since this distance is uniform in all directions, it gives that synchronised shift for all branches in all directions.)

6 Likes

The algorithm uses polar coordinates (distance,angle) converted into Cartesian coordinates (the one that Three.js uses):

``````x = distance * cos(angle)
y = distance * sin(angle)
``````

Now, imagine that you draw many points and keep the distance the same, but changing gradually the angle, you will get points along a concentric circle:

Now, imagine that you draw many points and keep the angle the same, but change gradually the distance. The result will be a radial line:

The last step is to combine both: increasing the distance will move points away from the center, increasing the angle will rotate the points around the center. The overall result will be a spiral:

Yes, a change i the distance should also need a change in the angle. The exact relation defines the look-and-feel of the spiral. Try the following versions:

``````// angle is fixed, so there will be straight lines, no spirals
positions[current] = Math.cos(branchAngel + 0*distance) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel + 0*distance) * distance;
``````
``````// angle is changing slowly, the spiral will have slight curvature
positions[current] = Math.cos(branchAngel + 0.1*distance) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel + 0.1*distance) * distance;
``````
``````// angle is changing faster, the spiral will have bigger curvature
positions[current] = Math.cos(branchAngel + distance) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel + distance) * distance;
``````
``````// angle is changing in the opposite direction, the spiral will be curved in the opposite direction
positions[current] = Math.cos(branchAngel - distance) * distance;
positions[current + 1] = 0;
positions[current + 2] = Math.sin(branchAngel - distance) * distance;
``````

Final remark, sometimes it is better to think in another way, because the relation distance-angle might be confusing. Here is my suggestion. There is parameter t that defines the position on a spiral, t=0 is the origin of the spiral. In this case, we have distance = t; and angle = branchAngle + t. This is the same relation as before, but the direct connection between the distance and the angle is removed.

3 Likes