目錄
項(xiàng)目搭建
初始化three.js基礎(chǔ)代碼
設(shè)置環(huán)境背景
設(shè)置水面樣式
添加天空小島
今天簡(jiǎn)單實(shí)現(xiàn)一個(gè)three.js的小Demo,加強(qiáng)自己對(duì)three知識(shí)的掌握與學(xué)習(xí),只有在項(xiàng)目中才能靈活將所學(xué)知識(shí)運(yùn)用起來(lái),話(huà)不多說(shuō)直接開(kāi)始。
項(xiàng)目搭建
本案例還是借助框架書(shū)寫(xiě)three項(xiàng)目,借用vite構(gòu)建工具搭建react項(xiàng)目,vite這個(gè)構(gòu)建工具如果有不了解的朋友,可以參考我之前對(duì)其講解的文章:vite腳手架的搭建與使用 。搭建完成之后,用編輯器打開(kāi)該項(xiàng)目,在終端執(zhí)行 npm i 安裝一下依賴(lài),安裝完成之后終端在安裝 npm i three 即可。
因?yàn)閞eact在每次頁(yè)面發(fā)生變化時(shí)會(huì)出現(xiàn)執(zhí)行整段代碼,這樣的話(huà)就會(huì)產(chǎn)生不必要的資源擁塞,所以我將three.js代碼單獨(dú)抽離成一個(gè)js文件。具體如下:
import { render } from "./three/水天一色小島.js"
import './App.css'
const App = () => {
return (
<div>
{render()}
</div>
)
}
export default App
當(dāng)然也是有比較設(shè)置一下css樣式,重置一下瀏覽器原本的css樣式,如下:
*{
margin: 0;
padding: 0;
}
body{
background-color: #1e1a20;
}
::-webkit-scrollbar {
display: none;
}
初始化three.js基礎(chǔ)代碼
three.js開(kāi)啟必須用到的基礎(chǔ)代碼如下:
導(dǎo)入three庫(kù):
import * as THREE from 'three'
初始化場(chǎng)景:
const scene = new THREE.Scene()
初始化相機(jī):
const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,2000)
camera.position.set(10,50,120) // 設(shè)置相機(jī)位置
camera.aspect = window.innerWidth / window.innerHeight // 更新攝像頭寬高比例
camera.updateProjectionMatrix() // 更新攝像頭矩陣
scene.add(camera)
初始化渲染器:
const renderer = new THREE.WebGLRenderer({
antialias:true, // 設(shè)置抗鋸齒
})
renderer.outputEncoding = THREE.sRGBEncoding // 告訴渲染器在輸出顏色時(shí)采用sRGB空間的標(biāo)準(zhǔn)渲染格式
renderer.setSize(window.innerWidth,window.innerHeight) // 設(shè)置渲染器的寬高
document.body.appendChild(renderer.domElement) // 將渲染器添加到頁(yè)面中
監(jiān)聽(tīng)屏幕大小的改變,修改渲染器的寬高和相機(jī)的比例:
window.addEventListener("resize",()=>{
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth,window.innerHeight)
})
導(dǎo)入控制器:
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 實(shí)例化控制器
const controls = new OrbitControls(camera,renderer.domElement)
設(shè)置渲染函數(shù):
export function render(){
renderer.render(scene,camera) // 渲染場(chǎng)景
requestAnimationFrame(render) // 引擎自動(dòng)更新渲染器
}
render()
ok,設(shè)置完這些基礎(chǔ)代碼之后,我們可以添加一個(gè)物體進(jìn)行檢驗(yàn)一下,就添加個(gè)平面吧,如下:
// 添加平面
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,可見(jiàn)代碼寫(xiě)的沒(méi)有錯(cuò)誤,接下來(lái)開(kāi)始具體的Demo實(shí)操。
設(shè)置環(huán)境背景
在網(wǎng)上隨便找一張全景圖片,然后進(jìn)行球體的紋理貼圖,代碼如下:
// 創(chuàng)建一個(gè)巨大的天空球體
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)
一開(kāi)始我們是置身在球體外部的,具體效果如下:
如果想我們一開(kāi)始就置身在球體內(nèi)部可以進(jìn)行如下操作:
設(shè)置視頻紋理:除了設(shè)置圖片紋理外,我們也可以設(shè)置一下視頻紋理,如下:
// 設(shè)置視頻紋理
const video = document.createElement("video")
video.src = "./src/public/sky.mp4" // 視頻路徑
video.loop = true // 循環(huán)播放
window,addEventListener("click",(e)=>{
// 判斷視頻是否處于播放狀態(tài)
if(video.paused){
video.play()
skyMaterial.map = new THREE.VideoTexture(video)
skyMaterial.map.needsUpdate = true
}
})
設(shè)置水面樣式
這里借助three庫(kù)中Water來(lái)實(shí)現(xiàn)水面波紋的效果,如下:
// 導(dǎo)入水面
import { Water } from "three/examples/jsm/objects/Water2"
// 創(chuàng)建平面
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)
這里有個(gè)坑,如果想實(shí)現(xiàn)這種波紋效果的話(huà),需要自行提供波紋的紋理貼圖,并提供特定的路徑,如果路徑不對(duì)的話(huà)是否爆出如下錯(cuò)誤的,如下:
添加天空小島
導(dǎo)入gltf載入庫(kù):
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"
import { DRACOLoader } from 'three/examples/jsm/loaders/dracoloader'
添加小島模型:
const loader = new GLTFLoader() // 實(shí)例化gltf載入庫(kù)
const dracoLoader = new DRACOLoader() // 實(shí)例化draco載入庫(kù)
dracoLoader.setDecoderPath("/draco/") // 添加draco載入庫(kù)
loader.setDRACOLoader(dracoLoader) // 添加draco載入庫(kù)
loader.load("./model/island2.glb",(gltf)=>{
scene.add(gltf.scene)
})
這里需要設(shè)置一下環(huán)境紋理來(lái)顯示具體樣式:
import { DRACOLoader } from 'three/examples/jsm/loaders/dracoloader'
import { RGBELoader } from 'three/examples/jsm/loaders/rgbeloader'
// 載入環(huán)境紋理
const hdrLoader = new RGBELoader()
hdrLoader.loadAsync("./src/public/050.hdr").then((texture)=>{
texture.mapping = THREE.EquirectangularReflectionMapping
scene.background = texture
scene.environment = texture
})
// 添加環(huán)境光
const light = new THREE.DirectionalLight(0xffffff,1)
light.position.set(-100,100,10)
scene.add(light)
最后實(shí)現(xiàn)的效果如下:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-448943.html
ok,今天的three.js小案例就講到這,給出本文的代碼筆記: (獲取素材也可以私信博主)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-448943.html
/* eslint-disable no-unused-vars */
import * as THREE from 'three'
// 導(dǎo)入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 導(dǎo)入水面
import { Water } from "three/examples/jsm/objects/Water2"
// 導(dǎo)入gltf載入庫(kù)
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"
import { DRACOLoader } from 'three/examples/jsm/loaders/dracoloader'
import { RGBELoader } from 'three/examples/jsm/loaders/rgbeloader'
// 初始化場(chǎng)景
const scene = new THREE.Scene()
// 初始化相機(jī)
const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,2000)
camera.position.set(10,50,120) // 設(shè)置相機(jī)位置
camera.aspect = window.innerWidth / window.innerHeight // 更新攝像頭寬高比例
camera.updateProjectionMatrix() // 更新攝像頭矩陣
scene.add(camera)
// 初始化渲染器
const renderer = new THREE.WebGLRenderer({
antialias:true, // 設(shè)置抗鋸齒
logarithmicDepthBuffer: true // 對(duì)數(shù)深度緩沖區(qū)
})
renderer.outputEncoding = THREE.sRGBEncoding // 告訴渲染器在輸出顏色時(shí)采用sRGB空間的標(biāo)準(zhǔn)渲染格式
renderer.setSize(window.innerWidth,window.innerHeight) // 設(shè)置渲染器的寬高
document.body.appendChild(renderer.domElement) // 將渲染器添加到頁(yè)面中
// 監(jiān)聽(tīng)屏幕大小的改變,修改渲染器的寬高和相機(jī)的比例
window.addEventListener("resize",()=>{
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth,window.innerHeight)
})
// 實(shí)例化控制器
const controls = new OrbitControls(camera,renderer.domElement)
// 設(shè)置渲染函數(shù)
export function render(){
renderer.render(scene,camera) // 渲染場(chǎng)景
requestAnimationFrame(render) // 引擎自動(dòng)更新渲染器
}
render()
// 創(chuàng)建一個(gè)巨大的天空球體
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)
// 設(shè)置視頻紋理
const video = document.createElement("video")
video.src = "./src/public/sky.mp4" // 視頻路徑
video.loop = true // 循環(huán)播放
window,addEventListener("click",(e)=>{
// 判斷視頻是否處于播放狀態(tài)
if(video.paused){
video.play()
let texture = new THREE.VideoTexture(video)
skyMaterial.map = texture
skyMaterial.map.needsUpdate = true
scene.background = texture
scene.environment = texture
}
})
// 載入環(huán)境紋理
const hdrLoader = new RGBELoader()
hdrLoader.loadAsync("./src/public/050.hdr").then((texture)=>{
texture.mapping = THREE.EquirectangularReflectionMapping
scene.background = texture
scene.environment = texture
})
// 添加環(huán)境光
const light = new THREE.DirectionalLight(0xffffff,1)
light.position.set(-100,100,10)
scene.add(light)
// 創(chuàng)建平面
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() // 實(shí)例化gltf載入庫(kù)
const dracoLoader = new DRACOLoader() // 實(shí)例化draco載入庫(kù)
dracoLoader.setDecoderPath("/draco/") // 添加draco載入庫(kù)
loader.setDRACOLoader(dracoLoader) // 添加draco載入庫(kù)
loader.load("./model/island2.glb",(gltf)=>{
scene.add(gltf.scene)
})
到了這里,關(guān)于Three.js--》實(shí)現(xiàn)3d小島模型搭建的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!