1 解决标签点的包含关系
<div id="WebGLwxp" align="center">
<div id="notice"></div>
</div>
notice是用来显示动态信息的div, WebGLwxp是渲染场景的div
2 首先解决鼠标点选问题
参考鼠标点选解决方案
3 然后解决三维坐标点转换为二维坐标点问题
//三维坐标转屏幕坐标
function transPosition(position) {
var world_vector = new THREE.Vector3(position.x, position.y, position.z);
var vector = world_vector.project(camera);
var halfWidth = window.innerWidth / 2;
var halfHeight = window.innerHeight / 2;
return {
x: Math.round(vector.x * halfWidth + halfWidth),
y: Math.round(-vector.y * halfHeight + halfHeight)
};
}
点选不同对象,显示其对应名称和坐标,当然可以根据需求增加更多功能
完整代码
<!DOCTYPE html>
<html>
<head>
<title>Threejs三维场景基本模块</title>
<style type="text/css">
body
{
margin: 0;
overflow: hidden; /* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script type="text/javascript" src="threejsmaster/build/three.js"></script>
<script type="text/javascript" src="threejsmaster/build/js/libs/dat.gui.min.js"></script>
<script type="text/javascript" src="threejsmaster/build/js/loaders/STLLoader.js"></script>
</head>
<body>
<!-- 作为Three.js渲染器输出元素 -->
<div id="WebGLwxp" align="center">
<div id="notice"></div>
</div>
<script type="text/javascript">
//全局变量---------------------------------
//仿真场景必备变量
var scene, camera, renderer;
//界面变量
var GuiControls;
//物体变量
var cube;
//相机视角
var fov = 45;
var mouseDownX = 0;
var mouseMoveX = 0;
//鼠标点选变量
var objects = []; //可以点选的物体容器
var mouseXY; //鼠标平面坐标
var raycaster; //射线对象
var boundingBox; //包围盒
var selectedObject; //被选中的物体
var WxpTexture; //纹理对象
//-----------------------------------------
//键盘函数
function WxpKeyPressed(e) {
var key = event.keyCode;
if (!boundingBox)
document.getElementById("notice").innerHTML = "请先选中物体" + key.toString();
switch (key) {
case 37: /*左方向键*/
GuiControls.camerPositionX += 0.1;
break;
case 39: /*右方向键*/
GuiControls.camerPositionX -= 0.1;
break;
case 38: /*向上键*/
GuiControls.camerPositionY -= 0.1;
break;
case 40: /*向下键*/
GuiControls.camerPositionY += 0.1;
break;
case 87: /*w*/
selectedObject.position.y += 0.5;
selectedObject.rotation.x -= Math.PI / 4.0;
break;
case 65: /*a*/
selectedObject.position.x -= 0.5;
selectedObject.rotation.y -= Math.PI / 4.0;
break;
case 83: /*s*/
selectedObject.position.y -= 0.5;
selectedObject.rotation.x += Math.PI / 4.0;
break;
case 68: /*d*/
selectedObject.position.x += 0.5;
selectedObject.rotation.y += Math.PI / 4.0; ;
break;
}
//
if (boundingBox)
scene.remove(boundingBox);
boundingBox = new THREE.BoxHelper(selectedObject, 0x0000ff);
scene.add(boundingBox);
}
//---------------------------------------------------
//中键滚动
function WxpMousewheel(e) {
e.preventDefault();
if (e.wheelDelta) {
if (e.wheelDelta > 0) { //当滑轮向上滚动时
fov += 1;
}
if (e.wheelDelta < 0) { //当滑轮向下滚动时
fov -= 1;
}
} else if (e.detail) { //Firefox滑轮事件
if (e.detail > 0) { //当滑轮向上滚动时
fov -= 1;
}
if (e.detail < 0) { //当滑轮向下滚动时
fov += 1;
}
}
camera.fov = fov;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
}
//左键按下--------------------------------
function WxpMouseDown(event) {//按下鼠标
event.preventDefault();
//鼠标点选物体
mouseXY.set((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1);
raycaster.setFromCamera(mouseXY, camera);
var intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) {
selectedObject = intersects[0].object;
var activePoint = intersects[0].point;
if (boundingBox)
scene.remove(boundingBox);
boundingBox = new THREE.BoxHelper(selectedObject, 0x0000ff);
scene.add(boundingBox);
//动态标签
var str = new String("");
var div = document.getElementById('notice');
var left = transPosition(selectedObject.position).x;
var top = transPosition(selectedObject.position).y - 50;
div.style.position = 'absolute';
div.style.color = "blue";
div.style.display = "";
div.style.left = left + 'px';
div.style.top = top + 'px';
str ="名称:"+selectedObject.name + " 坐标: x=" + left + " y=" + top;
div.innerHTML = str;
}
//没有选中物体就移除包围盒
else {
if (boundingBox)
scene.remove(boundingBox);
//标签内容置空
var div = document.getElementById('notice');
div.innerHTML="";
}
}
//三维坐标转屏幕坐标
function transPosition(position) {
var world_vector = new THREE.Vector3(position.x, position.y, position.z);
var vector = world_vector.project(camera);
var halfWidth = window.innerWidth / 2;
var halfHeight = window.innerHeight / 2;
return {
x: Math.round(vector.x * halfWidth + halfWidth),
y: Math.round(-vector.y * halfHeight + halfHeight)
};
}
//按下左键后移动------------------------------
function WxpMouseMove(event) {//移动鼠标
mouseMoveX = event.clientX - mouseDownX;
// mouseX = event.clientX - windowHalfX;
// targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
}
//左键释放-------------------------------------
function WxpMouseUp(event) {//释放鼠标键
document.removeEventListener('mousemove', WxpMouseMove, false);
document.removeEventListener('mouseup', WxpMouseUp, false);
}
//-----------------------------------------
//场景基本配置
function WxpInitScene() {
//**********************基本元素**************************************
var sceneWidth = window.innerWidth; // window.innerWidth-400;
var sceneHeight = window.innerHeight; //window.innerHeight-80;
//创建一个场景
scene = new THREE.Scene();
//创建一个摄像机对象
camera = new THREE.PerspectiveCamera(45, sceneWidth / sceneHeight, 0.1, 200);
//设置摄像机参数
camera.position.set(10.0, -20, 13);
camera.up.set(0, 0, 1); //Z轴正向向上
camera.lookAt(new THREE.Vector3(0, 0, 0));
//创建一个WebGL渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor(new THREE.Color(0x7696f1));
renderer.setSize(sceneWidth, sceneHeight);
renderer.setPixelRatio(window.devicePixelRatio); //框锯齿设置
//系统坐标系绘制-------------------------
var axesHelper = new THREE.AxesHelper(12);
scene.add(axesHelper);
raycaster = new THREE.Raycaster();
mouseXY = new THREE.Vector2();
//网格线绘制
var grid = new THREE.GridHelper(24, 24, 0xFF0000, 0x444444);
grid.material.opacity = 0.4;
grid.material.transparent = true;
grid.rotation.x = Math.PI / 2.0; //默认网格线旋转90度
scene.add(grid);
//---------------------------------------
//***********************************************************************
//建立环境光线
var ambient = new THREE.AmbientLight(0x666666);
scene.add(ambient);
//平行光(没感觉到作用)
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
scene.add(directionalLight);
//创建点光源 正上面
var spotLightTop = new THREE.SpotLight(0xFFFFFF);
spotLightTop.position.set(0, 0, 50);
spotLightTop.castShadow = true;
scene.add(spotLightTop);
//左前方
var spotLightFront = new THREE.SpotLight(0xaaaaaa);
spotLightFront.position.set(-50, 50, 5);
spotLightFront.castShadow = true;
scene.add(spotLightFront);
//右前方
var spotLightRight = new THREE.SpotLight(0xaaaaaa);
spotLightRight.position.set(50, 50, 5);
spotLightRight.castShadow = true;
scene.add(spotLightRight);
//左后方
var spotLightLeft = new THREE.SpotLight(0xaaaaaa);
spotLightLeft.position.set(-50, -50, 5);
spotLightLeft.castShadow = true;
scene.add(spotLightLeft);
//右后方
var spotLightRear = new THREE.SpotLight(0xaaaaaa);
spotLightRear.position.set(50, -50, 5);
spotLightRear.castShadow = true;
scene.add(spotLightRear);
//将渲染的结果输出到指定页面元素中
document.getElementById("WebGLwxp").appendChild(renderer.domElement);
window.addEventListener('keydown', WxpKeyPressed, false);
window.addEventListener('mousedown', WxpMouseDown, false);
window.addEventListener('mousewheel', WxpMousewheel, false);
}
//-----------------------------------------
//加载场景物体
function WxpAddObject() {
//加载物体
//创建一个立方体
var cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000, opacity: 0.5, transparent: true });
cube = new THREE.Mesh(cubeGeometry, cubeMaterial); //物体=几何体+材质
cube.castShadow = true;
cube.name = "objtest";
//设置立方体的位置
cube.position.set(0, 0, 0.5);
scene.add(cube);
objects.push(cube);
//创建一个立方体
var cubeGeometry2 = new THREE.CylinderGeometry(0, 1, 1, 20, 20, false);
// var cubeMaterial2 = new THREE.MeshNormalMaterial({flatShading: true});
// var cubeMaterial2 = new THREE.MeshPhongMaterial({color: 0x836DED,specular:0x111111,shininess:80});
WxpTexture = new THREE.ImageUtils.loadTexture("aa.png");
var cubeMaterial2 = new THREE.MeshBasicMaterial({ map: WxpTexture, transparent: true });
WxpTexture.wrapS = THREE.RepeatWrapping;
WxpTexture.wrapT = THREE.RepeatWrapping;
WxpTexture.repeat.set(2, 2);
WxpTexture.center.set(0.5, 0.5);
cube2 = new THREE.Mesh(cubeGeometry2, cubeMaterial2); //物体=几何体+材质
//设置立方体的位置
cube2.position.set(4, 0, 0.5);
scene.add(cube2);
objects.push(cube2);
cube2.name = "obj多对多";
//创建管道成型的路径(3D样条曲线)
var path = new THREE.CatmullRomCurve3([
new THREE.Vector3(-5, 0, 1),
new THREE.Vector3(0, 5, 1),
new THREE.Vector3(5, 0, 1),
new THREE.Vector3(0, 0, 0)]);
var point = path.getPoints(100);
var points = new THREE.CatmullRomCurve3(point);
// path:路径 40:沿着轨迹细分数 2:管道半径 25:管道截面圆细分数
var geometry3 = new THREE.TubeGeometry(path, 40, 0.2, 25);
var cube3 = new THREE.Mesh(geometry3, cubeMaterial2); //物体=几何体+材质
cube3.name = "objwwww";
scene.add(cube3);
objects.push(cube3);
//地板
var plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(10, 10),
new THREE.MeshBasicMaterial({ color: 0xdddddd, side: THREE.DoubleSide })
);
scene.add(plane);
plane.receiveShadow = true;
var loader = new THREE.STLLoader();
var stlFileName = new String("aa.stl");
loader.load(stlFileName, function(geometry) {
//创建纹理
var mat = new THREE.MeshPhongMaterial({ color: 0x836DED, specular: 0x111111, shininess: 100 });
var mesh = new THREE.Mesh(geometry, mat);
mesh.scale.set(0.01, 0.01, 0.01); //缩放
geometry.center(); //建立几何中心
mesh.position.set(0, -2, 0.5); //位置
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.name = "test";
objects.push(mesh);
scene.add(mesh);
});
}
//-----------------------------------------
//界面设置
function WxpGuiSetting() {
//存放所有需要改变的属性的对象
GuiControls = new function() {
this.rotationSpeed = 0.01;
this.camerPositionX = 4.00;
this.camerPositionY = -8.00;
this.camerPositionZ = 4.00;
};
//创建dat.GUI,传递并设置属性
var gui = new dat.GUI();
gui.add(GuiControls, 'rotationSpeed', 0, 0.5);
gui.add(GuiControls, 'camerPositionX', -40.0, 20.0);
gui.add(GuiControls, 'camerPositionY', -40.0, 10.0);
gui.add(GuiControls, 'camerPositionZ', 0.0, 40.0);
}
//渲染场景
function WxpRender() {
//更新必要的参数
cube.rotation.z += GuiControls.rotationSpeed;
camera.position.x = GuiControls.camerPositionX;
camera.position.y = GuiControls.camerPositionY;
camera.position.z = GuiControls.camerPositionZ;
WxpTexture.offset.x += 0.006;
//tture.rotation+= 0.01;
//鼠标控制旋转
//cube.rotation.z=mouseMoveX*0.02;
//document.getElementById("notice").innerHTML = cube.rotation.x.toFixed(2).toString();
//divRender();
//console.log(scene);
//通过requestAnimationFrame方法在特定时间间隔重新渲染场景,循环调用
requestAnimationFrame(WxpRender);
//渲染场景
renderer.render(scene, camera);
}
//-----------------------------------------
//ThreeJS仿真函数
function WxpThreeJSInit() {
//初始化场景
WxpInitScene();
//加载物体
WxpAddObject();
//界面设置
WxpGuiSetting();
//渲染场景
WxpRender();
}
//确保WxpThreeJSinit方法在网页加载完毕后被调用
window.onload = WxpThreeJSInit;
</script>
</body>
</html>