Three.Js實現(xiàn)看房自由小項目
一、前言
概述:基于WebGL的三維引擎,目前是國內(nèi)資料最多、使用最廣泛的三維引擎,可以制作一些3D可視化項目

目前隨著元宇宙概念的爆火,THREE技術(shù)已經(jīng)深入到了物聯(lián)網(wǎng)、VR、游戲、數(shù)據(jù)可視化等多個平臺,今天我們主要基于THREE實現(xiàn)一個三維的VR看房小項目
二、基礎(chǔ)知識

Three.js一般分為三個部分:場景、相機、渲染器,這三個主要的分支就構(gòu)成了THREE.JS的主要功能區(qū),這三大部分還有許多細小的分支,這些留到我們后續(xù)抽出一些章節(jié)專門講解一下。

工作流程:場景——相機——渲染器
從實際生活中拍照角度立方體網(wǎng)格模型和光照組成了一個虛擬的三維場景,相機對象就像你生活中使用的相機一樣可以拍照,只不過一個是拍攝真實的景物,一個是拍攝虛擬的景物。拍攝一個物體的時候相機的位置和角度需要設置,虛擬的相機還需要設置投影方式,當你創(chuàng)建好一個三維場景,相機也設置好,就差一個動作“咔”,通過渲染器就可以執(zhí)行拍照動作。
三、場景
概述:場景主要由網(wǎng)絡模型與光照組成,網(wǎng)絡模型分為幾何體與材質(zhì)
3.1 網(wǎng)絡模型
幾何體就像我們小時候?qū)W我們就知道點線面體四種概念,點動成線,線動成面,面動成體,而材質(zhì)就像是是幾何體上面的涂鴉,有不同的顏色、圖案…
例子如下:

