Three.js--》实现3d小岛模型搭建

news/2024/10/22 18:43:28/

目录

项目搭建

初始化three.js基础代码

设置环境背景

设置水面样式

添加天空小岛


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

项目搭建

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

因为react在每次页面发生变化时会出现执行整段代码,这样的话就会产生不必要的资源拥塞,所以我将three.js代码单独抽离成一个js文件。具体如下:

import { render } from "./three/水天一色小岛.js"
import './App.css'
const App = () => {return (<div>{render()}</div>)
}
export default App

当然也是有比较设置一下css样式,重置一下浏览器原本的css样式,如下:

*{margin: 0;padding: 0;
}
body{background-color: #1e1a20;
}
::-webkit-scrollbar {display: none;
}

初始化three.js基础代码

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

导入three库

import * as THREE from 'three'

初始化场景

const scene = new THREE.Scene()

初始化相机

const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,2000)
camera.position.set(10,50,120) // 设置相机位置
camera.aspect = window.innerWidth / window.innerHeight // 更新摄像头宽高比例
camera.updateProjectionMatrix() // 更新摄像头矩阵
scene.add(camera)

初始化渲染器

const renderer = new THREE.WebGLRenderer({antialias:true, // 设置抗锯齿})
renderer.outputEncoding = THREE.sRGBEncoding // 告诉渲染器在输出颜色时采用sRGB空间的标准渲染格式
renderer.setSize(window.innerWidth,window.innerHeight) // 设置渲染器的宽高
document.body.appendChild(renderer.domElement) // 将渲染器添加到页面中

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

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

导入控制器

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 实例化控制器
const controls = new OrbitControls(camera,renderer.domElement)

设置渲染函数

export function render(){renderer.render(scene,camera) // 渲染场景requestAnimationFrame(render) // 引擎自动更新渲染器
}
render()

ok,设置完这些基础代码之后,我们可以添加一个物体进行检验一下,就添加个平面吧,如下:

// 添加平面
const planeGeometry = new THREE.PlaneGeometry(100,100)
const planeMaterial = new THREE.MeshBasicMaterial({color:0xffffff
})
const plane = new THREE.Mesh(planeGeometry,planeMaterial)
scene.add(plane)

ok,可见代码写的没有错误,接下来开始具体的Demo实操。

设置环境背景

在网上随便找一张全景图片,然后进行球体的纹理贴图,代码如下:

// 创建一个巨大的天空球体
const skyGeometry = new THREE.SphereGeometry(1000,60,60)
const skyMaterial = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('./src/public/starry-sky2.jpg')
})
const sky = new THREE.Mesh(skyGeometry,skyMaterial)
scene.add(sky)

一开始我们是置身在球体外部的,具体效果如下:

如果想我们一开始就置身在球体内部可以进行如下操作:

设置视频纹理:除了设置图片纹理外,我们也可以设置一下视频纹理,如下:

// 设置视频纹理
const video = document.createElement("video")
video.src = "./src/public/sky.mp4" // 视频路径
video.loop = true // 循环播放
window,addEventListener("click",(e)=>{// 判断视频是否处于播放状态if(video.paused){video.play()skyMaterial.map = new THREE.VideoTexture(video)skyMaterial.map.needsUpdate = true}
})

设置水面样式

这里借助three库中Water来实现水面波纹的效果,如下:

// 导入水面
import { Water } from "three/examples/jsm/objects/Water2"
// 创建平面
const waterGeometry = new THREE.CircleGeometry(300,64)
const water = new Water(waterGeometry,{textureWidth: 1024,textureHeight: 1024,color:0x0080ff,scale: 1,
})
water.rotation.x = -Math.PI / 2
scene.add(water)

这里有个坑,如果想实现这种波纹效果的话,需要自行提供波纹的纹理贴图,并提供特定的路径,如果路径不对的话是否爆出如下错误的,如下:

添加天空小岛

导入gltf载入库

import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"
import { DRACOLoader } from 'three/examples/jsm/loaders/dracoloader'

添加小岛模型

