<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>three.js学习</title>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script type="module" src="./js/index.js"></script>
</body>
</html>
// 引入Three.js
import * as THREE from '../three.js-r123/build/three.module.js'
// 引入Three.js扩展库
import {
OrbitControls
} from '../three.js-r123/examples/jsm/controls/OrbitControls.js';
// 引入 gltf 模型加载库
import {
GLTFLoader
} from '../three.js-r123/examples/jsm/loaders/GLTFLoader.js';
//随便调用一个API查看Three.js是否引用成功
// if (THREE.Scene) {
// console.log('引用成功')
// }
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 导入模型
*/
var model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景
var loader = new GLTFLoader(); //创建一个GLTF加载器
loader.load("./scene/ALLmodel.glb", function (gltf) { //gltf加载成功后返回一个对象
console.log('控制台查看gltf对象结构', gltf);
//gltf.scene 可以包含网格模型 Mesh,光源 Light 等信息,至于 gltf.scene 是否包含光源,要看 .gltf 文件中是否有光源信息
console.log('gltf对象场景属性', gltf.scene);
// 递归遍历 gltf.scene ,批量更改所有 Mesh 的材质
gltf.scene.traverse(function (object) {
if (object.type === 'Mesh') {
// console.log(object.material);//控制台查看 mesh 材质
// MeshLambertMaterial:受光照影响
// MeshBasicMaterial:不受光照影响
object.material = new THREE.MeshLambertMaterial({
map: object.material.map, //获取原来材质的颜色贴图属性值
color: object.material.color //读取原来材质的颜色
})
}
})
// 把 gltf.scene 中的所有模型添加到 model 组对象中
model.add(gltf.scene);
})
scene.add(model);
// /**
// * 创建网格模型
// */
// //创建一个立方体几何对象Geometry
// var geometry = new THREE.BoxGeometry(100, 100, 100);
// // 材质对象Material
// var material = new THREE.MeshLambertMaterial({
// color: 0x0000ff, //材质颜色
// });
// //网格模型对象Mesh
// var mesh = new THREE.Mesh(geometry, material);
// //网格模型添加到场景中
// scene.add(mesh);
/**
* 光源设置
*/
// 平行光1
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.6); // 光的颜色,光照强度
directionalLight.position.set(400, 200, 300);
scene.add(directionalLight);
// 平行光2
var directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.6);
directionalLight2.position.set(-400, -200, -300);
scene.add(directionalLight2);
//环境光
var ambient = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambient);
// width和height用来设置Three.js输出Canvas画布尺寸,同时用来辅助设置相机渲染范围
var width = window.innerWidth; //窗口文档显示区的宽度
var height = window.innerHeight; //窗口文档显示区的高度
/**
* 相机设置
*/
// var k = width / height; //Three.js输出的Canvas画布宽高比
// var s = 110; //控制相机渲染空间左右上下渲染范围,s越大,相机渲染范围越大
// 正交相机,这一摄像机使用正交投影来进行投影。在这种投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变。这对于渲染2D场景或者UI元素是非常有用的。
/* 从左到右参数为:
left — 摄像机视锥体左侧面。
right — 摄像机视锥体右侧面。
top — 摄像机视锥体上侧面。
bottom — 摄像机视锥体下侧面。
near — 摄像机视锥体近端面。
far — 摄像机视锥体远端面。 */
// 这些参数一起定义了摄像机的viewing frustum(视锥体)。
// 视锥体,用于确定相机视野内的东西。 它有助于加速渲染过程——位于摄像机视锥体外的物体可以安全地排除在渲染之外。
// 正交相机
// var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
// 透视投影
var camera = new THREE.PerspectiveCamera(45, width / height, 1, 3000);
camera.position.set(190, 75, 160); //相机在Three.js坐标系中的位置
camera.lookAt(0, 0, 0); //相机指向Three.js坐标系原点
/**
* 创建渲染器对象
*/
// WebGL Render 用WebGL渲染出你精心制作的场景。
var renderer = new THREE.WebGLRenderer({
antialias: true, //开启锯齿
});
// Window 接口的devicePixelRatio返回当前显示设备的物理像素分辨率与CSS像素分辨率之比。 此值也可以解释为像素大小的比率:一个CSS像素的大小与一个物理像素的大小。 简单来说,它告诉浏览器应使用多少屏幕实际像素来绘制单个CSS像素。
renderer.setPixelRatio(window.devicePixelRatio); //设置设备像素比率,防止Canvas画布输出模糊。
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色,参数:颜色,透明度
renderer.outputEncoding = THREE.sRGBEncoding; //纹理中颜色空间修改
// renderer.domElement表示Three.js渲染结果,也就是一个HTML元素(Canvas画布)
document.body.appendChild(renderer.domElement); //body元素中插入canvas画布
// 把渲染器的渲染结果 canvas 对象插入到 'pos' 对应的 div 元素中
// document.getElementById('pos').appendChild(renderer.domElement)
//执行渲染操作 指定场景、相机作为参数
// renderer.render(scene, camera); // 静态照片式渲染
// Three.js三维坐标轴 三个坐标轴颜色RGB分别对应xyz轴:红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
// 参数:size -- (可选的) 表示代表轴的线段长度. 默认为 1.
var axesHelper = new THREE.AxesHelper(250);
scene.add(axesHelper);
// 渲染循环
function render() {
// mesh.rotateY(0.01); //立方体绕y轴旋转动画,参数:将要旋转的角度(以弧度来表示)。
renderer.render(scene, camera); //执行渲染操作
// window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
// 注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
// console.log(camera.position); //通过相机控件 OrbitControls 旋转相机,选择一个合适场景渲染角度
}
render();
// Orbit controls(轨道控制器)可以使得相机围绕目标进行轨道运动。参数:参数1:将要被控制的相机。该相机不允许是其他任何对象的子级,除非该对象是场景自身。参数2:domElement, 用于事件监听的HTML元素。
//创建控件对象 控件可以监听鼠标的变化,改变相机对象的属性
// 旋转:拖动鼠标左键
// 缩放:滚动鼠标中键
// 平移:拖动鼠标右键
var controls = new OrbitControls(camera, renderer.domElement);
// 窗口事件
// onresize 事件会在窗口被调整大小时发生
window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 重置相机投影的相关参数
k = window.innerWidth / window.innerHeight; //窗口宽高比
camera.left = -s * k;
camera.right = s * k;
camera.top = s;
camera.bottom = -s;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
};