Three.js Chapter 2 section 18 Galaxy Generator

황상진·2024년 4월 8일
0

Three.js

목록 보기
6/15
post-thumbnail

Galaxy

  • Generate random position particle
  • dispose
  • spheral galaxy
    - one line
    • branch
    • randomness
  • color
    - lerp

Generate random position particle

  • Particle 객체 생성하려면 geometry와 material이 필요하다
  • geometry는 BufferGeometry생성하고
  • Material은 PointsMaterial로 생성한다.
  • 그리고 이 Particle을 random위치에 생성하려면 x,y,z 값이 random으로 필요하다
  • Float32Array를 count의 3배(xyz)로 만들고 geometry position에 적용해준다.
	/**
     * Geometry
     */
    const geometry = new THREE.BufferGeometry()

    const positions = new Float32Array(parameters.count * 3)

    for(let i = 0; i < parameters.count; i++)
    {
        const i3 = i * 3

        positions[i3    ] = (Math.random() - 0.5) * 3
        positions[i3 + 1] = (Math.random() - 0.5) * 3
        positions[i3 + 2] = (Math.random() - 0.5) * 3
    }

    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))

	/**
     * Material
     */
    const material = new THREE.PointsMaterial({
        size: parameters.size,
        sizeAttenuation: true,
        depthWrite: false,
        blending: THREE.AdditiveBlending
    })
    
    const points = new THREE.Points(geometry, material)
    scene.add(points)

dispose

  • Three.js에서 scene에서 없앤다고해서 object를 자동적으로 처리하지 않는다.
  • 그래서 수동적으로 처리해주어야한다.
geometry.dispose()
material.dispose()
scene.remove(points)

spheral galaxy

  • one line
  • branch
  • spin
  • randomness

one line

  • 우선, particle들을 한줄에 랜덤으로 세워보자
  • 간단하다 x 좌표를 random * radius로 설정한다.
for(let i = 0; i < parameters.count; i++)
{
    const i3 = i * 3

    const radius = Math.random() * parameters.radius

    positions[i3    ] = radius
    positions[i3 + 1] = 0
    positions[i3 + 2] = 0
}

branch

  • 그 다음엔 한 줄로 되어있는 particle들을 여러개의 branch로 나누어보자
  • branch로 사용할 변수를 index의 나머지 연산을 한다.
    (branch가 3이면 0,1,2로 구성된다.)
  • 이 나머지 값을 branch 개수로 나누면 0, 1/3, 2/3이 되고
  • 여기에 2 PI를 곱하면 360도에서 0도, 120도, 240도로 나뉜다.
for(let i = 0; i < parameters.count; i++)
{
    const i3 = i * 3

    const radius = Math.random() * parameters.radius
    const branchAngle = (i % parameters.branches) / parameters.branches * Math.PI * 2

    positions[i3    ] = Math.cos(branchAngle) * radius
    positions[i3 + 1] = 0
    positions[i3 + 2] = Math.sin(branchAngle) * radius
}

spin

  • 다음으로, 각가의 branch들의 particle들이 나선형을 이루도록 한다.
  • 멀어질 수록 더 spin되어야하므로 spin 값에 radius를 곱하고
  • cos, sin을 활용하여 나선형 값을 구한다.
for(let i = 0; i < parameters.count; i++)
{
    const i3 = i * 3

    const radius = Math.random() * parameters.radius
    const spinAngle = radius * parameters.spin
    const branchAngle = (i % parameters.branches) / parameters.branches * Math.PI * 2

    positions[i3    ] = Math.cos(branchAngle + spinAngle) * radius
    positions[i3 + 1] = 0
    positions[i3 + 2] = Math.sin(branchAngle + spinAngle) * radius
}

randomness

  • 마지막으로 나뉘어진 branch들의 particle들에게 무작위 변수를 부여하여 조금 흩어지도록 설정한다.
  • spin과 마찬가지로 randomness도 원점으로부터 멀어질 수록 심해져야하므로, radius * randomness로 한다.
for(let i = 0; i < parameters.count; i++)
{
    const i3 = i * 3

    const radius = Math.random() * parameters.radius

    const spinAngle = radius * parameters.spin
    const branchAngle = (i % parameters.branches) / parameters.branches * Math.PI * 2
    
    const randomX = (Math.random() - 0.5) * parameters.randomness * radius
    const randomY = (Math.random() - 0.5) * parameters.randomness * radius
    const randomZ = (Math.random() - 0.5) * parameters.randomness * radius

    positions[i3    ] = Math.cos(branchAngle + spinAngle) * radius + randomX
    positions[i3 + 1] = randomY
    positions[i3 + 2] = Math.sin(branchAngle + spinAngle) * radius + randomZ
}

  • 그러나 아직 패턴을 눈으로 볼 수 있다.
  • random 정도를 더 증가시키기 위해서 power 함수를 사용한다.
const randomX = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : - 1) * parameters.randomness * radius
const randomY = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : - 1) * parameters.randomness * radius
const randomZ = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : - 1) * parameters.randomness * radius

color

  • inner color와 outer color를 구분하여서 원점과 가장자리의 색이 점차 달라지게 하였다.
  • color를 사용하기 위해서 pointMaterial의 vertexColor를 true로 설정한다.
  • 중간에 있는 particle의 색상은 중간이 되어야하기 때문에 color.lerp 함수를 활용한다.
  • lerp 함수는 (color, value)로 구성되어있다. value는 0~1 사이 값이다.
const colorInside = new THREE.Color(parameters.insideColor)
const colorOutside = new THREE.Color(parameters.outsideColor)

const mixedColor = colorInside.clone()
mixedColor.lerp(colorOutside, radius / parameters.radius)

colors[i3    ] = mixedColor.r
colors[i3 + 1] = mixedColor.g
colors[i3 + 2] = mixedColor.b

https://18-galaxy-hwangsangjins-projects.vercel.app/

profile
Web FrontEnd Developer

0개의 댓글

관련 채용 정보