const loader = new GLTFLoader() // 实例化gltf载入库
const dracoLoader = new DRACOLoader() // 实例化draco载入库
dracoLoader.setDecoderPath("/draco/") // 添加draco载入库
loader.setDRACOLoader(dracoLoader) // 添加draco载入库loader.load("./model/island2.glb",(gltf)=>{scene.add(gltf.scene)
})

这里需要设置一下环境纹理来显示具体样式

import { DRACOLoader } from 'three/examples/jsm/loaders/dracoloader'
import { RGBELoader } from 'three/examples/jsm/loaders/rgbeloader'
// 载入环境纹理
const hdrLoader = new RGBELoader()
hdrLoader.loadAsync("./src/public/050.hdr").then((texture)=>{texture.mapping = THREE.EquirectangularReflectionMappingscene.background = texturescene.environment = texture
})// 添加环境光
const light = new THREE.DirectionalLight(0xffffff,1)
light.position.set(-100,100,10)
scene.add(light)

最后实现的效果如下:

ok,今天的three.js小案例就讲到这,给出本文的代码笔记: (获取素材也可以私信博主)

/* eslint-disable no-unused-vars */
import * as THREE from 'three'
// 导入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 导入水面
import { Water } from "three/examples/jsm/objects/Water2"
// 导入gltf载入库
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"
import { DRACOLoader } from 'three/examples/jsm/loaders/dracoloader'
import { RGBELoader } from 'three/examples/jsm/loaders/rgbeloader'// 初始化场景
const scene = new THREE.Scene()
// 初始化相机
const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,2000)
camera.position.set(10,50,120) // 设置相机位置
camera.aspect = window.innerWidth / window.innerHeight // 更新摄像头宽高比例
camera.updateProjectionMatrix() // 更新摄像头矩阵
scene.add(camera)
// 初始化渲染器
const renderer = new THREE.WebGLRenderer({antialias:true, // 设置抗锯齿logarithmicDepthBuffer: true // 对数深度缓冲区
})
renderer.outputEncoding = THREE.sRGBEncoding // 告诉渲染器在输出颜色时采用sRGB空间的标准渲染格式
renderer.setSize(window.innerWidth,window.innerHeight) // 设置渲染器的宽高
document.body.appendChild(renderer.domElement) // 将渲染器添加到页面中// 监听屏幕大小的改变,修改渲染器的宽高和相机的比例
window.addEventListener("resize",()=>{camera.aspect = window.innerWidth / window.innerHeightcamera.updateProjectionMatrix()renderer.setSize(window.innerWidth,window.innerHeight)
})// 实例化控制器
const controls = new OrbitControls(camera,renderer.domElement)// 设置渲染函数
export function render(){renderer.render(scene,camera) // 渲染场景requestAnimationFrame(render) // 引擎自动更新渲染器
}
render()// 创建一个巨大的天空球体
let texture = new THREE.TextureLoader().load('./src/public/starry-sky2.jpg')
const skyGeometry = new THREE.SphereGeometry(1000,30,30)
const skyMaterial = new THREE.MeshBasicMaterial({map: texture
})
skyGeometry.scale(1,1,-1)
const sky = new THREE.Mesh(skyGeometry,skyMaterial)
scene.add(sky)// 设置视频纹理
const video = document.createElement("video")
video.src = "./src/public/sky.mp4" // 视频路径
video.loop = true // 循环播放
window,addEventListener("click",(e)=>{// 判断视频是否处于播放状态if(video.paused){video.play()let texture = new THREE.VideoTexture(video)skyMaterial.map = textureskyMaterial.map.needsUpdate = truescene.background = texturescene.environment = texture}
})// 载入环境纹理
const hdrLoader = new RGBELoader()
hdrLoader.loadAsync("./src/public/050.hdr").then((texture)=>{texture.mapping = THREE.EquirectangularReflectionMappingscene.background = texturescene.environment = texture
})// 添加环境光
const light = new THREE.DirectionalLight(0xffffff,1)
light.position.set(-100,100,10)
scene.add(light)// 创建平面
const waterGeometry = new THREE.CircleGeometry(300,64)
const water = new Water(waterGeometry,{textureWidth: 1024,textureHeight: 1024,color:0xeeeeff,scale: 1,
})
water.position.y = 3
water.rotation.x = -Math.PI / 2
scene.add(water)// 添加小岛模型
const loader = new GLTFLoader() // 实例化gltf载入库
const dracoLoader = new DRACOLoader() // 实例化draco载入库
dracoLoader.setDecoderPath("/draco/") // 添加draco载入库
loader.setDRACOLoader(dracoLoader) // 添加draco载入库loader.load("./model/island2.glb",(gltf)=>{scene.add(gltf.scene)
})

