<!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>Document</title>
<style>
body {
margin: 0;
overflow: hidden;
position: relative;
}
.label {
margin-top: -1em;
border: 10px;
border-radius: 8px;
width: 85px;
text-align: center;
cursor: pointer;
color: rgb(0, 155, 234);
line-height: 1.2;
background-color: rgb(244, 244, 244);
box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.25);
}
.label:hover {
box-shadow: 0px 0px 20px rgba(0, 155, 234, 0.8);
}
</style>
<script src="./three.js-r139/build/three.js"></script>
<script src="./three.js-r139/examples/js/controls/OrbitControls.js"></script>
<script src="./three.js-r139/examples/js/renderers/CSS2DRenderer.js"></script>
</head>
<body>
</body>
<script>
var scene, camera, renderer, controls, labelRenderer
// var stats = initStats()
// 地面网格所需变量
var length = 200
// 场景
function initScene() {
scene = new THREE.Scene()
}
/* 相机 */
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 200, 250);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
/* 渲染器 */
function initRender() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute'
labelRenderer.domElement.style.top = '0px'
document.body.appendChild(labelRenderer.domElement);
}
/* 生成标签 */
function createLabel(text, pos) {
const div = document.createElement('div')
// div.className = 'label'
div.innerHTML = text
div.style.padding = "2px";
div.style.color = "#fff";
div.style.height = "20px";
div.style.fontSize = "16px";
div.style.lineHeight = "16px";
div.style.position = "absolute";
// div.style.top = '0px';
div.style.backgroundColor = "rgba(25,25,25,0.5)";
div.style.borderRadius = "5px";
console.log('div', div);
const divLabel = new THREE.CSS2DObject(div)
divLabel.position.set(pos.x, pos.y, pos.z);
return divLabel
}
/* 灯光 */
function initLight() {
var ambientLight = new THREE.AmbientLight(0x333333);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(100, 300, 200);
scene.add(directionalLight);
}
/* 控制器 */
function initControls() {
controls = new THREE.OrbitControls(camera, labelRenderer.domElement);
/* 其它属性默认 */
}
/* 场景内容 */
function initContent() {
// const geometry1 = new THREE.BoxGeometry(50, 50, 50);
// const material = new THREE.MeshPhongMaterial({
// color: 0x00ff00,
// });
// const cube = new THREE.Mesh(geometry1, material);
// scene.add(cube);
//这里用这个构造
const geometry = new THREE.BufferGeometry()
// console.log(geometry);
const pointsArray = new Array()
pointsArray.push(new THREE.Vector3(-length / 2, 0, 0))
pointsArray.push(new THREE.Vector3(length / 2, 0, 0))
//用这个api传入顶点数组
geometry.setFromPoints(pointsArray)
var lineMaterial = new THREE.LineBasicMaterial({
color: 0x808080
}); /* 基础线材质 */
var planeGeometry = new THREE.PlaneGeometry(length, 10); /* 平面 width:200,、height:10 */
var planeMaterial = new THREE.MeshBasicMaterial({
color: 0xD9D9D9,
side: THREE.DoubleSide
}); /* 平面材质 */
// geometry.vertices.push(new THREE.Vector3(-length / 2, 0, 0)); /* 顶点(-100, 0, 0) */
// geometry.vertices.push(new THREE.Vector3(length / 2, 0, 0)); /* 顶点( 100, 0, 0) */
/* 循环创建线段 */
for (var i = 0; i <= length / 10; i++) {
/* 横向线段 */
var lineX = new THREE.Line(geometry, lineMaterial);
lineX.position.z = (i * 10) - length / 2;
scene.add(lineX);
/* 纵向线段 */
var lineY = new THREE.Line(geometry, lineMaterial);
lineY.rotation.y = 0.5 * Math.PI;
lineY.position.x = (i * 10) - length / 2;
scene.add(lineY);
}
/* 创建包围平面 */
var planeX_left = new THREE.Mesh(planeGeometry, planeMaterial);
planeX_left.rotation.y = 0.5 * Math.PI;
planeX_left.position.x = -length / 2;
var planeX_right = planeX_left.clone();
planeX_right.position.x = length / 2;
var planeY_top = new THREE.Mesh(planeGeometry, planeMaterial);
planeY_top.position.z = -length / 2;
var planeY_bottom = planeY_top.clone();
planeY_bottom.position.z = length / 2;
scene.add(planeY_bottom);
scene.add(planeY_top);
scene.add(planeX_left);
scene.add(planeX_right);
/* 四个包围面的位置 y轴向上5 */
scene.traverse(function (object) {
if (object.isMesh) {
if (object.geometry.type === 'PlaneGeometry') {
object.position.y = 5;
}
}
});
}
/* 获取射线与平面相交的交点 */
function getIntersects(event) {
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
var normal = new THREE.Vector3(0, 1, 0);
/* 创建平面 */
var planeGround = new THREE.Plane(normal, 0);
/* 从相机发出一条射线经过鼠标点击的位置 */
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObjects(scene.children, true);
console.log('dddddddddddd', intersects);
/* 获取射线 */
// var ray = raycaster.ray;
/* 计算相机到射线的对象,可能有多个对象,返回一个数组,按照距离相机远近排列 */
// var intersects = ray.intersectPlane(planeGround);
// var intersects = ray.direction;
if (intersects.length) {
var object = intersects[0].point
// console.log("x:" + intersects.x + " y:" + intersects.y + " z:" + intersects.z);
/* 返回向量 */
return object;
}
}
var pointsArray = [];
var window_mouse = true;
/* 鼠标按下事件 */
function onMouseDown(event) {
/* 获取相机发出的射线与 Plane 相交点*/
let intersects = getIntersects(event);
/* 存放网格的三维坐标 */
var vector3_x, vector3_z;
/* 鼠标左键按下时,创建点和线段 */
if (event.button === 0) {
if (!window_mouse) {
window.addEventListener('mousemove', onMouseMove, false);
/* 依据 windwo_mouse 标识避免事件的重复添加 */
window_mouse = true;
}
/* 若交点此时在平面之内则创建点(Points) */
var pointsGeometry = new THREE.BufferGeometry();
// var pointsGeometry = new THREE.SphereGeometry( 15, 32, 16 );
// pointsGeometry.vertices.push(intersects);
pointsGeometry.setFromPoints([intersects])
var pointsMaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 3
});
var points = new THREE.Points(pointsGeometry, pointsMaterial);
// points.position.set(intersects)
// console.log('points',points);
pointsArray.push(intersects);
scene.add(points);
/* 创建线段 */
var lineGeometry = new THREE.BufferGeometry();
var lineMaterial = new THREE.LineBasicMaterial({
color: 0x000fff
});
if (pointsArray.length >= 2) {
// lineGeometry.vertices.push(pointsArray[0].geometry.vertices[0], pointsArray[1].geometry.vertices[
// 0]);
lineGeometry.setFromPoints([pointsArray[0], pointsArray[1]])
console.log('pointsArray', pointsArray);
var line = new THREE.Line(lineGeometry, lineMaterial);
pointsArray.shift();
scene.add(line);
}
}
/* 鼠标右键按下时 回退到上一步的点,并中断绘制 */
if (event.button === 2) {
window.removeEventListener('mousemove', onMouseMove, false);
/* 移除事件之后,要设置为 false 为了避免事件的重复添加 */
window_mouse = false;
/* 鼠标左键未点击时线段的移动状态 */
if (scene.getObjectByName('line_move')) {
scene.remove(scene.getObjectByName('line_move'));
/* 删除数组中的元素,否则的话再次重绘会链接之前的点接着重绘 */
pointsArray.shift();
}
}
}
/* 鼠标移动事件 */
function onMouseMove(event) {
var intersects = getIntersects(event);
// console.log(intersects);
/* 判断交点是否在 x(-100, 100) ,z(-100, 100)(平面)之间 */
/* 鼠标左键未点击时线段的移动状态 */
if (scene.getObjectByName('line_move')) {
scene.remove(scene.getObjectByName('line_move'));
}
/* 创建线段 */
var lineGeometry = new THREE.BufferGeometry();
var lineMaterial = new THREE.LineBasicMaterial({
color: 0x000fff
});
if (pointsArray.length > 0) {
// lineGeometry.vertices.push(pointsArray[0].geometry.vertices[0]);
console.log('pointsArray', pointsArray);
// lineGeometry.setFromPoints([pointsArray[0]])
var mouseVector3 = new THREE.Vector3(intersects.x, 0, intersects.z);
// lineGeometry.vertices.push(mouseVector3);
lineGeometry.setFromPoints([pointsArray[0], mouseVector3])
// console.log('distance', pointsArray[0].distanceTo(mouseVector3), pointsArray[0]);
console.log('distance', mouseVector3.distanceTo(pointsArray[0]), pointsArray[0]);
let dis = mouseVector3.distanceTo(pointsArray[0]).toFixed(2)
let pos = new THREE.Vector3().copy(mouseVector3)
pos.add(pointsArray[0]) // 两个向量相加
pos.multiplyScalar(0.5) // 乘以二分之一 取中点
let label = scene.getObjectByName('active-label');
if (label) {
console.log('label2', label);
label.element.innerHTML = '~' + dis;
label.position.set(pos.x, pos.y, pos.z);
scene.add(label);
} else {
label = this.createLabel('~' + dis, pos);
console.log('label1', label);
label.name = 'active-label';
scene.add(label);
}
var line = new THREE.Line(lineGeometry, lineMaterial);
line.name = 'line_move';
scene.add(line);
}
}
/* 键盘按下事件 */
function onKeyDown(event) {
/* ESC键 回退上一步绘制,结束绘制*/
if (event.key === 'Escape') {
window.removeEventListener('mousemove', onMouseMove, false);
/* 移除事件之后,要设置为 false 为了避免 mousemove 事件的重复添加 */
window_mouse = false;
/* 鼠标左键未点击时线段的移动状态 */
if (scene.getObjectByName('line_move')) {
scene.remove(scene.getObjectByName('line_move'));
/* 删除数组中的元素,否则的话再次重绘会链接之前的点接着重绘 */
pointsArray.shift();
}
var length = scene.children.length - 1;
console.log(scene.children);
/* 按步骤移除点和先 */
if (scene.children[length].isLine || scene.children[length].isPoints) {
scene.children.pop();
length = scene.children.length - 1;
/* 若最后一项不是线段或者点就不移除 */
if (!scene.children[length].isMesh) {
scene.children.pop();
}
}
}
}
/* 更新数据 */
function update() {
// stats.update();
controls.update();
}
/* 窗口自动适应 */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
/* 循环调用 */
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
update();
}
/* 初始化 */
function init() {
/* 兼容性判断 */
//if (!Detector.webgl) Detector.addGetWebGLMessage();
initScene();
initCamera();
initRender();
initLight();
initContent();
initControls();
/* 事件监听 */
window.addEventListener('resize', onWindowResize, false);
window.addEventListener('mousedown', onMouseDown, false); /* 使用mousedown的时候可以判断出点击的鼠标左右键之分 */
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('keydown', onKeyDown, false); /* 使用事件的时候要把前面的on给去掉 */
}
/* 初始加载 */
(function () {
console.log('three start...');
init();
animate();
console.log('three end...');
})();
</script>
</html>
实现threeJS 测距(距离并不能显示出来)
最新推荐文章于 2024-10-11 17:05:07 发布
本文介绍了如何使用Three.js库在网页上实现动态的3D空间,通过鼠标交互创建线段和点,同时展示了关键的事件处理和几何体操作。读者将了解如何利用CSS2DRenderer创建标签,以及如何跟踪鼠标位置来生成和移动几何对象。
摘要由CSDN通过智能技术生成