Three.js--》实现3d地月模型展示

目录

项目搭建

初始化three.js基础代码

创建月球模型

添加地球模型

添加模型标签


今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。

项目搭建

本案例还是借助框架书写three项目,借用vite构建工具搭建vue项目,vite这个构建工具如果有不了解的朋友,可以参考我之前对其讲解的文章:vite脚手架的搭建与使用 。搭建完成之后,用编辑器打开该项目,在终端执行 npm i 安装一下依赖,安装完成之后终端在安装 npm i three 即可。

<template>
  <!-- 地月模型 -->
  <EarthMoonSurrounding></EarthMoonSurrounding>
</template>

<script setup>
import EarthMoonSurrounding from './components/EarthMoonSurrounding.vue';
</script>

<style lang="less">
  *{
    margin: 0;
    padding: 0;
  }
</style>

初始化three.js基础代码

three.js开启必须用到的基础代码如下:

导入three库

import * as THREE from 'three'

初始化场景

const scene = new THREE.Scene()

初始化相机

const camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,200)
camera.position.set(10,5,20)

初始化渲染器

const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth,window.innerHeight)

监听屏幕大小的改变,修改渲染器的宽高和相机的比例

window.addEventListener("resize",()=>{ 
  renderer.setSize(window.innerWidth,window.innerHeight)
  camera.aspect = window.innerWidth/window.innerHeight
  camera.updateProjectionMatrix()
})

设置渲染函数

const render = () =>{ 
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

进行挂载

onMounted(()=>{
  render()
})

ok,写完基础代码之后,接下来开始具体的Demo实操。

创建月球模型

首先这里通过直接给画布的canvas标签添加css样式,给其一个背景图片作为背景:

canvas{
  background-image: url('../../public/images/star.jpg');
  background-size: cover;
}

然后使用TextureLoader用于加载图片纹理的工具,将图片文件加载为 Three.js 中的纹理对象,并且可以将纹理应用到场景中的任何物体上,从而实现更加生动的渲染效果。

// 创建月球
const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS,16,16)
const moonMaterial = new THREE.MeshPhongMaterial({
  map: textureLoader.load('/public/textures/planets/moon_1024.jpg')
})
const moon = new THREE.Mesh(moonGeometry, moonMaterial)
moon.receiveShadow = true
moon.castShadow = true;
scene.add(moon)

创建好模型之后给场景中添加光源:

// 创建添加聚光灯光源
const dirLight = new THREE.SpotLight(0xffffff)
dirLight.position.set(0,0,10)
dirLight.intensity = 1
dirLight.castShadow = true
scene.add(dirLight)
// 添加环境光
const aLight = new THREE.AmbientLight(0xffffff)
aLight.intensity = 0.03
scene.add(aLight)

在渲染函数中通过getElapsedTime方法计算动画经过的时间或者控制动画的播放速度,来动态改变月球位置,让其绕圆周开始运动。

let clock = new THREE.Clock();
// 设置渲染函数
const render = () =>{ 
  const elapsed = clock.getElapsedTime()
  // 月球旋转
  moon.position.set(Math.sin(elapsed)*5,0,Math.cos(elapsed)*5)
  renderer.render(scene,camera)
  requestAnimationFrame(render)
}

添加地球模型

这里也采用TextureLoader用于加载图片纹理的工具,将图片文件加载为 Three.js 中的纹理对象,并且可以将纹理应用到场景中的任何物体上,从而实现更加生动的渲染效果。

// 创建地球
const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS,16,16)
const earthMaterial = new THREE.MeshPhongMaterial({
  map: textureLoader.load('/public/textures/planets/earth_atmos_2048.jpg'),
  specularMap: textureLoader.load('/public/textures/planets/earth_specular_2048.jpg'),
  normalMap: textureLoader.load('/public/textures/planets/earth_normal_2048.jpg'),
})
const earth = new THREE.Mesh(earthGeometry,earthMaterial)
earth.receiveShadow = true
earth.castShadow = true
scene.add(earth)

这里依然在render渲染函数处通过getElapsedTime方法计算动画经过的时间或者控制动画的播放速度,来动态改变地球自转速度,让自转运动。

let clock = new THREE.Clock();
let oldtime = 0
// 设置渲染函数
const render = () =>{ 
  const elapsed = clock.getElapsedTime()
  // 月球旋转
  moon.position.set(Math.sin(elapsed)*5,0,Math.cos(elapsed)*5)
  // 地球自转
  let axis = new THREE.Vector3(0,1,0)
  earth.rotateOnAxis(axis, (elapsed - oldtime) * Math.PI / 10)
  oldtime = elapsed
  requestAnimationFrame(render)
}

添加模型标签

