当前位置: 首页 > article >正文

【Three.js基础学习】26. Animated galaxy

前言

shaders实现星系

    课程回顾

        使用顶点着色器为每个粒子设置动画

        a属性 , u制服 ,v变化

        像素比:window.devicePixelRatio

        自动从渲染器检索像素比

            renderer.getPixelRatio()

        如何尺寸衰减, 放大缩小视角时,粒子都是同样大小的问题

        gl_Position += (1.0 / - viewPosition);

  

下面是实现的数学解释


一、代码

这个我听的迷迷糊糊的,直接看代码中的注释吧

1.script.js

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as dat from 'lil-gui'
import galaxyVertexShader from './shaders/galaxy/vertex.glsl'
import galaxyFragmentShader from './shaders/galaxy/fragment.glsl'


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

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

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

/**
 * Galaxy
 */
const parameters = {}
parameters.count = 200000
parameters.size = 0.005
parameters.radius = 6
parameters.branches = 3
parameters.spin = 1
parameters.randomness = 0.2
parameters.randomnessPower = 3
parameters.insideColor = '#ff6030'
parameters.outsideColor = '#1b3984'

let geometry = null
let material = null
let points = null

const generateGalaxy = () =>
{
    if(points !== null) // 制空
    {
        geometry.dispose()
        material.dispose()
        scene.remove(points)
    }

    /**
     * Geometry
     */
    geometry = new THREE.BufferGeometry()
    // 这里为什么*3 因为要向各个方向发展,为什么*1只是在一个方向上拉伸
    const positions = new Float32Array(parameters.count * 3)
    const randomness = new Float32Array(parameters.count * 3)
    const colors = new Float32Array(parameters.count * 3)
    const scales = new Float32Array(parameters.count * 1)

    const insideColor = new THREE.Color(parameters.insideColor)
    const outsideColor = 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 branchAngle = (i % parameters.branches) / parameters.branches * Math.PI * 2

/*
        长时间就会发现星系在变薄,像一条丝带 ,应该避免
        下面代码 创建一个新的Float32Array并且在旋转后使用该属性 不应该在旋转之前添加应用随机性randomZXY
 */
        const randomZ = Math.pow(Math.random(), parameters.randomnessPower) * (Math.random() < 0.5 ? 1 : - 1)  * parameters.randomness * radius
        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
        
        // 旋转 将数据填充到位置上
        positions[i3    ] = Math.cos(branchAngle) * radius
        positions[i3 + 1] = 0.0
        positions[i3 + 2] = Math.sin(branchAngle) * radius
    
        randomness[i3    ] = randomX
        randomness[i3 + 1] = randomY
        randomness[i3 + 2] = randomZ

        // Color
        const mixedColor = insideColor.clone()
        mixedColor.lerp(outsideColor, radius / parameters.radius)

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

        // Scale
        scales[i] = Math.random()
    }

    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('aRandomness', new THREE.BufferAttribute(randomness, 3))
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
    geometry.setAttribute('aScale', new THREE.BufferAttribute(scales, 1))

    /**
     * Material
     */
    material = new THREE.ShaderMaterial({
        depthWrite: false,
        blending: THREE.AdditiveBlending,
        vertexColors: true,
        uniforms:
        {
            uTime: { value: 0 },
            uSize: { value: 30 * renderer.getPixelRatio() }  // 星系顶点尺寸*像素比
        },    
        vertexShader: galaxyVertexShader,
        fragmentShader: galaxyFragmentShader
    })

    /**
     * Points
     */
    points = new THREE.Points(geometry, material)
    scene.add(points)
}

gui.add(parameters, 'count').min(100).max(1000000).step(100).onFinishChange(generateGalaxy).name('数量')
gui.add(parameters, 'radius').min(0.01).max(20).step(0.01).onFinishChange(generateGalaxy).name('半径')
gui.add(parameters, 'branches').min(2).max(20).step(1).onFinishChange(generateGalaxy).name('条数')
gui.add(parameters, 'randomness').min(0).max(2).step(0.001).onFinishChange(generateGalaxy).name('随机')
gui.add(parameters, 'randomnessPower').min(1).max(10).step(0.001).onFinishChange(generateGalaxy).name('随机功率')
gui.addColor(parameters, 'insideColor').onFinishChange(generateGalaxy).name('内部颜色')
gui.addColor(parameters, 'outsideColor').onFinishChange(generateGalaxy).name('外部颜色')

