<template>
    <canvas class="webgl"></canvas>
</template>


<script setup>
import {onMounted} from 'vue'

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import Stats from 'three/examples/jsm/libs/stats.module.js'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'

let canvas
let scene, camera, renderer
let stats, controls, gui

//像素比
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}

//初始化操作
let init = () => {
    // 获取dom元素
    canvas = document.querySelector('.webgl')

    // 场景初始化
    scene = new THREE.Scene()

    // 添加环境光
    const light = new THREE.AmbientLight(0xdeedff, 1.5)
    scene.add(light)

    let pointLight = new THREE.PointLight(0xffffff)
    pointLight.position.set(0, 2, 0)
    scene.add(pointLight)

    pointLight = new THREE.PointLight(0xffffff)
    pointLight.position.set(2, 0, 0)
    scene.add(pointLight)

    pointLight = new THREE.PointLight(0xffffff)
    pointLight.position.set(0, 0, -2)
    scene.add(pointLight)


    //相机
    camera = new THREE.PerspectiveCamera(45, sizes.width / sizes.height, 1, 1000)
    camera.position.set(6, 5, 6)
    camera.lookAt(scene.position)


    //渲染器
    renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true })
    renderer.setSize(sizes.width, sizes.height)
    // renderer.setClearColor('lightsalmon', 0.5)
    renderer.setPixelRatio(window.devicePixelRatio)




    //控制器
    controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    controls.autoRotate = true
    controls.autoRotateSpeed = 10

    //帧率检测
    stats = new Stats()
    document.body.appendChild(stats.domElement)


}
// 自适应屏幕
let onWindowsResize = () => {

    sizes.width = window.innerWidth
    sizes.height = window.innerHeight
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(window.devicePixelRatio)
}

//双击全屏
let onWindowsScreen = () => {
    let isFullScreen = document.fullscreenElement
    if (!isFullScreen) {
        renderer.domElement.requestFullscreen()
    } else {
        document.exitFullscreen()
    }
}


let expandFunction = () => {
    window.addEventListener('resize', onWindowsResize)
    window.addEventListener('dblclick', onWindowsScreen)

}


// 创建粒子
let params = {
    count: 50000,
    size: 0.01,
    radius: 5,
    branches: 3,
    spin: 1,
    randomness: 0.2,
    randomnessPower: 3,
    insideColor: '#ff6030',
    outsideColor: '#1b3984'
}
let geometry = null
let material = null
let particles = null

let createGalaxy = () => {

    // 清空之前的粒子
    if (particles !== null) {

        geometry.dispose()
        material.dispose()
        scene.remove(particles)
    }

    geometry = new THREE.BufferGeometry()
    material = new THREE.PointsMaterial({
        size: params.size,
        sizeAttenuation: true,
        blending: THREE.AdditiveBlending,
        vertexColors: true
    })
    const vertexPoints = []
    const vertexColors = []

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

    for (let i = 0; i < params.count; i++) {

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

        // 不能凸显内部距离
        /*         const randomX = (Math.random() - 0.5) * params.randomness
                const randomY = (Math.random() - 0.5) * params.randomness
                const randomZ = (Math.random() - 0.5) * params.randomness */

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

        vertexPoints[i3] = Math.cos(branchAngle + spinAngle) * radius + randomX
        vertexPoints[i3 + 1] = randomY
        vertexPoints[i3 + 2] = Math.sin(branchAngle + spinAngle) * radius + randomZ
        // console.log(vertexPoints[i3],vertexPoints[i3 + 2]);

        const mixedColor = colorInside.clone()
        mixedColor.lerp(colorOutside, radius)
        vertexColors[i3] = mixedColor.r
        vertexColors[i3 + 1] = mixedColor.g
        vertexColors[i3 + 2] = mixedColor.b
    }

    const points = new THREE.Float32BufferAttribute(vertexPoints, 3)
    const colors = new THREE.Float32BufferAttribute(vertexColors, 3)
    geometry.attributes.position = points
    geometry.attributes.color = colors

    particles = new THREE.Points(geometry, material)
    particles.name = 'galaxy'
    scene.add(particles)
}

// 添加gui
let createGui = () => {

    gui = new GUI()
    gui.add(params, 'count', 1000, 100000, 1).onFinishChange(createGalaxy)
    gui.add(params, 'size', 0.01, 0.03, 0.001).onFinishChange(createGalaxy)
    gui.add(params, 'radius', 5, 10, 1).onFinishChange(createGalaxy)
    gui.add(params, 'branches', 3, 10, 1).onFinishChange(createGalaxy)
    gui.add(params, 'spin', -5, 5, 0.001).onFinishChange(createGalaxy)
    gui.add(params, 'randomness', 0, 2, 0.001).onFinishChange(createGalaxy)
    gui.add(params, 'randomnessPower', 1, 10, 0.001).onFinishChange(createGalaxy)
    gui.addColor(params, 'insideColor').onFinishChange(createGalaxy)
    gui.addColor(params, 'outsideColor').onFinishChange(createGalaxy)

}

const clock = new THREE.Clock()
let animate = () => {

    const elapsedTime = clock.getElapsedTime()

    // for (let i = 0; i < params.count * 3; i++){
    //     const i3 = i * 3
    //     const x = particles.geometry.attributes.position.array[i3]
    //     particles.geometry.attributes.position.array[i3 + 2] = Math.sin(x + 2 * elapsedTime)
    // }
    // particles.geometry.attributes.position.needsUpdate=true
    controls.update()
    stats.update()
    renderer.render(scene, camera)
    requestAnimationFrame(animate)
}

onMounted(()=>{
    init()
    createGalaxy()
    createGui()
    animate()
    expandFunction()
})

</script>


<style scoped>
.webgl{
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
}


</style>
