我已經看過很多示例 - 並從某些借用 - 似乎無法使其正常工作。我想要的是onDocumentMouseDown中的raycaster在用戶點擊精靈可見表面上的任何位置時拾取精靈。我得到的是一個未對齊的結果,因爲如果用戶在精靈的右側,上方或下方點擊某個精靈,並且根本不會在用戶點擊左側邊緣時完成拾取的精靈。所以基本上有些東西是錯位的,而且我搞不清楚我做錯了什麼。任何指導將不勝感激。無法使Three.js onDocumentMouseDown正常工作
<script src="/common/three.js"></script>
<script src="/common/Detector.js"></script>
<script src="/common/CanvasRenderer.js"></script>
<script src="/common/GeometryUtils.js"></script>
<script src="/common/OrbitControls.js"></script>
<div id="WebGLCanvas"></div>
<script>
var container, scene, camera, renderer, controls;
var keyboard;
</script>
<script>
// custom global variables
var mouse = { x: 0, y: 0 };
var raycaster;
var sprites = new Array();
init();
try {
for (i = 0; i < 10; i++) {
var text = "Text " + i;
var x = Math.random() * 100;
var y = Math.random() * 100;
var z = Math.random() * 100;
var spritey = addOrUPdateSprite(text, i, x, y, z);
}
}
catch (ex) {
alert("error when creating sprite: " + ex.message);
}
animate();
function init() {
try {
scene = new THREE.Scene();
// CAMERA
var cont = document.getElementById("WebGLCanvas");
var SCREEN_WIDTH = window.innerWidth;
OFFSET_TOP = document.getElementById("WebGLCanvas").getBoundingClientRect().top;
var SCREEN_HEIGHT = window.innerHeight - OFFSET_TOP; //; //-document.getElementById("upper").clientHeight;
var VIEW_ANGLE = 60;
var ASPECT = SCREEN_WIDTH/SCREEN_HEIGHT;
var NEAR = 0.1;
var FAR = 1000;
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0, 100, 200);
camera.lookAt(new THREE.Vector3());
renderer = new THREE.WebGLRenderer({ antialias: true });
container = document.getElementById('WebGLCanvas');
container.appendChild(renderer.domElement);
renderer.setSize(window.innerWidth, SCREEN_HEIGHT);
controls = new THREE.OrbitControls(camera, renderer.domElement);
// spritey.position.normalize();
raycaster = new THREE.Raycaster();
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('touchstart', onDocumentTouchStart, false);
}
catch (ex) {
alert("error " + ex.message);
}
}
function animate() {
requestAnimationFrame(animate);
render();
update();
}
function update() {
controls.update();
}
function render() {
renderer.render(scene, camera);
}
function addOrUPdateSprite(text, name, x, y, z) {
var sprite = scene.getObjectByName(name);
if (sprite == null) {
sprite = makeTextSprite(text, { fontsize: 36, borderColor: { r: 255, g: 0, b: 0, a: 1.0 }, backgroundColor: { r: 255, g: 100, b: 100, a: 0.8 } });
sprite.name = name;
sprites.push(sprite);
scene.add(sprite);
}
sprite.position.set(x, y, z);
}
function makeTextSprite(message, parameters) {
if (parameters === undefined) parameters = {};
var fontface = parameters.hasOwnProperty("fontface") ? parameters["fontface"] : "sans-serif";
var fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 36;
var borderThickness = parameters.hasOwnProperty("borderThickness") ? parameters["borderThickness"] : 1;
var borderColor = parameters.hasOwnProperty("borderColor") ? parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 };
var backgroundColor = parameters.hasOwnProperty("backgroundColor") ? parameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 };
var textColor = parameters.hasOwnProperty("textColor") ? parameters["textColor"] : { r: 0, g: 0, b: 0, a: 1.0 };
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.font = fontsize + "px " + fontface;
var metrics = context.measureText(message);
var textWidth = metrics.width;
context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," + backgroundColor.b + "," + backgroundColor.a + ")";
context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," + borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
roundRect(context, borderThickness/2, borderThickness/2, (textWidth + borderThickness) * 1.1, fontsize * 1.4 + borderThickness, 8);
context.fillStyle = "rgba(" + textColor.r + ", " + textColor.g + ", " + textColor.b + ", 1.0)";
context.fillText(message, borderThickness, fontsize + borderThickness);
var texture = new THREE.Texture(canvas)
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture, useScreenCoordinates: false });
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(1.0 * fontsize, 0.5 * fontsize, 1.5 * fontsize);
return sprite;
}
// function for drawing rounded rectangles
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function onDocumentTouchStart(event) {
event.preventDefault();
event.clientX = event.touches[0].clientX;
event.clientY = event.touches[0].clientY;
onDocumentMouseDown(event);
}
function onDocumentMouseDown(event) {
mouse.x = (event.clientX/renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -((event.clientY)/renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(sprites, true);
if (intersects.length > 0) {
var obj = intersects[0].object;
alert(obj.name);
event.preventDefault();
}
}
</script>
有趣,謝謝!我認爲這解釋了爲什麼廣泛的截斷。你知道是否有任何方法讓實際大小隻是需要的? –
感謝prisoner849,這是非常有用的,因爲它已修復了我不知道的畫布寬度問題,現在文本不再被截斷,並且在可見精靈之外單擊不會被拾取。然而,仍然存在一個問題,那就是精靈左側的點擊仍然沒有被拾取,點擊精靈最右側也是如此。就好像射線照相機現在認爲精靈比它小。你的jsfiddle似乎承擔了這一點。這是一個戲劇性的改進,所以我很感激!任何更多的技巧你的冷笑? –
我發現這個[SO問題](http://stackoverflow.com/questions/36123458/three-raycaster-not-working-properly-with-scaled-three-sprite)。簡而言之:精靈越接近正方形(方形)越好。因此,最好儘可能靠近精靈的中心點。 – prisoner849