threejs 基本使用
- 创建场景
- 创建相机
- 创建几何体
- 给几何体注册点击事件
代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板代码</title>
<style>
canvas{
display: block;
}
body {
margin: 0;
overscroll-behavior: none;
}
#btns{
position: absolute;
top:10%;
width: 500px;
height: 100px;
left: 50%;
transform:translateX(-50%);
}
</style>
</head>
<body>
<div id="btns"></div>
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "./three.js-master/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from './three.js-master/build/three.module.js';
import {OrbitControls} from "./three.js-master/examples/jsm/controls/OrbitControls.js";
// import anime from "./js/anime.es.js"; // 暂时没有用
//创建一个做拾取的数组
let selectArray = [];
let scene,renderer,camera,orbitControls;
function init(){
scene = new THREE.Scene(); // 创建一个场景
renderer = new THREE.WebGLRenderer({
alpha:true, // 透明
antialias:true // 抗锯齿开启
});
renderer.setSize(window.innerWidth,window.innerHeight); // 设置渲染器的宽高
document.body.appendChild(renderer.domElement);
/**
* three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。
第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。
第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。
接下来的两个参数是近截面(near)和远截面(far)。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。
*/
camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.01,50000); // 创建相机并设置
camera.position.set(10,10,10); // 设置相机的位置
orbitControls = new OrbitControls(camera,renderer.domElement); // 一个是控制的相机对象 第二个是检测事件的dom 元素
camera.add(new THREE.PointLight()); // 创建一个点光源 点光源(PointLight)表示的是从一个点朝各个方向发射出光线的一种光照效果
scene.add(camera); // 相机添加到场景中
let helper = new THREE.GridHelper(50,50);
scene.add(helper);
}
function addMesh(){
//创建一个长宽高为1的盒子
let geometry = new THREE.BoxGeometry(1,1,1);
//以盒子几何体创建100个颜色不同的盒子Mesh
for(let i = 0;i< 100;i++){
let material = new THREE.MeshBasicMaterial({
color:0xffffff * Math.random()
});
let mesh = new THREE.Mesh(geometry,material);
mesh.position.x = Math.random() * 50 - 25; //x轴偏移 -25 ~ 25
mesh.position.y = 0.5; //y轴高度上升0.5,盒子的高度为1,这样可以直接放置到地面上
mesh.position.z = Math.random() * 50 - 25;
selectArray.push(mesh);
scene.add(mesh);
}
//创建射线对象
let raycaster = new THREE.Raycaster();
//创建用于保存鼠标点击位置的二维向量
let mousePoint = new THREE.Vector2();
renderer.domElement.addEventListener('click',(e)=>{
let x = e.clientX;
let y = e.clientY;
mousePoint.x = ( x / window.innerWidth ) * 2 - 1;
mousePoint.y = -( y / window.innerHeight ) * 2 + 1;
/* 算法公式:
鼠标点击位置x/页面宽度 = x轴比例
x轴比例 * 2 -1 = 坐标系扩大两倍,且坐标系x轴0点向右移动100%
y轴计算要麻烦一点,html的y轴从左上角开始计算,所以我们先计算比例,然后扩大坐标系
然后再将当前坐标系*-1,可以让坐标系反向,原先y轴的正方向变成了由屏幕下方到屏幕上方
坐标系转负后,这里还需要加一个1来让坐标系放到屏幕中心
最终得到的结果是,在以屏幕正中心为坐标系原点的,x,y位置
*/
//将射线绑定到相机上,并通过mousePoint定位到相机的指定位置
raycaster.setFromCamera(mousePoint,camera);
//拾取物体
let intersects = raycaster.intersectObjects(selectArray);
console.log(intersects);
if(intersects.length > 0){
let intersect = intersects[0];
console.log(intersect);
let object = intersect.object;
object.material.color = new THREE.Color("#ff0000");
}
});
/**
* 给物体注册点击事件
*/
renderer.domElement.addEventListener('mousemove',(e)=>{
let x = e.clientX;
let y = e.clientY;
let rx = ( x / window.innerWidth ) * 2 - 1;
let ry = -( y / window.innerHeight ) * 2 + 1;
console.log(rx,ry)
})
}
function render(){
renderer.render(scene,camera);
requestAnimationFrame(render);
}
init();
addMesh();
render();
</script>
</body>
</html>