index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:http://www.webgl3d.cn/</title>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script type="module">
import {renderer} from './RenderLoop.js'
//Three.js渲染结果Canvas画布插入到body元素中
document.body.appendChild(renderer.domElement);
import { choose } from './choose.js'//执行射线拾取代码
</script>
</body>
</html>
model.js(模型加载)
// 引入Three.js
import * as THREE from '../../../../three.js-r123/build/three.module.js';
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from '../../../../three.js-r123/examples/jsm/loaders/GLTFLoader.js';
var model = new THREE.Group();//声明一个组对象,用来添加加载成功的三维场景
var loader = new GLTFLoader(); //创建一个GLTF加载器
var granaryArr = [];//所有粮仓模型对象的集合,export导出用于射线拾取
loader.load("./scene/model.glb", function (gltf) {//gltf加载成功后返回一个对象
console.log('控制台查看gltf对象结构', gltf);
// console.log('gltf对象场景属性', gltf.scene);
// 递归遍历gltf.scene
gltf.scene.traverse(function (object) {
if (object.type === 'Mesh') {
// 批量更改所有Mesh的材质
object.material = new THREE.MeshLambertMaterial({
map: object.material.map, //获取原来材质的颜色贴图属性值
color: object.material.color, //读取原来材质的颜色
})
}
})
// 所有粮仓模型的父对象名称:'粮仓'
var group = gltf.scene.getObjectByName('粮仓');
//console.log('粮仓', group);
group.traverse(function (obj) {
if (obj.type === 'Mesh') {
granaryArr.push(obj);
}
})
model.add(gltf.scene);
})
export { model, granaryArr }
choose.js(射线拾取)
// 引入three.js
import * as THREE from '../../../three.js-r123/build/three.module.js';
import { camera } from './RendererCamera.js'
import { granaryArr } from './scene/model.js'//获取所有粮仓模型对象的集合
// 鼠标单击射线拾取meshArr中的某个国家Mesh
var chooseMesh = null
function choose(event) {
if (chooseMesh) {
chooseMesh.material.color.set(0xffffff);// 把上次选中的mesh设置为原来的颜色
}
var Sx = event.clientX; //鼠标单击位置横坐标
var Sy = event.clientY; //鼠标单击位置纵坐标
//屏幕坐标转WebGL标准设备坐标
var x = (Sx / window.innerWidth) * 2 - 1; //WebGL标准设备横坐标
var y = -(Sy / window.innerHeight) * 2 + 1; //WebGL标准设备纵坐标
//创建一个射线投射器`Raycaster`
var raycaster = new THREE.Raycaster();
//通过鼠标单击位置标准设备坐标和相机参数计算射线投射器`Raycaster`的射线属性.ray
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
//返回.intersectObjects()参数中射线选中的网格模型对象
// 未选中对象返回空数组[],选中一个数组1个元素,选中两个数组两个元素
var intersects = raycaster.intersectObjects(granaryArr);
// console.log("射线器返回的对象", intersects);
// console.log("射线投射器返回的对象 点point", intersects[0].point);
// console.log("射线投射器的对象 几何体",intersects[0].object.geometry.vertices)
// intersects.length大于0说明,说明选中了模型
if (intersects.length > 0) {
chooseMesh = intersects[0].object;
chooseMesh.material.color.set(0x00ffff);//选中改变颜色,这样材质颜色贴图.map和color颜色会相乘
}
}
addEventListener('click', choose); // 监听窗口鼠标单击事件,鼠标单击选中某个国家Mesh
// addEventListener('mousemove', choose);//鼠标滑动事件
export { choose }
后面的三个文件都是常规配置,跟环境相关的
RendererCamera.js(摄像机)
// 引入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';
// width和height用来设置Three.js输出Canvas画布尺寸,同时用来辅助设置相机渲染范围
var width = window.innerWidth; //窗口文档显示区的宽度
var height = window.innerHeight; //窗口文档显示区的高度
/**
* 相机设置
*/
// 透视投影
var camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(318, 162, 204);//通过相机控件OrbitControls旋转相机,选择一个合适场景渲染角度
camera.lookAt(0, 0, 0);
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer({
antialias: true, //开启锯齿
});
renderer.setPixelRatio(window.devicePixelRatio);//设置设备像素比率,防止Canvas画布输出模糊。
renderer.setSize(width, height); //设置渲染区域尺寸
// renderer.domElement表示Three.js渲染结果,也就是一个HTML元素(Canvas画布)
// document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
// 设置three.js背景颜色 和雾化颜色相配
renderer.setClearColor(0x005577, 1);
renderer.outputEncoding = THREE.sRGBEncoding;//解决加载gltf格式模型纹理贴图和原图不一样问题
//创建控件对象 控件可以监听鼠标的变化,改变相机对象的属性
// 旋转:拖动鼠标左键
// 缩放:滚动鼠标中键
// 平移:拖动鼠标右键
var controls = new OrbitControls(camera, renderer.domElement);
export { renderer, camera };
index.js(光源)
// 场景总文件
// 引入Three.js
import * as THREE from '../../../../three.js-r123/build/three.module.js';
import { model } from './model.js';
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
scene.add(model);//粮仓基地三维模型添加到场景中
// 设置雾化效果,雾的颜色和背景颜色相近,这样远处网格线和背景颜色融为一体
scene.fog = new THREE.Fog(0x005577, -100, 1000);
/**
* 光源设置
*/
// 平行光1
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(400, 200, 300);
scene.add(directionalLight);
// 平行光2
var directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight2.position.set(-400, -200, -300);
scene.add(directionalLight2);
//环境光
var ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
// Three.js三维坐标轴 三个坐标轴颜色RGB分别对应xyz轴
var axesHelper = new THREE.AxesHelper(250);
// scene.add(axesHelper);
export { scene };
RenderLoop.js(渲染)
import { scene } from './scene/index.js'//Three.js三维场景
import { renderer, camera } from './RendererCamera.js'//渲染器对象和相机对象
// 渲染循环
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
// console.log(camera.position);//通过相机控件OrbitControls旋转相机,选择一个合适场景渲染角度
}
render();
export {renderer}