/**
 * 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))

/**
 * Generate the first galaxy
 */
generateGalaxy()

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

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

    // Update material
    material.uniforms.uTime.value = elapsedTime

    // Update controls
    controls.update()

    // Render
    renderer.render(scene, camera)

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

tick()

2. 顶点着色器

uniform float uTime;
uniform float uSize;

attribute vec3 aRandomness;
attribute float aScale;

varying vec3 vColor;

/* 
    atan(x) 弧度 反正切函数
*/

void main()
{
    /**
     * Position
     */
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
                
    // Rotate
    float angle = atan(modelPosition.x, modelPosition.z); // 获取角度 偏移的
    float distanceToCenter = length(modelPosition.xz); // 到中心的距离
    float angleOffset = (1.0 / distanceToCenter) * uTime ; // 根据时间应该旋转多少度
    angle += angleOffset; // 更新角度 并且 角度加上角度偏移
    modelPosition.x = cos(angle) * distanceToCenter; // 更新到模型上,同时乘以到中心的距离
    modelPosition.z = sin(angle) * distanceToCenter;

    // Randomness 随机
    modelPosition.xyz += aRandomness;

    vec4 viewPosition = viewMatrix * modelPosition;
    vec4 projectedPosition = projectionMatrix * viewPosition;
    gl_Position = projectedPosition;

    /**
     * Size
     */
    gl_PointSize = uSize * aScale;
    gl_PointSize *= (1.0 / - viewPosition.z);

    /**
     * Color
     */
    vColor = color;
}

3.片段着色器

varying vec3 vColor;

void main()
{
    // // Disc
    // float strength = distance(gl_PointCoord, vec2(0.5));
    // strength = step(0.5, strength);
    // strength = 1.0 - strength;

    // // Diffuse point
    // float strength = distance(gl_PointCoord, vec2(0.5));
    // strength *= 2.0;
    // strength = 1.0 - strength;

    // Light point
    float strength = distance(gl_PointCoord, vec2(0.5));
    strength = 1.0 - strength;
    strength = pow(strength, 10.0);

    // Final color
    vec3 color = mix(vec3(0.0), vColor, strength);
    gl_FragColor = vec4(color, 1.0);
}

二、效果

shaders - 星系


总结

今天学的迷迷糊糊的,整体代码知道看得懂,思路,如何偏移以及一些数学计算很蒙!


http://www.kler.cn/a/401445.html

相关文章:

  • 编译OpenCV的速度,家里和公司的电脑相差很大
  • macbook外接2k/1080p显示器调试经验
  • 基于YOLOv8深度学习的独居老人情感状态监护系统(PyQt5界面+数据集+训练代码)
  • 【Pythonr入门第二讲】你好,世界
  • 【金融风控项目-08】:特征构造
  • 如何解决多系统数据重复与冲突问题?
  • Dubbo源码解析-服务导出(四)
  • chatGPT是如何使用tensrFlow训练模型的?
  • 【数据分享】1981-2024年我国逐日最低气温栅格数据(免费获取)
  • CSS3中的弹性布局之侧轴的对齐方式
  • 梧桐数据库深入探索递归查询的强大功能
  • Excel——宏教程(精简版)
  • EMall实践DDD模拟电商系统总结
  • 学习整理在php中一个二维数组按另一个一维数组顺序排序
  • 【OpenCV】Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR)
  • C++ 对函数的详细记录 【雨露均沾】
  • 【UGUI】Unity 游戏开发:背包系统初始化克隆道具
  • CFD 应用于分离过程:旋风分离器(第 2 部分)
  • 服务器上Cuda+Pytorch兼容性的那些问题
  • 鸿蒙学习生态应用开发能力全景图-鸿蒙开发套件(2)续集 OS 开放能力集
  • 跨平台WPF框架Avalonia教程 二
  • Java学习笔记--数组常见算法:数组翻转,冒泡排序,二分查找
  • 【leetcode 02】27. 移除元素
  • Three.js PBR材质
  • iOS无人直播虚拟视频实用版
  • Windows系统编程 - 进程遍历