【Three.js基础学习】14.Galaxy Generator

本文介绍了在Three.js中创建星际编辑器的过程,涉及粒子生成、随机位置、PointsMaterial的使用,以及如何处理参数改变时的缓存更新,确保实时效果。作者还提到在GUI中调试时遇到的问题和解决方案,包括onChange和onFinishChange方法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

  课程知识点

        1. 实现星际编辑器

        2. 创建粒子 1000, 在随机位置

        3. 创建材质 PointsMaterial

        4. Points() 接收

        5. 放到gui 中调试  但是会发现调整size 等 属性 页面无变化

            因此有两种方法 onChange() onFinishChange()

        这个时候更改就会 将参数传到 generateGalaxy

        同样有问题 增加可以 ,因为在数值增加 不断生成新的星系

        数值缩小时候,但是没有消减

        因此要在函数外部 创建geometry,position,material 这些变量

        判断是否和之前相等 ,不相等则 dispose()  清除几何体缓存,材质缓存同时

        删除这些点 scene.remove(points)

        // 实现漩涡星系 思路

        首先将所有粒子 放到一条直线上 ,x  position[i3 + 0] = Math.random() * parameters.radius

        要实现分支  %  取余操作

        这样在循环中 就可以得到 branchAngle=0,1,2,0,1,2,0,1,2,0,1,2,

                        对应的       i    =0,1,2,3,4,5,6,7,8,9

        下面主要是数学的应用 通过更改数值 实现星系

一、代码

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as lil from 'lil-gui'
import { AdditiveBlending } from 'three'

/* 
    课程知识点
        1. 实现星际编辑器
        2. 创建粒子 1000, 在随机位置
        3. 创建材质 PointsMaterial
        4. Points() 接收
        5. 放到gui 中调试  但是会发现调整size 等 属性 页面无变化
            因此有两种方法 onChange() onFinishChange()
        这个时候更改就会 将参数传到 generateGalaxy
        同样有问题 增加可以 ,因为在数值增加 不断生成新的星系
        数值缩小时候,但是没有消减

        因此要在函数外部 创建geometry,position,material 这些变量
        判断是否和之前相等 ,不相等则 dispose()  清除几何体缓存,材质缓存同时
        删除这些点 scene.remove(points)

        // 实现漩涡星系 思路
        首先将所有粒子 放到一条直线上 ,x  position[i3 + 0] = Math.random() * parameters.radius

        要实现分支  %  取余操作
        这样在循环中 就可以得到 branchAngle=0,1,2,0,1,2,0,1,2,0,1,2,
                        对应的       i    =0,1,2,3,4,5,6,7,8,9

        下面主要是数学的应用 通过更改数值 实现星系
*/

/**
 * Base
 */
// Debug
const gui = new lil.GUI()

// Canvas
const canvas = document.querySelector('canvas.webgl')

// Scene
const scene = new THREE.Scene()

/* 
* Galaxy 星系 Generator 编辑器
*/
const parameters = {}
parameters.count = 100000
parameters.size = 0.01
parameters.color = '#ffffff'
parameters.radius = 5 // 半径
parameters.branches = 3 // 分支
parameters.spin = 1 // 旋转
parameters.randomness = 0.2 // 随机值
parameters.randomnessPower = 3 // 
parameters.insideColor = '#ff6030' // 
parameters.outsideColor = '#1b3984' 

let geometry = null
let points = null
let material = null
const generateGalaxy = () =>{
    /* 
    * Destroy old galaxy
    */
   if(points !== null){
    geometry.dispose()
    material.dispose()
    scene.remove(points)
   }

    // Geometry
    geometry = new THREE.BufferGeometry()
    // 创建粒子 位置参数
    const position = new Float32Array(parameters.count * 3)
    const colors = new Float32Array(parameters.count * 3)

    const colorInside = new THREE.Color(parameters.insideColor)
    const colorOutside = new THREE.Color(parameters.outsideColor)


    // 设置随机位置
    for(let i=0;i<parameters.count;i++){
        const i3 = i * 3
        // position
        const radius = Math.random() * parameters.radius
        const sponAngle = radius * parameters.spin
        const branchAngle = (i % parameters.branches) / parameters.branches * Math.PI * 2

        const randomX = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : -1)
        const randomY = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : -1)
        const randomZ = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : -1)

        position[i3 + 0] = Math.cos(branchAngle + sponAngle) * radius + randomX
        position[i3 + 1] = randomY
        position[i3 + 2] = Math.sin(branchAngle + sponAngle) * radius + randomZ


        // position[i3 + 0] = (Math.random() - 0.5) * 10  // x位置
        // position[i3 + 1] = (Math.random() - 0.5) * 10  // y
        // position[i3 + 2] = (Math.random() - 0.5) * 10  // z

        // color
        const mixedColor = colorInside.clone()
        mixedColor.lerp(colorOutside,radius/parameters.radius)
        colors[i3 + 0] = mixedColor.r
        colors[i3 + 1] = mixedColor.g
        colors[i3 + 2] = mixedColor.b
    }
    geometry.setAttribute(
        'position',
        new THREE.BufferAttribute(position,3)
    )
    geometry.setAttribute(
        'color',
        new THREE.BufferAttribute(colors,3)
    )

    // Material
    material = new THREE.PointsMaterial({
        // color:parameters.color,
        size:parameters.size,
        sizeAttenuation:true, // 衰减
        depthWrite:false, // 深度缓冲区
        blending: THREE.AdditiveBlending,
        vertexColors:true
    })
    // material.vertexColors = true
    
    /* 
    *   Points
    */
    points = new THREE.Points(
        geometry,
        material
    )
    scene.add(points)
}
gui.add(parameters, 'count').min(100).max(100000).step(100).onFinishChange(generateGalaxy)
gui.add(parameters, 'size').min(0.001).max(1).step(0.001).onFinishChange(generateGalaxy)
gui.add(parameters, 'radius').min(0.01).max(20).step(0.01).onFinishChange(generateGalaxy)
gui.add(parameters, 'branches').min(2).max(20).step(1).onFinishChange(generateGalaxy)
gui.add(parameters, 'spin').min(-5).max(5).step(0.001).onFinishChange(generateGalaxy)
gui.add(parameters, 'randomness').min(0).max(2).step(0.001).onFinishChange(generateGalaxy)
gui.add(parameters, 'randomnessPower').min(1).max(10).step(0.001).onFinishChange(generateGalaxy)
gui.addColor(parameters, 'insideColor').onFinishChange(generateGalaxy)
gui.addColor(parameters, 'outsideColor').onFinishChange(generateGalaxy)

generateGalaxy()

/**
 * Sizes
 */
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}

window.addEventListener('resize', () =>
{
    // Update sizes
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight

    // Update camera
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()

    // Update renderer
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})

/**
 * Camera
 */
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.x = 3
camera.position.y = 3
camera.position.z = 3
scene.add(camera)

// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
    canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

/**
 * Animate
 */
const clock = new THREE.Clock()

const tick = () =>
{
    const elapsedTime = clock.getElapsedTime()

    // Update controls
    controls.update()

    // Render
    renderer.render(scene, camera)

    // Call tick again on the next frame
    window.requestAnimationFrame(tick)
}

tick()

二、知识点

1.思路图

2.效果


总结

五一前看的,全被自己吃进肚子里了,想想怎么实现的一头雾水!还是要看之前代码,很烦...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值