http://www.ppmy.cn/news/79047.html

相关文章

NFT游戏Mythical Beings将参加NFT Polygon 在线展会

Mythical Beings神秘生物是由Tarasca Art & Games 开发的基于区块链的卡牌收集游戏。游戏中每张卡牌所拥有的属性和背后的故事都是独一无二的&#xff0c;Mythical Beings不仅具有游戏属性&#xff0c;还兼具故事的传承。 作为一款跨链Polygon的NFT游戏&#xff0c;Mythic…

多态的应用

多态的应用 1.多态的构建&#xff1a; ​ 自我理解&#xff1a;就是 父类引用指向子类对象。 功能 &#xff1a; 父类能调用父类对应子类的方法和属性&#xff0c;但是都是优先调用 重写的方法 或 子类的属性&#xff01; 创建子类构造器&#xff0c;就是先进入子类构造器&…

花指令问题

前言 想起之前打题的时候经常会遇到一些关乎花指令的问题&#xff0c;但是没有系统地总结归纳花指令去除的姿势&#xff0c;浅浅开一个坑慢慢来写 题1&#xff1a;简单jmp 可以骗过dbg&#xff0c;但是放在ida中就很容易看出来&#xff0c;无效跳转 题目来源&#xff1a;[HD…

【Android笔记103】Android之自动完成文本框组件(AutoCompleteTextView、MultiAutoCompleteTextView)

这篇文章,主要介绍Android之自动完成文本框组件(AutoCompleteTextView、MultiAutoCompleteTextView)。 目录 一、AutoCompleteTextView组件 1.1、运行效果 1.2、案例代码 (1)布局文件

【C++刷题集】-- day3

目录 选择题 单选 OR59 字符串中找出连续最长的数字串⭐ 【题目解析】 【解题思路】 JZ39 数组中出现次数超过一半的数字⭐ 【题目解析】 【解题思路1】 【解题思路2】 选择题 单选 1、以下程序的输出结果是 ( ) #include <stdio.h> int main() {char a[10] …

CodeForces.1786A2.发牌.[中等][flg标识][数学规律][双色牌]

题目描述&#xff1a; 题目解读&#xff1a; 发牌问题&#xff0c;给两人发双色牌&#xff0c;同样还是 给a发1张&#xff0c;然后给b发2&#xff0c;3张&#xff1b; 给a发4&#xff0c;5张&#xff0c;给b发6&#xff0c;7张&#xff1b; 给a发8&#xff0c;9张&#xff…

mac 切换java jdk版本 java8 java11

1. 终端执行命令 查看本地各版本jdk&#xff1a;mac通常默认安装了jdk1.8 安装目录是 /Library/Java/JavaVirtualMachines/ cd /Library/Java/JavaVirtualMachines/ ls 2. 上述命令列出的各版本目录名 后&#xff0c;在全局配置文件.bash_profile中新增上面命令列出的各…

分布式事务解决方案-Seata

分布式事务解决方案-Seata 1.分布式事务问题1.1.本地事务1.2.分布式事务1.3.演示分布式事务问题 2.理论基础2.1.CAP定理2.1.1.一致性2.1.2.可用性2.1.3.分区容错2.1.4.矛盾 2.2.BASE理论2.3.解决分布式事务的思路 3.初识Seata3.1.Seata的架构3.2.部署TC服务3.3.微服务集成Seata…