import * as THREE from 'three';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
/**
* 3d 根据文档学习 3 - 载入模型
* https://threejs.org/docs/index.html#manual/zh/introduction/Loading-3D-models
* 模型网站:https://sketchfab.com/3d-models?features=downloadable&sort_by=-likeCount
* 谷歌邮箱登录,微软邮箱创建的账号(网易邮箱注册失败,估计大陆号不支持)
*/
export class ThreeDoc3Load {
constructor(canvasId) {
this.work(canvasId);
}
/**
* 如果有可能的话,我们推荐使用glTF(gl传输格式)。.GLB和.GLTF是这种格式的这两种不同版本, 都可以被很好地支持。
* 由于glTF这种格式是专注于在程序运行时呈现三维物体的,所以它的传输效率非常高,且加载速度非常快。 功能方面则包括了网格、
* 材质、纹理、皮肤、骨骼、变形目标、动画、灯光和摄像机。
* 公共领域的glTF文件可以在网上找到,例如 Sketchfab
* @param canvasId
*/
work(canvasId) {
// 创建 3d 场景
const scene = new THREE.Scene();
/**
* GLTF加载器(GLTFLoader)
* glTF(gl传输格式)是一种开放格式的规范 (open format specification), 用于更高效地传输、加载3D内容。该类文件以JSON
* (.glft)格式或二进制(.glb)格式提供, 外部文件存储贴图(.jpg、.png)和额外的二进制数据(.bin)。一个glTF组件可传输一个
* 或多个场景, 包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机。
* @type {GLTFLoader}
*/
const loader = new GLTFLoader();
// 文件夹名称,摄像机xyz,
let dir , cameraXYZ, cameraPx, cameraPy, cameraPz, lightR;
// 口袋妖怪治疗中心
dir = 'pokemon_rse_-_pokemon_center';
cameraXYZ = [ 0.6, 1, 1.8 ];
lightR = 1.2;
// 露琪亚
dir = 'lugia-statue';
cameraXYZ = [ -2, 1.3, 5 ];
lightR = 1.2;
// 卡通小汽车
dir = 'pony_cartoon';
cameraXYZ = [ 2.3, 2.4, 3.6 ];
lightR = 20;
// 引用地址
let url = `assets/models/${ dir }/scene.gltf`;
/**
* .load ( url : String, onLoad : Function, onProgress : Function, onError : Function ) :
* url — 包含有.gltf/.glb文件路径/URL的字符串。
* onLoad — 加载成功完成后将会被调用的函数。该函数接收parse所返回的已加载的JSON响应。
* onProgress — (可选)加载正在进行过程中会被调用的函数。其参数将会是XMLHttpRequest实例,包含有总字节数.total与已加载的字节数.loaded。
* onError — (可选)若在加载过程发生错误,将被调用的函数。该函数接收error来作为参数。
*/
loader.load(url, function (gltf) {
scene.add(gltf.scene);
}, undefined, function (error) {
console.error(error);
});
/**
* .setDRACOLoader ( dracoLoader : DRACOLoader ) : this
* dracoLoader — THREE.DRACOLoader的实例,用于解码使用KHR_draco_mesh_compression扩展压缩过的文件。
* .parse ( data : ArrayBuffer, path : String, onLoad : Function, onError : Function ) : undefined
* data — 需要解析的glTF文件,值为一个ArrayBuffer或JSON字符串。
* path — 用于找到后续glTF资源(如纹理和.bin数据文件)的基础路径。
* onLoad — 解析成功完成后将会被调用的函数。
* onError — (可选)若在解析过程发生错误,将被调用的函数。该函数接收error来作为参数。
* 解析基于glTF的ArrayBuffer或JSON字符串,并在完成后触发onLoad回调。onLoad的参数将是一个包含有已加载部分的Object:.scene、 .scenes、 .cameras、 .animations 和 .asset。
*/
/**
* 创建渲染器
* WebGLRenderer渲染器之外,Three.js同时提供了其他几种渲染器。当用户所使用的浏览器过于老旧,或者由于其他原因不支持WebGL时,可以使用这几种渲染器进行降级。
* @type {number}
*/
const renderer = new THREE.WebGLRenderer();
/**
* 渲染器尺寸:设置渲染器的宽高使渲染出的场景充满应用程序
* 对于性能比较敏感的应用程序来说,你可以使用setSize传入一个较小的值,例如window.innerWidth/2和window.innerHeight/2
* 如果想以较低的分辨率来渲染,可以在调用setSize时,将updateStyle(第三个参数)设为false
*/
renderer.setSize(window.innerWidth, window.innerHeight);
// 最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。
document.body.appendChild(renderer.domElement);
let light = '';
// 添加灯光 - 环境光 - 无阴影
light = new THREE.AmbientLight(0xffffff, lightR);
// 平行光
// light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(0,0,0);
scene.add(light);
/**
* 照相机常用的有两种
* 正投影相机:THREE.OrthographicCamera(left,right,top,bottom,near,far);
* 透视照相机:THREE.PerspectiveCamera( fov, aspect, near, far ) ;
* fov - 视野角度。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)
* aspect ratio - 长宽比。也就是你用一个物体的宽除以它的高的值。当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的
* near,far - 近截面和远截面。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中
*/
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 设置相机位置
[ cameraPx, cameraPy, cameraPz ] = cameraXYZ;
camera.position.x = cameraPx;
camera.position.y = cameraPy;
camera.position.z = cameraPz;
camera.lookAt(0,0,0);
// 添加控制器
let orb = new OrbitControls(camera, document.body);
orb.addEventListener('change', function () {
console.log(camera.position);
});
renderer.render(scene, camera);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
}
}