//打造酷炫三角形
for (let i = 0; i < 50; i++) {
const geometry = new THREE.BufferGeometry();
const arr = new Float32Array(9);
for (let j = 0; j < 9; j++) {
arr[j] = Math.random() * 5;
}
geometry.setAttribute('position', new THREE.BufferAttribute(arr, 3));
let randomColor = new THREE.Color(Math.random(), Math.random(), Math.random());
const material = new THREE.MeshBasicMaterial({
color: randomColor,
transparent: true,
opacity:0.5,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}

const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshStandardMaterial({ color: 0x0000ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

const geometry = new THREE.ConeGeometry(5, 15, 32);//底面半徑 高 側(cè)邊三角分段
const material = new THREE.MeshStandardMaterial({ color: 0x0000ff });
const clone = new THREE.Mesh(geometry, material);
scene.add(clone);
3.2 光照
3.2.1 環(huán)境光
概念:光照對three.js的物體全表面進行光照測試,有可能會發(fā)生光照融合

//環(huán)境光 const ambient = new THREE.AmbientLight(0x404040); scene.add(ambient);
3.2.2 平行光
概念:向特定方向發(fā)射的光,太陽光也視作平行的一種,和上面比較,物體變亮了
//平行光 顏色 強度 const directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(100, 100, 100);//光源位置 directionalLight.target = cube;//光源目標 默認 0 0 0 scene.add(directionalLight);
3.2.3 點光源
概念:由中間向四周發(fā)射光、強度比平行光小

// 顏色 強度 距離 衰退量(默認1) const pointLight = new THREE.PointLight(0xff0000, 1, 100, 1); pointLight.position.set(50, 50, 50); scene.add(pointLight);
3.2.4 聚光燈
概念:家里面的節(jié)能燈泡,強度較好

//聚光燈 const spotLigth = new THREE.PointLight(0xffffff); spotLigth.position.set(50, 50, 50); spotLigth.target = cube; spotLigth.angle = Math.PI / 6; scene.add(spotLigth);
3.2.5 半球光
概念:光源直接放置于場景之上,光照顏色從天空光線顏色漸變到地面光線顏色

//半球光 const light = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);//天空 場景 scene.add(light);
四、相機
4.1 正交相機

| 參數(shù)(屬性) | 含義 |
|---|---|
| left | 渲染空間的左邊界 |
| right | 渲染空間的右邊界 |
| top | 渲染空間的上邊界 |
| bottom | 渲染空間的下邊界 |
| near | near屬性表示的是從距離相機多遠的位置開始渲染,一般情況會設置一個很小的值。 默認值0.1 |
| far | far屬性表示的是距離相機多遠的位置截止渲染,如果設置的值偏小小,會有部分場景看不到。 默認值1000 |
let width = window.innerWidth; let height = window.innerHeight; const camera = new THREE.OrthographicCamera(width / - 2, width / 2, height / 2, height / - 2, 1, 1000); scene.add(camera); camera.position.set(100, 200, 100);
4.2 透視相機

| 參數(shù) | 含義 | 默認值 |
|---|---|---|
| fov | fov表示視場,所謂視場就是能夠看到的角度范圍,人的眼睛大約能夠看到180度的視場,視角大小設置要根據(jù)具體應用,一般游戲會設置60~90度 | 45 |
| aspect | aspect表示渲染窗口的長寬比,如果一個網(wǎng)頁上只有一個全屏的canvas畫布且畫布上只有一個窗口,那么aspect的值就是網(wǎng)頁窗口客戶區(qū)的寬高比 | window.innerWidth/window.innerHeight |
| near | near屬性表示的是從距離相機多遠的位置開始渲染,一般情況會設置一個很小的值。 | 0.1 |
| far | far屬性表示的是距離相機多遠的位置截止渲染,如果設置的值偏小,會有部分場景看不到 | 1000 |
let width = window.innerWidth; let height = window.innerHeight; const camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000); camera.position.set(150, 100, 300); camera.lookAt(scene.position);
五、渲染器
概述:從WEBGL的角度來看,three就是對它的進一步封裝,想要進一步了解渲染器這方面的知識點還需要了解一下WEBGL,這里我們就不做過多介紹了。
六、貼圖紋理
6.1 基礎(chǔ)介紹
概述:這部分對于我們是否能夠給別人呈現(xiàn)一個真實的渲染場景來說,很重要,比如下面一個普普通通的正方體,我們只要一加上貼圖,立馬不一樣了。
以前

之后

6.2 環(huán)境貼圖
概述:目前有許許多多的貼圖,比如基礎(chǔ)、透明、環(huán)境、法線、金屬、粗糙、置換等等,今天我們呢主要講解一下環(huán)境和一點 HDR處理
在THREE的世界里面,坐標抽x、y、z的位置關(guān)系圖如下所示:

紅、綠、藍分別代表x、z、y,我們的貼圖就是在px nx py ny pz nz這六個方向防止一張圖片,其中p就代表坐標軸的正方向
CubeTextureLoader:加載CubeTexture的一個類。 內(nèi)部使用ImageLoader來加載文件。
//場景貼圖
const sphereTexture = new THREE.CubeTextureLoader().setPath('./textures/course/environmentMaps/0/');
const envTexture= sphereTexture.load([
'px.jpg',
'nx.jpg',
'py.jpg',
'ny.jpg',
'pz.jpg',
'nz.jpg'
]);
//場景添加背景
scene.background = envTexture;
//場景的物體添加環(huán)境貼圖(無默認情況使用)
scene.environment = envTexture;
const sphereGeometry = new THREE.SphereGeometry(5, 30, 30);
const sphereMaterial = new THREE.MeshStandardMaterial({
roughness: 0,//設置粗糙程度
metalness: 1,//金屬度
envMap:envTexture,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);gif圖片有點大上傳不了,我就截了幾張圖





6.3 HDR處理
概述:高動態(tài)范圍圖像,相比普通的圖像,能夠提供更多的動態(tài)范圍和圖像細節(jié),一般被運用于電視顯示產(chǎn)品以及圖片視頻拍攝制作當中。

import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader;
const rgbeLoader = new RGBELoader().setPath('./textures/course/hdr/');
//異步加載
rgbeLoader.loadAsync('002.hdr').then((texture) => {
//設置加載方式 等距圓柱投影的環(huán)境貼圖
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
})
七、拓展
7.1 坐標系
概述:坐標軸能夠更好的反饋物體的位置信息,紅、綠、藍分別代表x、z、y

const axesHelper = new THREE.AxesHelper(20);//里面的數(shù)字代表坐標抽長度 scene.add(axesHelper);
7.2 控制器
概述:通過鼠標控制物體和相機的移動、旋轉(zhuǎn)、縮放
導包
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
應用
const controls = new OrbitControls(camera, renderer.domElement)
自旋轉(zhuǎn)

controls.autoRotate = true
必須在render函數(shù)調(diào)用update實時更新才奏效
7.3 自適應
概述:根據(jù)屏幕大小自適應場景

//自適應屏幕
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(window.devicePixelRatio)
})
設置相機的寬高比、重新更新渲染相機、渲染器的渲染大小、設備的像素比
7.4 全屏響應
概述:雙擊進入全屏,再次雙擊/ESC退出全屏

window.addEventListener('dblclick', () => {
let isFullScreen = document.fullscreenElement
if (!isFullScreen) {
renderer.domElement.requestFullscreen()
}
else {
document.exitFullscreen()
}
})
7.5 信息面板
概述;通過操作面板完成界面的移動物體的相關(guān)應用
鏈接:https://www.npmjs.com/package/dat.gui
//安裝npm npm install --save dat.gui //如果出現(xiàn)...標記錯誤,安裝到開發(fā)依賴就可以了 npm i --save-dev @types/dat.gui

//界面操作
const gui = new dat.GUI();
//操作物體位置
gui
.add(cube.position, 'x')
.min(0)
.max(10)
.step(0.1)
.name('X軸移動')
.onChange((value) => {
console.log('修改的值為' + value);
})
.onFinishChange((value) => {
console.log('完全停止' + value);
});
//操作物體顏色
const colors = {
color: '#0000ff',
};
gui
.addColor(colors, 'color')
.onChange((value) => {
//修改物體顏色
cube.material.color.set(value);
});
7.6 頻率檢測
概述:檢測幀率
導包
import Stats from 'three/addons/libs/stats.module.js';
應用
const stats = new Stats(); document.body.appendChild(stats.dom);
自變化

stats.update()
必須在render函數(shù)調(diào)用update實時更新才奏效
7.7 導航網(wǎng)格
概述:底部二維平面的網(wǎng)格化,幫助我們更好的創(chuàng)建場景

const gridHelper = new THREE.GridHelper(10, 20)//網(wǎng)格大小、細分次數(shù) scene.add(gridHelper)
八、源碼
//導入包
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import * as dat from 'dat.gui';
import Stats from 'three/addons/libs/stats.module.js';
let scene,camera,renderer
//場景
scene = new THREE.Scene();
//坐標抽
const axesHelper = new THREE.AxesHelper(20);
scene.add(axesHelper);
//場景貼圖
const sphereTexture = new THREE.CubeTextureLoader().setPath('./textures/course/environmentMaps/0/');
const envTexture= sphereTexture.load([
'px.jpg',
'nx.jpg',
'py.jpg',
'ny.jpg',
'pz.jpg',
'nz.jpg'
]);
//場景添加背景
scene.background = envTexture;
//場景的物體添加環(huán)境貼圖(無默認情況使用)
scene.environment = envTexture;
const sphereGeometry = new THREE.SphereGeometry(5, 30, 30);
const sphereMaterial = new THREE.MeshStandardMaterial({
roughness: 0,//設置粗糙程度
metalness: 1,//金屬度
envMap:envTexture,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);
//光照
const ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.05);
directionalLight.position.set(10,10,10);
directionalLight.lookAt(scene.position);
scene.add( directionalLight );
//相機
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
2000,
);
camera.position.set(10,10,20);
camera.lookAt(scene.position);
scene.add(camera);
//渲染器
renderer = new THREE.WebGLRenderer({
//防止鋸齒
antialias: true,
});
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.setClearColor(0xb9d3ff, 1);
document.body.appendChild(renderer.domElement);
//鼠標控制器
const controls = new OrbitControls(camera, renderer.domElement);
//阻尼 必須在 render函數(shù)調(diào)用 controls.update();
controls.dampingFactor = true;
controls.autoRotate=true
const stats=new Stats()
document.body.appendChild(stats.dom);
function render () {
renderer.render(scene, camera);
requestAnimationFrame(render);
controls.update();//調(diào)用
stats.update()
}
render();
//全屏操作
window.addEventListener('dblclick', () => {
//查詢是否全屏
let isFullScene = document.fullscreenElement;
console.log(isFullScene);
if (!isFullScene) {
renderer.domElement.requestFullscreen();
}
else {
document.exitFullscreen();
}
})
//自適應
window.addEventListener('resize', () => {
//寬高比
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);//設置像素比
})
//界面操作
const gui = new dat.GUI();
//操作物體位置
gui
.add(sphere.position, 'x')
.min(0)
.max(10)
.step(0.1)
.name('X軸移動')
.onChange((value) => {
console.log('修改的值為' + value);
})
.onFinishChange((value) => {
console.log('完全停止' + value);
});
//操作物體顏色
const colors = {
color: '#0000ff',
};
gui
.addColor(colors, 'color')
.onChange((value) => {
//修改物體顏色
sphere.material.color.set(value);
});
到此這篇關(guān)于Three.Js實現(xiàn)看房自由的文章就介紹到這了,更多相關(guān)three.js看房內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js和jquery對dom節(jié)點的操作(創(chuàng)建/追加)
本文詳細介紹下js和jquery對dom節(jié)點的操作包括創(chuàng)建、追加等等,感興趣的朋友可以參考下哈,希望對你有所幫助2013-04-04
用javascript實現(xiàn)的激活輸入框后隱藏初始內(nèi)容
用javascript實現(xiàn)的激活輸入框后隱藏初始內(nèi)容...2007-06-06

