Vue ThreeJs实现银河系行星运动

news2025/1/14 1:23:18

预览

可通过右上角调整参数,进行光影练习

代码

<template>
    <div id="body"></div>
</template>
<script>

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

/*场景,渲染器,镜头,背景星星,帧率器,第一人称控制*/
let scene, renderer, camera, particleSystem, control;
let Sun,
    Mercury,  //水星
    Venus,  //金星
    Earth,
    Mars,
    Jupiter, //木星
    Saturn, //土星
    Uranus, //天王
    Neptune, //海王
    stars = [];
const cameraFar = 3000;  //镜头视距

export default {
    mounted() {

        /*renderer*/
        //渲染器
        renderer = new THREE.WebGLRenderer({ alpha: true })
        renderer.physicallyCorrectLights = true;
        renderer.shadowMap.enabled = true; //辅助线
        renderer.shadowMapSoft = true; //柔和阴影
        renderer.setClearColor('black', 1);
        renderer.setSize(window.innerWidth, window.innerHeight)
        document.getElementById('body').appendChild(renderer.domElement);

        /*scene*/
        scene = new THREE.Scene();

        /*camera*/
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, cameraFar);
        camera.position.set(-200, 50, 0);
        camera.lookAt(new THREE.Vector3(0, 0, 0));
        scene.add(camera);

        control = new OrbitControls(camera, renderer.domElement)
        control.update()

        /*sun skin pic*/
        // const texture = new THREE.TextureLoader().load( 'textures/land_ocean_ice_cloud_2048.jpg' );
        let sunSkinPic = new THREE.TextureLoader().load(new URL('../assets/sunCore.jpg', import.meta.url), {}, () => {
            renderer.render(scene, camera);
        });

        /*sun*/
        Sun = new THREE.Mesh(new THREE.SphereGeometry(12, 16, 16),
            new THREE.MeshLambertMaterial({
                /*color: 0xffff00,*/
                emissive: 0xdd4422,
                map: sunSkinPic
            })
        );
        Sun.name = 'Sun';
        Sun.castShadow = false;
        Sun.receiveShadow = false;
        scene.add(Sun);
        /*opacity sun*/
        let opSun = new THREE.Mesh(new THREE.SphereGeometry(14, 16, 16),
            new THREE.MeshLambertMaterial({
                side: THREE.DoubleSide,
                color: 0xff0000,
                /*emissive: 0xdd4422,*/
                transparent: true,
                opacity: .35
            })
        );

        opSun.name = 'Sun';
        scene.add(opSun);

        const plane = new THREE.Mesh(new THREE.PlaneGeometry(500, 500),
            new THREE.MeshStandardMaterial({
                side: THREE.DoubleSide,
                color: 0xffffff,
                metalness: .7,
                roughness: 0.5,
                // emissive: 0xffffff,
            })
        );
        plane.rotateX(-Math.PI / 2)
        plane.position.y = -30
        // plane.castShadow = true;
        plane.receiveShadow = true;
        scene.add(plane)

        //gui
        const gui = new GUI()

        /*planets*/
        Mercury = this.initPlanet('Mercury', 0.02, 0, 'rgb(124,131,203)', 20, 2);
        stars.push(Mercury);

        Venus = this.initPlanet('Venus', 0.012, 0, 'rgb(190,138,44)', 30, 4);
        stars.push(Venus);

        Earth = this.initPlanet('Earth', 0.010, 0, 'rgb(46,69,119)', 40, 5);
        stars.push(Earth);

        Mars = this.initPlanet('Mars', 0.008, 0, 'rgb(210,81,16)', 50, 4);
        stars.push(Mars);

        Jupiter = this.initPlanet('Jupiter', 0.006, 0, 'rgb(254,208,101)', 70, 9);
        stars.push(Jupiter);

        Saturn = this.initPlanet('Saturn', 0.005, 0, 'rgb(210,140,39)', 100, 7, {
            color: 'rgb(136,75,30)',
            innerRedius: 9,
            outerRadius: 11
        });
        stars.push(Saturn);

        Uranus = this.initPlanet('Uranus', 0.003, 0, 'rgb(49,168,218)', 120, 4);
        stars.push(Uranus);

        Neptune = this.initPlanet('Neptune', 0.002, 0, 'rgb(84,125,204)', 150, 3);
        stars.push(Neptune);



        //环境光
        let ambient = new THREE.AmbientLight(0x999999, 3);
        scene.add(ambient);

        /*太阳光*/
        let sunLight = new THREE.PointLight(0xddddaa, 6500, 500);
        sunLight.castShadow = true;
        sunLight.position.set(0, 0)
        // sunLight.scale.set(25,25,25)
        opSun.add(sunLight);
        let sunAmbient = new THREE.AmbientLight(0x999999, 3);
        opSun.add(sunAmbient)
        sunLight.shadow.mapSize.set(2048, 2048)

        /*背景星星*/
        const particles = 20000;  //星星数量
        /*buffer做星星*/
        let bufferGeometry = new THREE.BufferGeometry();

        let positions = new Float32Array(particles * 3);
        let colors = new Float32Array(particles * 3);

        let color = new THREE.Color();

        const gap = 1000; // 定义星星的最近出现位置

        for (let i = 0; i < positions.length; i += 3) {

            // positions

            /*-2gap < x < 2gap */
            let x = (Math.random() * gap * 2) * (Math.random() < .5 ? -1 : 1);
            let y = (Math.random() * gap * 2) * (Math.random() < .5 ? -1 : 1);
            let z = (Math.random() * gap * 2) * (Math.random() < .5 ? -1 : 1);

            /*找出x,y,z中绝对值最大的一个数*/
            let biggest = Math.abs(x) > Math.abs(y) ? Math.abs(x) > Math.abs(z) ? 'x' : 'z' :
                Math.abs(y) > Math.abs(z) ? 'y' : 'z';

            let pos = { x, y, z };

            /*如果最大值比n要小(因为要在一个距离之外才出现星星)则赋值为n(-n)*/
            if (Math.abs(pos[biggest]) < gap) pos[biggest] = pos[biggest] < 0 ? -gap : gap;

            x = pos['x'];
            y = pos['y'];
            z = pos['z'];

            positions[i] = x;
            positions[i + 1] = y;
            positions[i + 2] = z;

            // colors

            /*70%星星有颜色*/
            let hasColor = Math.random() > 0.3;
            let vx, vy, vz;

            if (hasColor) {
                vx = (Math.random() + 1) / 2;
                vy = (Math.random() + 1) / 2;
                vz = (Math.random() + 1) / 2;
            } else {
                vx = 1;
                vy = 1;
                vz = 1;
            }

            /*let vx = ( Math.abs(x) / n*2 ) ;
            var vy = ( Math.abs(y) / n*2 ) ;
            var vz = ( Math.abs(z) / n*2 ) ;*/

            color.setRGB(vx, vy, vz);

            colors[i] = color.r;
            colors[i + 1] = color.g;
            colors[i + 2] = color.b;
        }

        bufferGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        bufferGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
        bufferGeometry.computeBoundingSphere();

        /*星星的material*/
        let material = new THREE.PointsMaterial({ size: 6, vertexColors: THREE.VertexColors });
        particleSystem = new THREE.Points(bufferGeometry, material);
        scene.add(particleSystem);


        //帮助模块
        const axesHelper = new THREE.AxesHelper(500)
        scene.add(axesHelper)
        axesHelper.visible = false;
        const lightHelper = new THREE.PointLightHelper(sunLight, 1, 100);
        scene.add(lightHelper);
        lightHelper.visible = false;
        plane.visible = false;


        gui.add(Sun.position, 'y').name('太阳Y轴').min(-100).max(100).onChange((val) => {
            opSun.position.y = val;
        })
        gui.add(sunLight.position, 'y').name('光源Y轴').min(-100).max(100).onChange((val) => {
            sunLight.position.y = val;
        })
        gui.add(sunAmbient, 'intensity').name('太阳环境光强度').min(0).max(10)
        gui.add(sunLight, 'intensity').name('太阳点光照强度').min(0).max(20000)
        gui.add(sunLight, 'distance').name('太阳点光照距离').min(0).max(20000)
        gui.add(sunLight, 'decay').name('太阳点光照衰减').min(0).max(5)

        gui.add(plane, 'visible').name('显示平面')
        gui.add(axesHelper, 'visible').name('显示坐标轴')
        gui.add(lightHelper, 'visible').name('显示光源辅助')


        //渲染动画
        let run = { run: true };
        gui.add(run, 'run')
        const animate = () => {
            if (run.run) {
                /*行星公转*/
                stars.forEach(star =>
                    this.moveEachStar(star)
                )
                Sun.rotation.y = (Sun.rotation.y == 2 * Math.PI ? 0.0008 * Math.PI : Sun.rotation.y + 0.0008 * Math.PI);
            }
            requestAnimationFrame(animate)
            renderer.render(scene, camera)
            lightHelper.update()
        }
        requestAnimationFrame(animate)


    },
    methods: {
        /*每一颗行星的公转*/
        moveEachStar(star) {

            star.angle += star.speed;
            if (star.angle > Math.PI * star.distance) {
                star.angle -= Math.PI * star.distance;
            }

            star.Mesh.position.set(star.distance * Math.sin(star.angle), 0, star.distance * Math.cos(star.angle));

            /*碎星带*/
            if (star.ring) {
                star.ring.position.set(star.distance * Math.sin(star.angle), 0, star.distance * Math.cos(star.angle));
            }
        },
        initPlanet(name, speed, angle, color, distance, volume, ringMsg) {
            let mesh = new THREE.Mesh(new THREE.SphereGeometry(volume, 16, 16),
                new THREE.MeshStandardMaterial({
                    color, metalness: .7,
                    roughness: 0.5,
                })
            );
            mesh.position.x = distance;
            mesh.receiveShadow = true;
            mesh.castShadow = true;

            mesh.name = name;

            /*轨道*/
            let track = new THREE.Mesh(new THREE.RingGeometry(distance - 0.2, distance + 0.2, 64, 1),
                new THREE.MeshBasicMaterial({ color: 0x888888, side: THREE.DoubleSide })
            );
            track.rotation.x = - Math.PI / 2;
            scene.add(track);

            let star = {
                name,
                speed,
                angle,
                distance,
                volume,
                Mesh: mesh
            }

            /*如果有碎星带*/
            if (ringMsg) {
                let ring = new THREE.Mesh(new THREE.RingGeometry(ringMsg.innerRedius, ringMsg.outerRadius, 32, 6),
                    new THREE.MeshBasicMaterial({ color: ringMsg.color, side: THREE.DoubleSide, opacity: .7, transparent: true })
                );

                ring.name = `Ring of ${name}`;
                ring.rotation.x = - Math.PI / 3;
                ring.rotation.y = - Math.PI / 4;
                scene.add(ring);

                star.ring = ring;
            }


            scene.add(mesh);

            return star;
        },
    }
}
</script>