在 Three.js 中,CSS2DRenderer 是一个用于将 HTML 元素渲染成 2D 贴图,并将其添加到 Three.js 场景中的工具类。它可以帮助我们更方便地在 Three.js 场景中添加 HTML 元素,比如显示标签、文字等。CSS2DRenderer 类似于 Three.js 中的 WebGLRenderer,但是它渲染的不是 Three.js 的 3D 对象,而是 HTML 元素。

import { CSS2DRenderer} from 'three/examples/jsm/renderers/CSS2DRenderer'

// 创建标签选择器
const labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight)
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.body.appendChild(labelRenderer.domElement)
// 给CSS2DRenderer添加控制器
const controls1 = new OrbitControls(camera,labelRenderer.domElement)
controls1.enableDamping = true

CSS2DObject 则是可以在 Three.js 场景中创建的一个 CSS2D 元素。它类似于 Three.js 中的 Mesh,但是它表示的不是三维物体,而是一个 CSS 元素。你可以通过创建 CSS2DObject 实例,将其添加到 Three.js 的场景中,并设置其内部的 HTML 元素,从而在 Three.js 场景中显示 HTML 内容。

import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'

// 创建月球标签
const moonDiv = document.createElement('div');
moonDiv.className = 'label';
moonDiv.textContent = 'Moon';
const moonLabel = new CSS2DObject(moonDiv)
moonLabel.position.set(0, MOON_RADIUS + 0.5, 0);
moon.add(moonLabel)

// 创建地球标签
const earthDiv = document.createElement('div');
earthDiv.className = 'label';
earthDiv.textContent = 'Earch';
const eartchLabel = new CSS2DObject(earthDiv)
eartchLabel.position.set(0, EARTH_RADIUS + 0.5, 0);
earth.add(eartchLabel)

然后给出直接设置类名的样式:

最后在渲染函数中加载渲染标签函数 :

demo做完,给出本案例的完整代码:(获取素材也可以私信博主)

<script setup>
import * as THREE from 'three'
import { onMounted } from 'vue';
// 控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 文字2D渲染器
import { CSS2DRenderer,CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,200)
camera.position.set(10,5,20)

// 创建渲染器
const renderer = new THREE.WebGLRenderer({ 
  alpha: true
})
renderer.setPixelRatio(window.devicePixelRatio) // 根据屏幕显示像素比
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.shadowMap.enabled = true // 渲染阴影
document.body.appendChild(renderer.domElement)

window.addEventListener("resize",()=>{ 
  renderer.setSize(window.innerWidth,window.innerHeight)
  camera.aspect = window.innerWidth/window.innerHeight
  camera.updateProjectionMatrix()
})

// 设置控制器
const controls = new OrbitControls(camera,renderer.domElement)
controls.enableDamping = true

let clock = new THREE.Clock();
let oldtime = 0
// 设置渲染函数
const render = () =>{ 
  const elapsed = clock.getElapsedTime()
  // 月球旋转
  moon.position.set(Math.sin(elapsed)*5,0,Math.cos(elapsed)*5)
  // 地球自转
  let axis = new THREE.Vector3(0,1,0)
  earth.rotateOnAxis(axis, (elapsed - oldtime) * Math.PI / 10)
  oldtime = elapsed
  renderer.render(scene,camera)
  labelRenderer.render(scene, camera)
  requestAnimationFrame(render)
}

// 设置地球和月球的半径大小
const EARTH_RADIUS = 2.5
const MOON_RADIUS = 0.27
// 实例化纹理加载器
const textureLoader = new THREE.TextureLoader()
// 创建标签选择器
const labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight)
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.body.appendChild(labelRenderer.domElement)
// 给CSS2DRenderer添加控制器
const controls1 = new OrbitControls(camera,labelRenderer.domElement)
controls1.enableDamping = true

// 创建月球
const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS,16,16)
const moonMaterial = new THREE.MeshPhongMaterial({
  map: textureLoader.load('/public/textures/planets/moon_1024.jpg')
})
const moon = new THREE.Mesh(moonGeometry, moonMaterial)
moon.receiveShadow = true
moon.castShadow = true;
scene.add(moon)
// 创建月球标签
const moonDiv = document.createElement('div');
moonDiv.className = 'label';
moonDiv.textContent = 'Moon';
const moonLabel = new CSS2DObject(moonDiv)
moonLabel.position.set(0, MOON_RADIUS + 0.5, 0);
moon.add(moonLabel)

