问题描述
我正在尝试使用Three.JS重新创建Flash网站,但是尝试创建某些功能时遇到了麻烦。
应该发生的是,我想让一些按钮图像围绕屏幕中心旋转。如果将鼠标悬停在它们上方,然后单击以打开网站上的其他位置,则应该能够将其停止。
我一切正常,直到鼠标悬停在按钮上时要求按钮停止。我试图使用光线投射来实现这一点,但是当我在场景中移动鼠标时,似乎网格与渲染的纹理不在同一位置。实际上,似乎网格物体和渲染的图像的旋转方向彼此相反。
这是我的代码,我将您链接到我的网站上的一个页面,在此页面上我将测试此改进,以便您可以找到真实的示例:
<!DOCTYPE html>
<html>
<head>
<Meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
body { margin: 0;}
canvas { display: block;}
</style>
</head>
<body>
<script>
//var THREE = new THREE();
var renderer,scene,camera,nucleus;
var width = window.innerWidth;
var height = window.innerHeight;
var fov = 60;
var near = 1;
var far = 10000;
var min = 0;
var max = 10;
var insObjSpeed = 0;
var buttons = [];
var numOfBtns = 1;
var projector,mouse = { x: 0,y: 0 },INTERSECTED;
//var mouse;
function populateScene(){
var geom = new THREE.CircleGeometry(3,50);
var matTx = new THREE.TextureLoader().load('imgs/buttons/logo.png');
var mat = new THREE.MeshBasicMaterial({map:matTx});
nucleus = new THREE.Mesh(geom,mat);
nucleus.position.set(0,0);
scene.add(nucleus);
var btn = null;
var btnMat = null;
var plane = new THREE.Plane();
var point = new THREE.Vector3();
var btnMats = [new THREE.TextureLoader().load('imgs/buttons/georo.png'),new THREE.TextureLoader().load('imgs/buttons/wiki.png'),new THREE.TextureLoader().load('imgs/buttons/port.png'),new THREE.TextureLoader().load('imgs/buttons/yt.png'),new THREE.TextureLoader().load('imgs/buttons/l2r.png'),new THREE.TextureLoader().load('imgs/buttons/ci.png'),new THREE.TextureLoader().load('imgs/buttons/ov.png'),new THREE.TextureLoader().load('imgs/buttons/ttv.png'),new THREE.TextureLoader().load('imgs/buttons/tw.png'),new THREE.TextureLoader().load('imgs/buttons/ffs.png')];
var usedMats = [];
for (var i1 = 0; i1 < numOfBtns; i1++){
var matIdx = Math.floor(Math.random() * (max - min + 1)) + min;
var matTx = btnMats[matIdx];
if (usedMats.includes(matTx)){
while (usedMats.includes(matTx)){
matIdx = Math.floor(Math.random() * (max - min + 1)) + min;
matTx = btnMats[matIdx];
}
}
usedMats.push(matTx);
//var matTx = new THREE.TextureLoader().load('imgs/buttons/georo.png')
var geom2 = new THREE.CircleGeometry(3,50);
var mat = new THREE.MeshBasicMaterial({map:matTx});
btn = new THREE.Mesh(geom2,mat);
btn.angle = new THREE.Vector3(Math.random(),Math.random(),Math.random()).normalize();
btn.orbitSpeed = 0.0045; //Math.random() * 0.05) * 0.5;
plane.normal.copy(btn.angle);
point.set(Math.random(),Math.random());
plane.projectPoint(point,btn.position);
if (Math.random() > 0.5) { btn.orbitSpeed *= -1; }
btn.position.setLength(Math.floor(Math.random() * 20) + 15);
btn.position.applyAxisAngle(btn.angle,Math.random() / 10);
btn.position.add(nucleus.position);
buttons.push(btn);
scene.add(btn);
}
}
function updateBtns() {
var obj = null;
for (var i1 = 0; i1 < numOfBtns; i1++){
obj = buttons[i1];
obj.position.sub(nucleus.position);
obj.position.applyAxisAngle(obj.angle,obj.orbitSpeed);
obj.position.add(nucleus.position);
//if (i1 == 0){ console.log(obj.position); }
}
}
function init() {
document.body.style.backgroundColor = "#333333";
renderer = new THREE.Webglrenderer({
antialias: true,alpha: true
});
mouse = new THREE.Vector2();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
document.body.style.overflow = "hidden";
document.body.style.margin = "0";
document.body.style.padding = "0";
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(fov,width/height,near,far);
camera.position.z = 100;
scene.add(camera);
//controls = new THREE.trackballControls(camera,renderer.domElement);
document.addEventListener( 'mousemove',onDocumentMouseMove,false );
projector = new THREE.Projector();
resize();
window.onresize = resize;
populateScene();
animate();
}
function onDocumentMouseMove( event )
{
// the following line would stop any other event handler from firing
// (such as the mouse's trackballControls)
event.preventDefault();
// update the mouse variable
mouse.x = ( event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -( event.clientY / renderer.domElement.clientHeight) * 2 + 1;
console.log("mouse pos: " + mouse.x + "," + mouse.y);
}
function resize(){
width = window.innerWidth;
height = window.innerHeight;
if (renderer && camera){
renderer.setSize(width,height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function render(){
renderer.render(scene,camera);
}
function animate(){
checkMouse();
requestAnimationFrame(animate);
updateBtns();
render();
//checkMouseHover();
}
function checkMouse(){
var vector = new THREE.Vector3( mouse.x,mouse.y,1 );
console.log("ray vec: " + vector.x + "," + vector.y);
projector.unprojectVector( vector,camera );
var ray = new THREE.Raycaster( camera.position,vector.sub( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( scene.children,true );
// INTERSECTED = the object in the scene currently closest to the camera
// and intersected by the Ray projected from the mouse position
// if there is one (or more) intersections
if ( intersects.length > 0 ) {
// if the closest object intersected is not the currently stored intersection object
if ( intersects[ 0 ].object != INTERSECTED && intersects[0].object !== nucleus) {
// restore prevIoUs intersection object (if it exists) to its original color
if ( INTERSECTED ) {
console.log("Intersection detected at: " + intersects[0].point);
INTERSECTED = intersects[0].object;
INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
// store reference to closest object as current intersection object
// store color of closest object (for later restoration)
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
// set a new color for closest object
INTERSECTED.material.color.setHex( 0xffff00 );
}
}
}
else { // there are no intersections
// restore prevIoUs intersection object (if it exists) to its original color
if ( INTERSECTED ) { INTERSECTED.material.color.setHex( INTERSECTED.currentHex ); }
// remove prevIoUs intersection object reference
// by setting current intersection object to "nothing"
INTERSECTED = null;
}
}
function onMouSEOver(ev){
insObjSpeed = ev.object.orbitSpeed;
//ev.object.orbitSpeed = 0.0;
}
function onMouSEOut(ev) { ev.object.orbitSpeed = insObjSpeed; }
function THREEReady() { init(); }
function onMouseMove(event){
mouse.x = (event.clientX/width)*2-1;
mouse.y = (event.clientY/height)*2-1;
}
(function() {
window.addEventListener('mousemove',onMouseMove,false);
function addScript(url,callback){
callback = callback || function() {};
var script = document.createElement("script");
script.addEventListener("load",callback);
script.setAttribute("src",url);
document.head.appendChild(script);
}
addScript("./js/ThreeJS_0.119.1.js",function() {
addScript("./js/ThreeJS_0.119.1_Projector.js",function(){
THREEReady();
})});
})();
</script>
</body>
解决方法
对于初学者来说,您的mouseMove()
在进行y值计算之前缺少负号。这意味着您的y值会被翻转(应为-1
时为+1
),应如下所示:
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
第二,我不确定为什么只使用现有的mouse
Vector2作为outlined in the docs时为什么要在每个帧上创建一个新的Vector3。
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse,camera );
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
无需执行unprojectVector
然后减去摄像机位置,或者如果您使用setFromCamera()
,则无需执行任何操作。
编辑:只要意识到您还有两个相互覆盖的侦听器(onMouseMove
和onDocumentMouseMove
),其中一个侦听器使用错误的公式来计算mouse.y
,这就是为什么重新获得一个反向的y值。