完整代码

ThreeJs DEMO: 通过行星模型辅助光源阴影的练习项目

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1340971.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FontsTest.java

package fonts;import java.awt.Font; import java.awt.GraphicsEnvironment;/*** Font测试* * 不同字体在不同操作系统是不一样的&#xff0c;更新* * linux&#xff1a; https://blog.csdn.net/spencer_tseng/article/details/135232675windows&#xff1a; https://blog.cs…

48道Linux面试题

本博客将汇总 Linux 面试中常见的题目&#xff0c;并提供详细的解答。 文章目录 1、绝对路径用什么[符号表](https://so.csdn.net/so/search?q符号表&spm1001.2101.3001.7020)示&#xff1f;当前目录、上层目录用什么表示&#xff1f;主目录用什么表示? 切换目录用什么命…

活动回顾 (下) | 机器学习系统趋势研判,大咖金句汇总

作者&#xff1a;三羊、李宝珠、李玮栋、Yudi、xixi 编辑&#xff1a;李宝珠 在大模型时代的浪潮中&#xff0c;机器学习系统正经历着前所未有的变革。模型规模的急剧膨胀&#xff0c;让我们见证了 AI 能力的巨大提升&#xff0c;然而这种提升不仅为各个领域带来了新的机遇&…

Java版企业电子招标采购系统源码——鸿鹄电子招投标系统的技术特点

在数字化时代&#xff0c;采购管理也正经历着前所未有的变革。全过程数字化采购管理成为了企业追求高效、透明和规范的关键。该系统通过Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;打造了从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通过…

六、Redis 分布式系统

六、Redis 分布式系统 六、Redis 分布式系统6.1 数据分区算法6.1.1 顺序分区6.1.2 哈希分区 6.2 系统搭建与运行6.2.1 系统搭建6.2.2 系统启动与关闭 6.3 集群操作6.3.1 连接集群6.3.2 写入数据6.3.3 集群查询6.3.4 故障转移6.3.5 集群扩容6.3.6 集群收缩 6.4 分布式系统的限制…

两张图片沿着斜对角线合并成一张图片

在图像融合领域,论文中的对比算法可视化,需要将红外图像和可见光图像沿着斜对角线合并成一张图片。 红外与可见光图像举例: 然后做出这样的效果: 用Python的PIL库,将两张图片沿着斜对角线合并成一张图片。 from PIL import Image, ImageDraw# 两张图片的路径 image1_pat…

elasticsearch系列三:常用查询语法

概述 前几篇我们介绍了如何在es中存储数据&#xff0c;如何更加合理的存储数据&#xff0c;今天我们来说下常用的查询语法&#xff0c;如何实现mysql中的等于、大于、小于、and 、or、in等方式。 案例 我们以kibana为例&#xff0c;比如sql中的等于&#xff0c;在es中可以用…

使用cmake配置matplotlibcpp生成VS项目

https://gitee.com/feboreigns/matplotlibcpp 这篇文章需要一些cmake基础&#xff0c;python基础&#xff0c;visualstudio基础 准备环境 注意如果在VS平台使用必须要手动下载python&#xff0c;不能使用conda里面的&#xff0c;比如3.8版本&#xff0c;因为conda里面没有py…

阿里云PolarDB数据库费用价格表

阿里云数据库PolarDB租用价格表&#xff0c;云数据库PolarDB MySQL版2核4GB&#xff08;通用&#xff09;、2个节点、60 GB存储空间55元5天&#xff0c;云数据库 PolarDB 分布式版标准版2核16G&#xff08;通用&#xff09;57.6元3天&#xff0c;阿里云百科aliyunbaike.com分享…

k8s二进制部署--部署高可用

连接上文 notready是因为没有网络&#xff0c;因此无法创建pod k8s的CNI网络插件模式 1.pod内部&#xff0c;容器与容器之间的通信。 在同一个pod中的容器共享资源和网络&#xff0c;使用同一个网络命名空间。 2.同一个node节点之内&#xff0c;不同pod之间的通信。 每个pod都…

rs61 外置声卡 win10 驱动

官方的是32位xp的驱动&#xff0c;win10已经无法使用。 USB\VID_08BB&PID_2900 | Device Drivers (oemdrivers.com) 硬件ID和雅马哈sound-yamaha-mg10xu-usb-driver的一样&#xff0c;下载驱动安装测试正常 https://usa.yamaha.com/files/download/software/9/1549789/YS…

深度解析TB用户购物行为:系统搭建与优化

深度解析TB用户购物行为&#xff1a;系统搭建与优化 引言系统搭建数据集技术选型 系统功能1. 用户维度分析2. 产品维度分析3. 聚类结果分析 创新点系统优化与展望优化展望 结语 引言 在电商时代&#xff0c;了解用户购物行为并从中提取有价值的信息对于企业制定营销策略和优化…

算法基础之计数问题

计数问题 核心思想&#xff1a; 数位dp / 累加 累加 ​ 分情况讨论 &#xff1a; xxx 000 ~ abc –1 yyy 000 ~ 999 共 abc * 1000 种 特别地&#xff0c;当枚举数字0时 (找第4位为0的数) 前三位不能从000开始了 否则没这个数不合法(有前导零) xxx abc 2.1. d < 1 , 不…

uniapp实现前端银行卡隐藏中间的数字,及隐藏姓名后两位

Vue 实现前端银行卡隐藏中间的数字 主要应用了 filters过滤器 来实现效果 实现效果&#xff0c;如图&#xff1a; <template><div><div style"background-color: #f4f4f4;margin:50px 0 0 460px;width:900px;height:300px;"><p>原来&#…

算法导论复习纲要

函数 1. 上界下界&#xff0c;紧确界的定义 2. 求解递推式&#xff0c;代入法&#xff0c;递归树法&#xff0c;主方法 分治算法 动态规划 1. 切割钢条&#xff1a;递归方法&#xff0c;动态的自上而下&#xff0c; 2. 矩阵乘法&#xff1a;最优子结构性的证明&#xff0c…

听GPT 讲Rust源代码--src/tools(28)

File: rust/src/tools/clippy/clippy_lints/src/operators/identity_op.rs 文件路径 rust/src/tools/clippy/clippy_lints/src/operators/identity_op.rs 中的作用是定义了 IdentityOp 类型的 Clippy lint 规则&#xff0c;用于检查代码中是否存在不必要的恒等操作符&#xff0…

【AI+MJ提示词】Midjourney提示词系统化-反乌托邦(Dystopian)和技术朋克

反乌托邦&#xff08;Dystopian&#xff09;和技术朋克 反乌托邦&#xff08;Dystopian&#xff09;和技术朋克&#xff08;Techno Punk&#xff09;都是描述未来世界的文学流派。 反乌托邦描述的未来世界通常是一个被政府或强大机构严格控制的世界&#xff0c;人们的生活被监…

攻防世界—no-strings-attached

# 攻防世界—no-strings-attached 介绍下——IDA内置脚本 shiftF12 收获——要一个一个大致看出代码在干嘛 先运行一遍 int __cdecl main(int argc, const char **argv, const char **envp) { setlocale(6, &locale); banner(); prompt_authentication(); authenti…

哈希桶的模拟实现【C++】

文章目录 哈希冲突解决闭散列 &#xff08;开放定址法&#xff09;开散列 &#xff08;链地址法、哈希桶&#xff09;开散列实现&#xff08;哈希桶&#xff09;哈希表的结构InsertFindErase 哈希冲突解决 闭散列 &#xff08;开放定址法&#xff09; 发生哈希冲突时&#xf…

【CSS】基础知识梳理和总结

1. 前言 CSS&#xff08;Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;用来为HTML文档添加样式的计算机语言。HTML中加载样式的方法有三种&#xff1a; 通过<link>标签加载外部样式表&#xff08;External Style Sheet&#xff09;&#xff0c…