// 创建地球
const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS,16,16)
const earthMaterial = new THREE.MeshPhongMaterial({
  map: textureLoader.load('/public/textures/planets/earth_atmos_2048.jpg'),
  specularMap: textureLoader.load('/public/textures/planets/earth_specular_2048.jpg'),
  normalMap: textureLoader.load('/public/textures/planets/earth_normal_2048.jpg'),
})
const earth = new THREE.Mesh(earthGeometry,earthMaterial)
earth.receiveShadow = true
earth.castShadow = true
scene.add(earth)
// 创建地球标签
const earthDiv = document.createElement('div');
earthDiv.className = 'label';
earthDiv.textContent = 'Earch';
const eartchLabel = new CSS2DObject(earthDiv)
eartchLabel.position.set(0, EARTH_RADIUS + 0.5, 0);
earth.add(eartchLabel)

// 创建添加聚光灯光源
const dirLight = new THREE.SpotLight(0xffffff)
dirLight.position.set(0,0,10)
dirLight.intensity = 1
dirLight.castShadow = true
scene.add(dirLight)
// 添加环境光
const aLight = new THREE.AmbientLight(0xffffff)
aLight.intensity = 0.03
scene.add(aLight)

onMounted(()=>{
  render()
})
</script>
<style lang="less">
canvas{
  background-image: url('../../public/images/star.jpg');
  background-size: cover;
}
.label {
  color: #fff;
  font-size: 16px;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《离散数学》:代数系统和图论导论

一、代数系统 代数系统是数学中的一个重要概念&#xff0c;它涉及一组对象以及定义在这些对象上的运算规则。代数系统可以是抽象的&#xff0c;也可以是具体的。 在抽象代数中&#xff0c;代数系统通常由一组元素和一组操作&#xff08;或称为运算&#xff09;组成。这些操作…

【MySQL新手入门系列四】:手把手教你MySQL数据查询由入门到学徒

SQL语言是与数据库交互的机制&#xff0c;是关系型数据库的标准语言。SQL语言可以用于创建、修改和查询关系数据库。SQL的SELECT语句是最重要的命令之一&#xff0c;用于从指定表中查询数据。在此博客中&#xff0c;我们将进一步了解SELECT语句以及WHERE子句以及它们的重要性。…

vue进阶-vue-route

Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成&#xff0c;让用 Vue.js 构建单页应用变得轻而易举。 本章只做学习记录&#xff0c;详尽的内容一定要去官网查看api文档 Vue Router-Vue.js 的官方路由 1. 路由的基本使用 1.1 安装vue-router npm install vue-…

SpringCloud Eureka注册中心高可用集群配置(八)

当注册中心扛不住高并发的时候&#xff0c;这时候 要用集群来扛&#xff1b; 我们再新建两个module microservice-eureka-server-2002 microservice-eureka-server-2003 第一步&#xff1a; pom.xml 把依赖加下&#xff1a; <dependencies> <dependency…

golang 协程的实现原理

核心概念 要理解协程的实现, 首先需要了解go中的三个非常重要的概念, 它们分别是G, M和P, 没有看过golang源代码的可能会对它们感到陌生, 这三项是协程最主要的组成部分, 它们在golang的源代码中无处不在. G (goroutine) G是goroutine的头文字, goroutine可以解释为受管理的…

Prompt 范式产业实践分享!基于飞桨 UIE-X 和 Intel OpenVINO 实现跨模态文档信息抽取

近期 Prompt 范式备受关注&#xff0c;实际上&#xff0c;其思想在产业界已经有了一些成功的应用案例。中科院软件所和百度共同提出了大一统诸多任务的通用信息抽取技术 UIE&#xff08;Universal Information Extraction&#xff09;。截至目前&#xff0c;UIE 系列模型已发布…

Selenium 相对定位

目录 前言&#xff1a; 相对定位 工作原理 可用的相对定位 Above Below Left of Right of Near 链式相对定位 相对于WebElement的相对定位 实例演示 前言&#xff1a; Selenium传统定位基本能解决80%的定位需求&#xff0c;但是还是有一些复杂场景传统定位定不到的…

express框架学习笔记

express简介 express是一个基于Node.js平台的极简的、灵活的WEB应用开发框架。express是一个封装好的工具包&#xff0c;封装了很多功能&#xff0c;便于我们开发WEB应用&#xff08;HTTP服务&#xff09; express使用 新建express文件夹新建文件test01.js&#xff0c;代码如…

深蓝学院C++基础与深度解析笔记 第 5 章 语句

1. 语句基础 ● 语句的常见类别 – 表达式语句&#xff1a;表达式后加分号&#xff0c;对表达式求值后丢弃&#xff0c;可能产生副作用 – 空语句&#xff1a;仅包含一个分号的语句&#xff0c;可能与循环一起工作 – 复合语句&#xff08;语句体&#xff09;&#xff1a;由大…

电商数仓(用户行为采集平台)数据仓库概念、用户行为日志、业务数据、模拟数据、用户行为数据采集模块、日志采集Flume

1、数据仓库概念 数据仓库&#xff08; Data Warehouse &#xff09;&#xff0c;是为企业制定决策&#xff0c;提供数据支持的。可以帮助企业&#xff0c;改进业务流程、提高产品质量等。 数据仓库的输入数据通常包括&#xff1a;业务数据、用户行为数据和爬虫数据等。 业务数…

流场粒子追踪精度数值实验

在计算流线&#xff0c;拉格朗日拟序结构等流场后处理时&#xff0c;我们常常需要计算无质量的粒子在流场中迁移时的轨迹&#xff0c;无质量意味着粒子的速度为流场当地的速度。此时&#xff0c;求解粒子的位移这个问题是一个非常简单的常微分方程问题。 假设流场中存在 i 个粒…

Java版本+企业电子招投标系统源代码之电子招投标系统建设的重点和未来趋势

计算机与网络技术的不断发展&#xff0c;推动了社会各行业信息化的步伐。时至今日&#xff0c;电子政务、电子商务已经非常普及&#xff0c;云计算、大数据、工业4.0、“互联网”等发展理念也逐步深入人心&#xff0c;如何将传统行业与互联网科技有效结合起来&#xff0c;产生1…

Vue实现元素沿着坐标数组移动,超出窗口视图时页面跟随元素滚动

一、实现元素沿着坐标数组移动 现在想要实现船沿着下图中的每个河岸移动。 实现思路&#xff1a; 1、将所有河岸的位置以 [{x: 1, y: 2}, {x: 4, y: 4}, …] 的形式保存在数组中。 data() {return {coordinateArr: [{ x: 54, y: 16 }, { x: 15, y: 31 }, { x: 51, y: 69 }…

升级Nginx

目录 前言 一、升级Nginx 1&#xff09;首先在官网下载一个新版本的Nginx 2&#xff09;首先将下载的压缩包进行解包 3&#xff09;进入已解包的目录中 4&#xff09;配置安装路径 5&#xff09;make 6&#xff09;备份原来Nginx的资源 7&#xff09;重启Nginx服务 8&#…

【2023最全教程】Web自动化测试怎么做?Web自动化测试的详细流程和步骤

一、什么是web自动化测试 自动化&#xff08;Automation&#xff09;是指机器设备、系统或过程&#xff08;生产、管理过程&#xff09;在没有人或较少人的直接参与下&#xff0c;按照人的要求&#xff0c;经过自动检测、信息处理、分析判断、操纵控制&#xff0c;实现预期的目…

毕业季Android开发面试,有哪些常见的题?

前言 对于计算机行业早已烂大街&#xff0c;随之而来的毕业季。还会有大批的程序员涌进来&#xff0c;而我们想要继续进入Android开发岗位的人员&#xff0c;最先考虑的是面试。面试题是我们决定踏进工作的重要环节。 对于刚毕业的实习生来说&#xff0c;如何在应聘中脱颖而出…

LightningChart .NET 10.5.1 Crack LightningChart 2023

LightningChart .NET v.10.5.1 已经发布&#xff01; DataCursor 和 3D TransparencyRenderMode 现在可用。 为所有 3D、Polar 和 Smith 系列启用 DataCursor 在早期阶段&#xff0c;LightningChart 提供了不同的工具&#xff0c;需要用户编写额外的代码才能启用数据跟踪功能。…

控制您的数据:Web3私有链为数据主权带来的突破性变革

在数字化时代&#xff0c;数据已经成为企业和个人最宝贵的资产之一。然而&#xff0c;随着大规模数据泄露和滥用事件的频发&#xff0c;数据主权和隐私保护成为了备受关注的问题。在这个背景下&#xff0c;Web3私有链的出现为数据主权带来了一场突破性的变革。 首先&#xff0c…

风景类Midjourney prompt提示词

稳定输出优美风景壁纸的Midjourney prompt提示词。 1\在夏夜&#xff0c;有淡蓝色的星空&#xff0c;海边&#xff0c;流星&#xff0c;烟花&#xff0c;海滩上全是蓝色的玫瑰和绿色的植物&#xff0c;由Ivan Aivazovsky和Dan Mumford&#xff0c;趋势在cgsociety&#xff0c;…

windows2022证书配置.docx

Windows证书的配置 要求两台主机&#xff0c;一台作为域&#xff0c;一台进入域 按要求来选择角色服务 确认之后安装 安装完以后配置证书服务 选择服务 按要求配置 注&#xff1a;此处不用域用户登陆无法使用企业CA 按要求来 创建新的私钥 这几处检查无误后默认即可 有效期…