網(wǎng)站建設(shè)與管理專業(yè)的行業(yè)發(fā)展磁力bt種子搜索
文章:
- Three——一、初識(shí)Three以及基礎(chǔ)的前端場(chǎng)景搭建(結(jié)尾含源碼)
- Three——二、加強(qiáng)對(duì)三維空間的認(rèn)識(shí)
- Three——三、動(dòng)畫執(zhí)行、畫布大小、渲染幀率和相機(jī)適配體驗(yàn)
- Three——四、幾何體、高光網(wǎng)絡(luò)材質(zhì)、鋸齒模糊以及GUI庫(kù)的使用
- Three——五、點(diǎn)線模型對(duì)象、三角形概念、幾何體頂點(diǎn)位置,頂點(diǎn)索引、法線以及對(duì)幾何體進(jìn)行旋轉(zhuǎn)縮放和平移
Threejs 常見(jiàn)幾何體簡(jiǎn)介
Three.js 常見(jiàn)的幾何體:
常見(jiàn)的幾何體:
//BoxGeometry:長(zhǎng)方體
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球體
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry:圓柱
const geometry = new THREE.CylinderGeometry(50, 50, 100);
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100, 50);
// CircleGeometry:圓形平面
const geometry = new THREE.CircleGeometry(50);
這里拿平面做示例:
雙面可見(jiàn)
Three.js 的材質(zhì)默認(rèn)正面可見(jiàn),反面不可見(jiàn),對(duì)于矩形平面PlaneGeometry
、圓形平面如果你想看到兩面,可以設(shè)置side: THREE.DoubleSide
。
new THREE.MeshBasicMaterial({side: THREE.FrontSide, //默認(rèn)只有正面可見(jiàn)
});
new THREE.MeshBasicMaterial({side: THREE.DoubleSide, //兩面可見(jiàn)
});
高光網(wǎng)絡(luò)材質(zhì)
高光網(wǎng)格材質(zhì)MeshPhongMaterial
和基礎(chǔ)網(wǎng)格材質(zhì)MeshBasicMaterial
、漫反射網(wǎng)格材質(zhì)MeshLambertMaterial
一樣都是網(wǎng)格模型的 Mesh 的材質(zhì)。
注意:高光網(wǎng)格材質(zhì)MeshPhongMaterial
和漫反射網(wǎng)格材質(zhì)MeshLambertMaterial
一樣會(huì)受到光照的影響。
MeshPhongMaterial 對(duì)光照反射特點(diǎn)
MeshPhongMaterial
和MeshLambertMaterial
都會(huì)收到光照的影響區(qū)別在于,對(duì)光線反射方式有差異。
MeshPhongMaterial
可以實(shí)現(xiàn)高光反射效果,而MeshLamberMaterial
恰恰相反。所謂的高光,就比如你在一個(gè)太陽(yáng)下方去看一個(gè)小汽車,你會(huì)在特定的角度及位置看到玻璃表面某個(gè)位置特別亮。
鏡面反射與漫反射
MeshPhongMaterial
可以提供一個(gè)鏡面的反射效果,可以類比你生活中拿一面鏡子,放在太陽(yáng)光下,調(diào)整角度,可以把太陽(yáng)光反射到其它地方,如果反射光對(duì)著眼睛,也就是反射光線和視線平行的時(shí)候,會(huì)非常刺眼。
MeshLambertMaterial
對(duì)應(yīng)的 Mesh 受到光線照射,沒(méi)有鏡面反射的效果,只是一個(gè)漫反射,也就是光線向四周反射。
高光亮度屬性shininess
通過(guò)MeshPhongMaterial
的高光亮度shininess
屬性,可以控制高光反射效果
// 模擬鏡面反射,產(chǎn)生一個(gè)高光效果
const material = new THREE.MeshPhongMaterial({color: 0x00ffff,shininess: 500, //高光部分的亮度,默認(rèn)30
});
數(shù)字越大,光越亮
對(duì)比效果:
下面是使用MeshLambertMaterial
材質(zhì)的效果:
WebGL 渲染器設(shè)置(鋸齒模糊)
設(shè)置渲染器鋸齒屬性:antialias
const renderer = new THREE.WebGLRenderer({antialias: true,
});
對(duì)比:
設(shè)置背景的兩種方式
scene.background = new THREE.Color(0xaaaaaa);
// or
// renderer.setClearColor(0xffffff, 1); //設(shè)置背景顏色
gui.js 庫(kù)
簡(jiǎn)介
借助gui.js可以快速創(chuàng)建控制三維場(chǎng)景的UI交互界面
gihtub地址:https://github.com/dataarts/dat.gui
npm地址:https://www.npmjs.com/package/dat.gui
three中自帶了gui庫(kù)
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
創(chuàng)建 GUI 對(duì)象
const gui = new GUI();
通過(guò)domElement
改變 GUI 界面默認(rèn)的 style 屬性
嘗試改變他的位置和長(zhǎng)度
const gui = new GUI();
gui.domElement.style.right = "0px";
gui.domElement.style.width = "300px";
add()方法
add()
方法可以創(chuàng)建一個(gè)交互界面,例如滾動(dòng)條,從而改變 js 對(duì)象屬性的屬性值
.add(控制對(duì)象,對(duì)象具體屬性,其它參數(shù))
其他參數(shù),可以一個(gè)或多個(gè),數(shù)據(jù)類型也可以不同,gui 會(huì)自動(dòng)根據(jù)參數(shù)形式,自動(dòng)生成對(duì)應(yīng)的交互界面。
參數(shù) 3 和參數(shù) 4,分別是一個(gè)數(shù)字,交互界面是一個(gè)鼠標(biāo)可以拖動(dòng)的拖動(dòng)條,可以在一個(gè)區(qū)間改變屬性的值
const obj = {x: 30,
};
gui.add(obj, "x", 0, 100);
gui 改變 js 對(duì)象多個(gè)屬性
const obj = {x: 30,y: 60,z: 300,
};
// gui界面上增加交互界面,改變obj對(duì)應(yīng)屬性
gui.add(obj, "x", 0, 100);
gui.add(obj, "y", 0, 50);
gui.add(obj, "z", 0, 60);
通過(guò) gui 改變 threejs 光照強(qiáng)度測(cè)試
給光源綁定intensity
屬性,通過(guò) gui 的拖動(dòng)條來(lái)改變光源屬性
// 需要光源和光源位置信息
// const pointLight = new THREE.PointLight(0xffffff, 1.0);
// pointLight.position.set(100, 60, 50);gui.add(pointLight, "intensity", 0, 2.0);
scene.add(pointLight);// 光源輔助觀察
// const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
// scene.add(pointLightHelper);
效果:會(huì)將下方綁定模型位置同時(shí)進(jìn)行演示
gui 綁定模型位置
mesh.position
是 JavaScript 對(duì)象,具有 x、y、z 屬性,這三個(gè)屬性分別表示模型的 xyz 坐標(biāo),這就是說(shuō),gui 改變mesh.position
的 x、y、z 屬性,就可以可視化改變 mesh 的位置。
function guiFun() {gui.add(mesh.position, "x", 0, 100);gui.add(mesh.position, "y", 0, 50);gui.add(mesh.position, "z", 0, 60);
}
效果演示:
name()
name 屬性可以將默認(rèn)值改成所需文字
gui.add(pointLight, "intensity", 0, 2.0).name("光源");
step()步長(zhǎng)
每次拖動(dòng)的間隔
gui.add(pointLight, "intensity", 0, 2.0).name("光源").step(0.1);
onChange()方法
當(dāng) gui 界面某個(gè)值的時(shí)候,.onChange()方法就會(huì)執(zhí)行,這時(shí)候你可以根據(jù)需要通過(guò).onChange()執(zhí)行某些代碼。就是可以將老值被新值替換。
let obj = {x: 30,y: 30,z: 30,
};
gui.add(obj, "x", 0, 180).onChange(function (value) {mesh.position.x = value;
});
gui 改變材質(zhì)顏色
const obj = {color: 0x00ffff,
};
// .addColor()生成顏色值改變的交互界面
gui.addColor(obj, "color").onChange(function (value) {mesh.material.color.set(value);
});
gui 下拉菜單
通過(guò).add()方法創(chuàng)建新的 UI 交互界面,下拉框、單選框
1、 .add()方法參數(shù) 3 和 4 數(shù)據(jù)類型:數(shù)字
此方法如上
add(控制對(duì)象,對(duì)象具體屬性,其他參數(shù))
其他參數(shù),可以一個(gè)或多個(gè),數(shù)據(jù)類型也可以不同,gui 會(huì)自動(dòng)根據(jù)參數(shù)形式,自動(dòng)生成對(duì)應(yīng)的交互界面。
2、.add()方法參數(shù) 3 數(shù)據(jù)類型:數(shù)組
參數(shù) 3 如果是一個(gè)數(shù)組的話,那么他的交互界面是下拉菜單
例如:
const obj = {scale: 0,
};
gui.add(obj, "scale", [-100, 0, 100]).name("x軸坐標(biāo)").onChange(function (value) {mesh.position.x = value;});
3、 .add()方法參數(shù) 3 數(shù)據(jù)類型:對(duì)象
參數(shù) 3 如果為對(duì)象,那么生成的交互界面也會(huì)是下拉菜單
例如:
const obj = {scale: 0,
};
// 參數(shù)3數(shù)據(jù)類型:對(duì)象(下拉菜單)
gui.add(obj, "scale", {left: -100,center: 0,right: 100,// 左: -100,//可以用中文// 中: 0,// 右: 100}).name("位置選擇").onChange(function (value) {mesh.position.x = value;});
4、.add()方法對(duì)應(yīng)屬性的數(shù)據(jù)類型:布爾值
如果.add()
改變屬性的數(shù)據(jù)類型如果是布爾值,那么交互界面就是一個(gè)單選按鈕
例如:
const obj = {bool: false,
};
// 改變的obj屬性數(shù)據(jù)類型是布爾值,交互界面是單選框
gui.add(obj, "bool").name("是否旋轉(zhuǎn)");
gui.add(obj, "bool").onChange(function (value) {// 點(diǎn)擊單選框,控制臺(tái)打印obj.bool變化console.log("obj.bool", value);
});
案例:控制旋轉(zhuǎn)模型
const obj = {bool: false,
};
gui.add(obj, "bool").name("旋轉(zhuǎn)動(dòng)畫");
const render = () => {if (obj.bool) mesh.rotateY(0.01);renderer.render(scene, camera);requestAnimationFrame(render);
};
render();
效果:
gui.js 庫(kù)(分組)
如果頁(yè)面出現(xiàn)控制的屬性較多時(shí),為了避免混合,可以適當(dāng)進(jìn)行分組管理
例如:
const gui = new GUI(); //創(chuàng)建GUI對(duì)象
//創(chuàng)建一個(gè)對(duì)象,對(duì)象屬性的值可以被GUI庫(kù)創(chuàng)建的交互界面改變
const obj = {color: 0x00ffff, // 材質(zhì)顏色specular: 0x111111, // 材質(zhì)高光顏色
};// 材質(zhì)顏色color
gui.addColor(obj, "color").onChange(function (value) {material.color.set(value);
});
// 材質(zhì)高光顏色specular
gui.addColor(obj, "specular").onChange(function (value) {material.specular.set(value);
});// 環(huán)境光強(qiáng)度
gui.add(ambient, "intensity", 0, 2);
// 平行光強(qiáng)度
gui.add(directionalLight, "intensity", 0, 2);
// 平行光位置
gui.add(directionalLight.position, "x", -400, 400);
gui.add(directionalLight.position, "y", -400, 400);
gui.add(directionalLight.position, "z", -400, 400);
使用.addFolder()分組
環(huán)境光子菜單部分
const gui = new GUI();
let obj = {color: 0x00ffff, // 材質(zhì)顏色specular: 0xff0000,
};
const matFolder = gui.addFolder("材質(zhì)");// 材質(zhì)子菜單部分
matFolder.close();
matFolder.addColor(obj, "color").onChange(function (value) {material.color.set(value);console.log(material.specular.set(value));
});
matFolder.addColor(obj, "specular").onChange(function (value) {material.specular.set(value);
});
環(huán)境光子菜單部分
const ambientFolder = gui.addFolder("環(huán)境光");
ambientFolder.add(pointLight, "intensity", 0, 2);
平行光
const dirFolder = gui.addFolder("平行光強(qiáng)度");// 光源輔助觀察
// const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
// scene.add(pointLightHelper);
// const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
// directionalLight.position.set(100, 0, 0);// // 方向光指向?qū)ο缶W(wǎng)格模型mesh,可以不設(shè)置,默認(rèn)的位置是0,0,0
// directionalLight.target = mesh;
// // 輔助觀察
// const dirLightHelper = new THREE.DirectionalLightHelper(
// directionalLight,
// 5,
// 0xff0000
// );
// // 添加輔助標(biāo)識(shí)
// scene.add(dirLightHelper);
// // 添加平行光到場(chǎng)景中
// scene.add(directionalLight);
// 平行光強(qiáng)度
dirFolder.add(directionalLight, "intensity", 0, 2);
// 平行光位置
dirFolder.add(directionalLight.position, "x", -400, 400);
dirFolder.add(directionalLight.position, "y", -400, 400);
dirFolder.add(directionalLight.position, "z", -400, 400);
顯示效果如下:
關(guān)閉.close()和展開.open()交互界面
用.close()
和.open()
方法可以設(shè)置默認(rèn)是否折疊還是展開,默認(rèn)狀態(tài)為open()
// 菜單名稱.close();
dirFolder.close();
matFolder.close();
效果如下:
.addFolder()子菜單嵌套
通過(guò) addFolder 可以再次進(jìn)行 addFolder 完成子菜單嵌套
const dirFolder2 = dirFolder.addFolder("位置"); //子菜單的子菜單
dirFolder.add(directionalLight, "intensity", 0, 2);
const dirFolder2 = dirFolder.addFolder("位置"); //子菜單的子菜單
dirFolder2.close(); //關(guān)閉菜單
// 平行光位置
dirFolder2.add(directionalLight.position, "x", -400, 400);
dirFolder2.add(directionalLight.position, "y", -400, 400);
dirFolder2.add(directionalLight.position, "z", -400, 400);// 平行光位置
dirFolder.add(directionalLight.position, "x", -400, 400);
dirFolder.add(directionalLight.position, "y", -400, 400);
dirFolder.add(directionalLight.position, "z", -400, 400);
dirFolder.close();
至此可以基本的掌握了 three.js 中基本的用法,本專欄只用來(lái)學(xué)習(xí)交流,最后附上示例代碼,詳情可參考郭老師的電子書:http://www.webgl3d.cn/
<!-- author: Mr.J -->
<!-- date: 2023-04-12 11:43:45 -->
<!-- description: Vue3+JS代碼塊模板 -->
<template><div class="container" ref="container"></div>
</template><script setup>import * as THREE from "three";// 軌道import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";import { ref, reactive, onMounted } from "vue";import { GUI } from "three/addons/libs/lil-gui.module.min.js";// 三個(gè)必備的參數(shù)let scene, camera, renderer, controls, mesh, stats, material;import Stats from "three/addons/libs/stats.module.js";// guiconst gui = new GUI();// 旋轉(zhuǎn)控制let obj = {color: 0x00ffff, // 材質(zhì)顏色specular: 0xff0000,};const matFolder = gui.addFolder("材質(zhì)");const ambientFolder = gui.addFolder("環(huán)境光");const dirFolder = gui.addFolder("平行光強(qiáng)度");onMounted(() => {// 外層需要獲取到dom元素以及瀏覽器寬高,來(lái)對(duì)畫布設(shè)置長(zhǎng)寬// clientWidth等同于container.value.clientWidthlet container = document.querySelector(".container");const { clientWidth, clientHeight } = container;console.log(clientHeight);init();render();// 首先需要獲取場(chǎng)景,這里公共方法放在init函數(shù)中function init() {scene = new THREE.Scene();// 給相機(jī)設(shè)置一個(gè)背景scene.background = new THREE.Color(0xaaaaaa);// 透視投影相機(jī)PerspectiveCamera// 支持的參數(shù):fov, aspect, near, farcamera = new THREE.PerspectiveCamera(60,clientWidth / clientHeight,0.001,6000);// 相機(jī)坐標(biāo)camera.position.set(300, 300, 300);// 相機(jī)觀察目標(biāo)camera.lookAt(scene.position);// 渲染器renderer = new THREE.WebGLRenderer({antialias: true,});// 渲染多大的地方renderer.setSize(clientWidth, clientHeight);container.appendChild(renderer.domElement);stats = new Stats();container.appendChild(stats.domElement);addBox();console.log("查看當(dāng)前屏幕設(shè)備像素比", window.devicePixelRatio);}function addBox() {// 模型部分// 幾何體const geometry = new THREE.BoxGeometry(100, 100, 100);// 材質(zhì)material = new THREE.MeshPhongMaterial({color: 0x00ffff,transparent: true, //開啟透明// opacity: 0.5, //設(shè)置透明度// side: THREE.DoubleSide, //兩面可見(jiàn)shininess: 500,specular: 0xff0000, //高光部分的顏色});mesh = new THREE.Mesh(geometry, material);mesh.position.set(0, 0, 0);scene.add(mesh);guiFun();}function guiFun() {matFolder.close();matFolder.addColor(obj, "color").onChange(function (value) {material.color.set(value);console.log(material.specular.set(value));});matFolder.addColor(obj, "specular").onChange(function (value) {material.specular.set(value);});/* const obj = {scale: 0,};// 參數(shù)3數(shù)據(jù)類型:對(duì)象(下拉菜單)gui.add(obj, "scale", {left: -100,center: 0,right: 100,// 左: -100,//可以用中文// 中: 0,// 右: 100}).name("位置選擇").onChange(function (value) {mesh.position.x = value;}); *//* const obj = {bool: false,};// 改變的obj屬性數(shù)據(jù)類型是布爾值,交互界面是單選框gui.add(obj, "bool").name("是否旋轉(zhuǎn)").onChange(function (value) {// 點(diǎn)擊單選框,控制臺(tái)打印obj.bool變化console.log("obj.bool", value);}); */}// 相機(jī)控件const control = () => {controls = new OrbitControls(camera, renderer.domElement);controls.addEventListener("change", function () {// 瀏覽器控制臺(tái)查看相機(jī)位置變化// console.log("camera.position", camera.position);});};control();// 光源const linght = () => {const pointLight = new THREE.PointLight(0xffffff, 1.0);pointLight.position.set(100, 60, 50);ambientFolder.add(pointLight, "intensity", 0, 2);scene.add(pointLight);// 光源輔助觀察const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);scene.add(pointLightHelper);const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);directionalLight.position.set(100, 0, 0);// 方向光指向?qū)ο缶W(wǎng)格模型mesh,可以不設(shè)置,默認(rèn)的位置是0,0,0directionalLight.target = mesh;// 輔助觀察const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight,5,0xff0000);// 添加輔助標(biāo)識(shí)scene.add(dirLightHelper);// 添加平行光到場(chǎng)景中scene.add(directionalLight);// 平行光強(qiáng)度dirFolder.add(directionalLight, "intensity", 0, 2);const dirFolder2 = dirFolder.addFolder("位置"); //子菜單的子菜單dirFolder2.close(); //關(guān)閉菜單// 平行光位置dirFolder2.add(directionalLight.position, "x", -400, 400);dirFolder2.add(directionalLight.position, "y", -400, 400);dirFolder2.add(directionalLight.position, "z", -400, 400);// 平行光位置dirFolder.add(directionalLight.position, "x", -400, 400); bdirFolder.add(directionalLight.position, "y", -400, 400);dirFolder.add(directionalLight.position, "z", -400, 400);dirFolder.close();};linght();// gui.add(obj, "bool").name("旋轉(zhuǎn)動(dòng)畫");function render() {// if (obj.bool) mesh.rotateY(0.01);renderer.render(scene, camera);requestAnimationFrame(render);}window.addEventListener("resize", () => {// 更新攝像頭camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);});/* const obj = {bool: false,};gui.add(obj, "bool").name("旋轉(zhuǎn)動(dòng)畫");const render = () => {if (obj.bool) mesh.rotateY(0.01);renderer.render(scene, camera);requestAnimationFrame(render);};render(); */});
</script><style>.container {width: 100%;height: 100vh;position: relative;z-index: 1;}
</style>