I've been having issues with three.js raycasting recently.
I have a div element for which the element is not the full screen and it should not be the full screen and I think this is causing issues with the positioning of the raycast which I don't know how to fix.
let mouseVector = new THREE.Vector3()
let raycaster = new THREE.Raycaster()
Object.assign(mouseVector, {
x: 2 * (e.clientX / canvas.width) - 1,
y: 1 - 2 * (e.clientY / canvas.height)
})
raycaster.setFromCamera(mouseVector, camera)
let intersects = raycaster.intersectObject(scene.children)
for(const intersection of intersects) {
console.log(intersection)
}
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( scene.children, true );
console.log(intersects);
for(const ray of intersects) {
if(ray.object.name !== "Grid") {
if(smallestDist == undefined){
smallestDist1 = ray;
}else if(smallestDist > ray.distance){
smallestDist1 = ray
}
}
}
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
if(intersects[i].object.name == "Grid"){
}else{
if(smallestDist == undefined){
smallestDist = intersects[i];
}else if(smallestDist > intersects[i].distance){
smallestDist = intersects[i]
}
}
}
console.log(smallestDist1)
if(smallestDist1){
const geometry = new THREE.SphereGeometry( 0.5, 15, 15 );
const material = new THREE.MeshBasicMaterial( {color: 0xFF0000} );
const sphere = new THREE.Mesh( geometry, material );
sphere.position.set(smallestDist1.point.x, smallestDist1.point.y, smallestDist1.point.z)
sphere.name = "TestSphere"
scene.add( sphere );
}
Above is the code i've tried however as the element with the 3D object isn't full window sized I think it's bugging out. Any help is appreciated.
Try to compute mouse like so:
const rect = renderer.domElement.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
mouse.x = ( x / canvas.clientWidth ) * 2 - 1;
mouse.y = ( y / canvas.clientHeight) * - 2 + 1
The top-left point of the browser window is the origin of coordinate (0, 0) for MouseEvent, while the exact center point of canvas for threejs.
Click here to see coordinate details.
As shown the image above, four corner points of the canvas is equivalent to (-1, 1), (1, 1), (1, -1), (-1, -1) under threejs context.
Otherwise, the canvas might have offsets to the browser (0, 0), which can be accessed with canvas.offsetTop and cavas.offsetLeft.
With all above considered, any MouseEvent client coordinate (event.clientX, event.clientY) should be mapped to threejs coordinate as below:
mouse.x = ( (event.clientX - canvas.offsetLeft) / canvas.clientWidth ) * 2 - 1;
mouse.y = ( (event.clientY - canvas.offsetTop) / canvas.clientHeight ) * -2 + 1;
Related
I'm trying to line up some ellipse with the endpoint of a line that moves and rotates, and the end goal is to be able to calculate the coordinates of said endpoint. I can calculate the initial position, but as soon as I move the car all of the ellipses go in the opposite direction. I'm not great at geometry and I can't figure out why it's doing this or how to fix it.
What I have so far:
sketch.js
// Declares global variables
const h = window.innerHeight;
const w = window.innerWidth;
var car;
var borders = [];
var pos = {
x: w / 2,
y: h / 2,
angle: 0
}
function setup () {
// Creates the canvas
background ( '#000000' );
createCanvas ( w, h );
angleMode ( DEGREES );
rectMode ( CENTER );
stroke ( 255 );
// Creates some borders
borders.push ( new Border ( 0, height / 2, width, height / 2 ) );
// Creates the car
car = new Car();
}
function draw () {
// Clears the canvas
background ( '#000000' );
fill("white");
// Displays the borders
for ( var border of borders ) {
border.show();
}
// Moves the car
if ( keyIsDown ( UP_ARROW ) ) {
car.forward();
}
if ( keyIsDown ( DOWN_ARROW ) ) {
car.backward();
}
// Checks if the car is intersecting
const intersection = car.intersects ( borders );
car.emit(borders);
if ( intersection ) {
fill("red");
}
// Displays the car on the canvas
translate(pos.x, pos.y);
rotate(pos.angle);
car.show();
}
car.js
class Car {
// Defines the class
constructor ( ) {
this.pos = createVector ( 0, 0 );
this.width = 20;
this.length = 40;
this.speed = 0;
this.rays = [];
// Creates the car's rays
for ( var x = 0; x < 360; x += 20 ) {
this.rays.push ( new Ray ( createVector ( this.pos.x, this.pos.y ), radians ( x ) ) );
}
}
// Displays the car on the canvas
show () {
// Displays the car
rect ( this.pos.x, this.pos.y, this.width, this.length );
// Displays the rays
for ( var ray of this.rays ) {
ray.show();
}
}
// Checks if any rays are intersecting a border
emit ( borders ) {
// Loops through all the rays
for ( var ray of this.rays ) {
// Loops through all the borders
for ( var border of borders ) {
const intersection = ray.intersects ( border );
if ( intersection ) {
console.log(intersection);
}
}
}
}
// Moves forward
forward () {
pos.y -= cos(pos.angle) * 4;
pos.x += sin(pos.angle) * 4;
// Steers left
if ( keyIsDown ( LEFT_ARROW ) ) {
pos.angle -= 3;
}
// Steers right
if ( keyIsDown ( RIGHT_ARROW ) ) {
pos.angle += 3;
}
}
// Moves backward
backward () {
pos.y += cos(pos.angle) * 4;
pos.x -= sin(pos.angle) * 4;
// Steers left
if ( keyIsDown ( LEFT_ARROW ) ) {
pos.angle -= 3;
}
// Steers right
if ( keyIsDown ( RIGHT_ARROW ) ) {
pos.angle += 3;
}
}
// Checks if the car is intersecting any borders
intersects ( borders ) {
// Calculates the car's corners
var corners = [
createVector ( pos.x - ( this.width / 2 ), pos.y - ( this.length / 2 ) ),
createVector ( pos.x + ( this.width / 2 ), pos.y - ( this.length / 2 ) ),
createVector ( pos.x + ( this.width / 2 ), pos.y + ( this.length / 2 ) ),
createVector ( pos.x - ( this.width / 2 ), pos.y + ( this.length / 2 ) )
];
var sides = [
[
corners[0],
corners[1]
],
[
corners[1],
corners[2]
],
[
corners[2],
corners[3]
],
[
corners[3],
corners[0]
]
];
// Loops through each side
for ( var side of sides ) {
// Loops through each border
for ( var border of borders ) {
var x1 = side[0].x;
var y1 = side[0].y;
var x2 = side[1].x;
var y2 = side[1].y;
const x3 = border.x.x;
const y3 = border.x.y;
const x4 = border.y.x;
const y4 = border.y.y;
// Rotates the corners relative to the car
var tempX1 = x1 - pos.x;
var tempY1 = y1 - pos.y;
var tempX2 = x2 - pos.x;
var tempY2 = y2 - pos.y;
var rotatedX1 = tempX1 * cos ( pos.angle ) - tempY1 * sin ( pos.angle );
var rotatedY1 = tempX1 * sin ( pos.angle ) + tempY1 * cos ( pos.angle );
var rotatedX2 = tempX2 * cos ( pos.angle ) - tempY2 * sin ( pos.angle );
var rotatedY2 = tempX2 * sin ( pos.angle ) + tempY2 * cos ( pos.angle );
x1 = rotatedX1 + pos.x;
y1 = rotatedY1 + pos.y;
x2 = rotatedX2 + pos.x;
y2 = rotatedY2 + pos.y;
// Checks if the car is intersecting
const d = ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 );
const t = ( x1 - x3 ) * ( y3 - y4 ) - ( y1 - y3 ) * ( x3 - x4 ) / d;
if ( 0 <= t && t <= 1 ) {
return createVector ( x1 + t * ( x2 - x1 ), y1 + t * ( y2 - y1 ) );
}
}
}
}
}
ray.js
class Ray {
// Defines the class
constructor ( position, angle ) {
this.pos = position;
this.angle = angle;
this.dir = p5.Vector.fromAngle ( angle );
}
// Checks if the ray is intersecting a border
intersects ( border ) {
// const endpoints = [
// ];
var x1 = pos.x;
var y1 = pos.y;
var x2 = this.dir.x * 100;
var y2 = this.dir.y * 100;
const x3 = border.x.x;
const y3 = border.x.y;
const x4 = border.y.x;
const y4 = border.y.y;
// Rotates the corners relative to the car
var tempX2 = x2 - pos.x;
var tempY2 = y2 - pos.y;
var rotatedX2 = tempX2 * cos ( pos.angle ) - tempY2 * sin ( pos.angle );
var rotatedY2 = tempX2 * sin ( pos.angle ) + tempY2 * cos ( pos.angle );
x2 = rotatedX2 + pos.x;
y2 = rotatedY2 + pos.y;
/* This is where I'm having difficulty */
push();
translate(pos.x, pos.y);
ellipse(x2, y2, 10);
pop();
// const den = ( ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 ) );
// if ( den == 0 ) {
// console.log(1);
// return;
// }
// var t = ( ( x1 - x3 ) * ( y3 - y4 ) - ( y1 - y3 ) * ( x3 - x4 ) ) / den;
// var u = ( ( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 ) ) / den;
// if ( 0 <= t && t <= 1 ) {
// const x = x1 + t * ( x2 - x1 );
// const y = y1 + t * ( y2 - y1 );
// // return createVector ( x, y );
// ellipse ( x, y, 10 );
// }
// return;
}
// Displays the ray on the canvas
show () {
push();
translate(this.pos.x, this.pos.y);
line(0, 0, this.dir.x * 100, this.dir.y * 100);
pop();
}
}
border.js
class Border {
// Defines the class
constructor ( x1, y1, x2, y2 ) {
this.x = createVector ( x1, y1 );
this.y = createVector ( x2, y2 );
}
show () {
stroke ( 255 );
line ( this.x.x, this.x.y, this.y.x, this.y.y );
}
}
My interpretation is that in lines 31-36 of ray.js, you're trying to rotate the point x2, y2 by pos.angle. You actually don't need to do any trig in order to do that.
In the trig, you subtracted off pos from this.dir. But this.dir was already a vector whose base was at the position of the car, so the coordinates of this.dir were already relative to the position of the car. Here is one solution, where x2 and y2 are initialized with the rotation:
var x2 = this.dir.x * 100 * cos ( pos.angle ) -
this.dir.y * 100 * sin ( pos.angle );
var y2 = this.dir.x * 100 * sin ( pos.angle ) +
this.dir.y * 100 * cos ( pos.angle );
As I said above, though, you don't have to do any trig. You can make use of the .rotate() method:
var x2 = this.dir.copy().rotate(radians(pos.angle)).x * 100;
var y2 = this.dir.copy().rotate(radians(pos.angle)).y * 100;
NOTE: you need to convert to radians when using .rotate() and other vector methods because angleMode() does not affect vectors.
In both of these solutions, you should get rid of lines 31-36.
I think you might run into problems, however, when you try to apply this. Since x2 and y2 are relative to the car's position, they are not the actual endpoints of the lines drawn on the screen. Rather, they are in a circle of points up by the top left corner. If you were to try to test whether the line segment between x1, y1 and x2, y2 intersects with the line segment between x3, y3 and x4, y4, you would get that it only intersects when the border is between pos and the top left corner.
I think what you're actually looking for is
var x2 = this.dir.copy().rotate(radians(pos.angle)).x + pos.x;
var y2 = this.dir.copy().rotate(radians(pos.angle)).y + pos.y;
NOTE: you would also have to get rid of the translation when you display the ellipses in order for this to look right.
When I uncomment your other code in ray.js, it behaves better in this last version.
Additionally, you seem to multiply this.dir.x and this.dir.y by 100 every time you refer to them. You can omit this if you make this.dir 100 pixels long, which is built into the .fromAngle() method:
this.dir = p5.Vector.fromAngle(angle, 100);
will give you a vector in the proper direction with length 100.
I want to detect a click event on a three.js sprite here's the code:
function bindEvents(state) {
let intersected;
function onDocumentMouseDown(event) {
event.preventDefault();
const mouseX = (event.clientX / window.innerWidth) * 2 - 1;
const mouseY = - (event.clientY / window.innerHeight) * 2 + 1;
const camera = state.threeD.elements.camera;
const raycaster = state.threeD.raycaster;
raycaster.setFromCamera(new THREE.Vector2(mouseX, mouseY), camera);
var intersects = raycaster.intersectObjects(state.clickables?state.clickables:[]);
if (intersects.length > 0) {
if (intersected) intersected.material.map = intersected.currentMap;
intersected = intersects[0].object;
intersected.currentMap = intersected.material.map;
intersected.material.map = selectCityTexture(128, '#cccccc', 'cccccc');
}
}
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('touchstart', onDocumentMouseDown, false);
}
This almost works, the mouse position is offset by some amount. Probably some calculation error, I have no idea how the above code works please help.
const mouseX = (event.clientX / window.innerWidth) * 2 - 1;
const mouseY = - (event.clientY / window.innerHeight) * 2 + 1;
these are changed with
const mouseX = (event.clientX / canvas.width) * 2 - 1;
const mouseY = - (event.clientY / canvas.height) * 2 + 1;
I have an annoying problem where my raycasting is fine with the mouse but not with touch.
I setup events as such
$(document).bind('mousedown', onDocumentMouseDown);
$(document).bind('mousewheel', onDocumentMouseWheel);
$(document).bind('touchstart', onDocumentTouchStart);
$(document).bind('touchmove', onDocumentTouchMove);
My mouse event
function onDocumentMouseDown(e) {
e.preventDefault();
detectHotspotClick(e.pageX,e.pageY);
}
My Touch event
function onDocumentTouchStart(e) {
e.preventDefault();
var event = e.originalEvent;
if (event.touches.length == 1) {
var t=event.touches[0];
draggingY = t.pageY;
detectHotspotClick(t.pageX,t.pageY);
}
if (event.touches.length == 2) {
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
}
}
My detection
function detectHotspotClick(x,y){
console.log('detectHotspotClick('+ x + "," + y+ ")" );
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
mouse.x = ( x / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( y / renderer.domElement.height ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( targetList, true );
if ( intersects.length > 0)
hotspotClick(intersects[ 0 ].object);
}
This works fine with mouse, but I notice on Touch, the mouse.x value always seems to be negetative and I'm not sure that's right.
Is there any other way of doing this I should consider?
Not sure why.. but it works with detectHotspotClick(t.pageX*2,t.pageY*2) on the touchevent, which must report different figures to the mouse event.
I'm trying to find the distance that the mouse has traveled along a normal vector.
The idea is to move a set of vertices within an object along the intersecting face's normal vector.
Currently, I have an onmousedown event handler that finds the intersecting face, adjacent faces with the same normal, and the vertices associated to those faces. I also have an onmousemove event handler that moves the vertices along the normal.
Right now, the onmousemove just moves the vertices 1 unit along the face normal every time the event is fired. I'd like them to move with the mouse.
The code that I am working off of came largely from the three.js editor. Any help is very much appreciated, thanks!
var object; // Set outside this code
var camera; // Set outside this code
var viewport; // Set outside this code
var raycaster = new THREE.Raycaster();
var point = new THREE.Vector2();
var mouse = new THREE.Vector2();
var _dragging = false;
var faces = [];
var vertices = [];
function onMouseDown(event) {
if (object === undefined || _dragging === true) {
return;
}
event.preventDefault();
event.stopPropagation();
var intersect = getIntersects(event, object)[0];
if (intersect && intersect.face) {
faces = getAdjacentNormalFaces(intersect.object.geometry, intersect.face);
vertices = getFaceVertices(intersect.object.geometry, self.faces);
}
_dragging = true;
}
function onMouseMove(event) {
if (object === undefined || vertices.length === 0 || _dragging === false) {
return;
}
event.preventDefault();
event.stopPropagation();
var normal = faces[0].normal;
/*
* Get the distance to move the vertices
*/
var distance = 1;
var i;
for (i = 0; i < self.vertices.length; i++) {
self.vertices[i].x += (normal.x * distance);
self.vertices[i].y += (normal.y * distance);
self.vertices[i].z += (normal.z * distance);
}
object.geometry.verticesNeedUpdate = true;
object.geometry.computeBoundingBox();
object.geometry.computeBoundingSphere();
}
var getIntersects = function (event, object) {
var rect = viewport.getBoundingClientRect();
point.fromArray([
( event.clientX - rect.left ) / rect.width,
( event.clientY - rect.top ) / rect.height
]);
mouse.set(( point.x * 2 ) - 1, -( point.y * 2 ) + 1);
raycaster.setFromCamera(mouse, camera);
if (object instanceof Array) {
return raycaster.intersectObjects(object);
}
return raycaster.intersectObject(object);
};
var getAdjacentNormalFaces = function (geometry, face) {
// Returns an array of all faces that are adjacent and share the same normal vector
};
var getFaceVertices = function (geometry, faces) {
// Returns an array of vertices that belong to the array of faces
};
Update:
As a summary... I have the event handlers, the set of vertices that need to be moved and the normal vector that the vertices should be moved on. What I need is the offset distance that the vertices should be moved based on where the mouse is.
My first thought is to create a plane perpendicular to the normal vector and track the mouse position on that plane. However, I am not sure 1. how to create the perpendicular plane where the largest side is visible to the camera and 2. how to translate the x/y coordinates of the mouse on the plane to the distance the vertices should be moved.
The way I solved this is to map the zero and normal points on the 2D plane and then use the inverse slope to find the perpendicular line that intersects the normal line. I can then use the starting point and the point of intersection to find the distance the mouse moved. I also had to scale the final distance using the camera.
For a quick reference:
// linear slope/intercept: y = mx + b
// solve for b: b = y - mx
// solve for m: (y2 - y1) / (x2 - x1)
// get inverse slope: -1 / m
// get intersect point: (b2 - b1) / (m1 - m2)
There may be an easier way but this is what I did and hopefully it helps others:
On Mousedown
Project the center (0,0,0) vector, the face normal vector and an arbitrary 1 unit vector (1,0,0) onto the camera and get the screen position of the three points
var zero2D = toScreenPosition(0, 0, 0);
var one2D = toScreenPosition(1, 0, 0);
var normal2D = toScreenPosition(intersect.face.normal.x, intersect.face.normal.y, intersect.face.normal.z);
/ ***** /
var toScreenPosition = function (x, y, z) {
var rect = viewport.getBoundingClientRect();
var point = new THREE.Vector2();
screenPositionVector.set(x || 0, y || 0, z || 0);
screenPositionVector.project(camera);
point.set((screenPositionVector.x + 1) / 2 * rect.width, -(screenPositionVector.y - 1) / 2 * rect.height);
return point;
};
Store the mouse starting point and the x direction of the normal (1 or -1).
start2D.set(event.clientX, event.clientY);
normalDir = zero2D.x < normal2D.x ? 1 : -1;
Store the slope and inverse slope of the zero/normal line.
slope = (normal2D.y - zero2D.y) / (normal2D.x - zero2D.x); // TODO: Handle zero slope
inverseSlope = -1 / slope; // TODO: If slope is 0, inverse is infinity
Store the y intercept of the normal line based on the mouse coordinates.
startingYIntercept = event.clientY - (slope * event.clientX);
Use the zero2D and one2D point to find the camera scale. The camera scale is the distance between the two 2D points divided by the distance between the two 3D points (1).
cameraScale = one2D.distanceTo(zero2D);
For better accuracy, we are going to move the vertices based on total movement, not the delta between event handler calls. Because of this, we need to track the starting position of all the vertices.
startingVertices = [];
var i;
for (i = 0; i < vertices.length; i++) {
startingVertices.push({x: vertices[i].x, y: vertices[i].y, z: vertices[i].z});
}
On Mousemove
Using the mouse position and the inverse slope, find the perpendicular line's y intercept.
var endingYIntercept = event.clientY - (inverseSlope * event.clientX);
Use the intercept equation to find the x location where the normal line and perpendicular line intercept.
var endingX = (endingYIntercept - startingYIntercept) / (slope / inverseSlope);
Plug x back in to find the y point. Since the lines intercept at x, you can use either the normal line or perpendicular line. Set the end point based on this.
var endingY = (slope * endingX) + startingYIntercept;
end2D.set(endingX, endingY);
Find the distance between the points and divide by the camera scale.
var distance = end2D.distanceTo(start2D) / cameraScale;
If the normal is in the opposite direction of the mouse movement, multiply distance by -1.
if ((normalDir > 0 && endingX < start2D.x) || (normalDir < 0 && endingX > start2D.x)) {
distance = distance * -1;
}
Since we are moving the vertices by a total distance and not the delta between event handlers, the vertex update code is a little different.
var i;
for (i = 0; i < self.vertices.length; i++) {
vertices[i].x = startingVertices[i].x + (normal.x * distance);
vertices[i].y = startingVertices[i].y + (normal.y * distance);
vertices[i].z = startingVertices[i].z + (normal.z * distance);
}
Extra Credit On Mouseup
When the vertices are moved, the geometry's center is not changed and needs to be updated. To update the center, I can call geometry.center(), however, in Three.js, the geometry's position is based off of its center so this will effectively move the center and the position of the geometry in the opposite direction at half the distance of the vertex move. I don't want this, I want the geometry to stay in the same position when I move the vertices. To do this, I take the first vertex's ending position minus its start position divided by 2 and add that vector to the geometry's position. I then recenter the geometry.
if (_dragging && self.vertices.length > 0) {
offset.set(self.vertices[0].x - startingVertices[0].x, self.vertices[0].y - startingVertices[0].y, self.vertices[0].z - startingVertices[0].z);
offset.divideScalar(2);
object.position.add(offset);
object.geometry.center();
}
All Together
var object; // Set outside this code
var camera; // Set outside this code
var viewport; // Set outside this code
var raycaster = new THREE.Raycaster();
var point = new THREE.Vector2();
var mouse = new THREE.Vector2();
var _dragging = false;
var faces = [];
var vertices = [];
var startingVertices = [];
var slope = 0;
var inverseSlope;
var startingYIntercept = 0;
var normalDir = 1;
var cameraScale = 1;
var start2D = new THREE.Vector2();
var end2D = new THREE.Vector2();
var offset = new THREE.Vector3();
var onMouseDown = function (event) {
if (object === undefined || _dragging === true) {
return;
}
event.preventDefault();
event.stopPropagation();
var intersect = getIntersects(event, object)[0];
if (intersect && intersect.face) {
var zero2D = toScreenPosition(0, 0, 0);
var one2D = toScreenPosition(1, 0, 0);
var normal2D = toScreenPosition(intersect.face.normal.x, intersect.face.normal.y, intersect.face.normal.z);
start2D.set(event.clientX, event.clientY);
normalDir = zero2D.x < normal2D.x ? 1 : -1;
slope = (normal2D.y - zero2D.y) / (normal2D.x - zero2D.x); // TODO: Handle zero slope
inverseSlope = -1 / slope; // TODO: If slope is 0, inverse is infinity
startingYIntercept = event.clientY - (slope * event.clientX);
cameraScale = one2D.distanceTo(zero2D);
faces = getAdjacentNormalFaces(intersect.object.geometry, intersect.face);
vertices = getFaceVertices(intersect.object.geometry, self.faces);
startingVertices = [];
var i;
for (i = 0; i < vertices.length; i++) {
startingVertices.push({x: vertices[i].x, y: vertices[i].y, z: vertices[i].z});
}
}
_dragging = true;
}
var onMouseMove = function (event) {
if (object === undefined || vertices.length === 0 || _dragging === false) {
return;
}
event.preventDefault();
event.stopPropagation();
var normal = faces[0].normal;
var endingYIntercept = event.clientY - (inverseSlope * event.clientX);
var endingX = (endingYIntercept - startingYIntercept) / (slope / inverseSlope);
var endingY = (slope * endingX) + startingYIntercept;
end2D.set(endingX, endingY);
var distance = end2D.distanceTo(start2D) / cameraScale;
if ((normalDir > 0 && endingX < start2D.x) || (normalDir < 0 && endingX > start2D.x)) {
distance = distance * -1;
}
var i;
for (i = 0; i < self.vertices.length; i++) {
vertices[i].x = startingVertices[i].x + (normal.x * distance);
vertices[i].y = startingVertices[i].y + (normal.y * distance);
vertices[i].z = startingVertices[i].z + (normal.z * distance);
}
object.geometry.verticesNeedUpdate = true;
object.geometry.computeBoundingBox();
object.geometry.computeBoundingSphere();
}
var onMouseUp = function (event) {
if (_dragging && vertices.length > 0) {
offset.set(vertices[0].x - startingVertices[0].x, vertices[0].y - startingVertices[0].y, vertices[0].z - startingVertices[0].z);
offset.divideScalar(2);
object.position.add(offset);
object.geometry.center();
}
}
var getIntersects = function (event, object) {
var rect = viewport.getBoundingClientRect();
point.fromArray([
( event.clientX - rect.left ) / rect.width,
( event.clientY - rect.top ) / rect.height
]);
mouse.set(( point.x * 2 ) - 1, -( point.y * 2 ) + 1);
raycaster.setFromCamera(mouse, camera);
if (object instanceof Array) {
return raycaster.intersectObjects(object);
}
return raycaster.intersectObject(object);
};
var toScreenPosition = function (x, y, z) {
var rect = viewport.getBoundingClientRect();
var point = new THREE.Vector2();
screenPositionVector.set(x || 0, y || 0, z || 0);
screenPositionVector.project(camera);
point.set((screenPositionVector.x + 1) / 2 * rect.width, -(screenPositionVector.y - 1) / 2 * rect.height);
return point;
};
var getAdjacentNormalFaces = function (geometry, face) {
// Returns an array of all faces that are adjacent and share the same normal vector
};
var getFaceVertices = function (geometry, faces) {
// Returns an array of vertices that belong to the array of faces
};
You could achieve two ways, on mouse move or in animationframe.
onmouseMove(){
mouseX = ( event.clientX - windowHalfX ) / resistanceh;
mouseY = ( event.clientY - windowHalfY ) / resistancew;
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
if ( intersects.length > 0 ) {
if(mousedown){
//do your thing
}
or in your animation updating these values is more accurate I found.
AnimationFrame(){
mouseX = ( event.clientX - windowHalfX ) / resistanceh;
mouseY = ( event.clientY - windowHalfY ) / resistancew;
I'm experimenting with WebGL and Three.js,
But how to calculate the Z-Axis coordination while moving mouse?
I use this for X and Y:
function getCoord(e) {
X = e.layerX - canvas.offsetLeft;
Y = e.layerY - canvas.offsetTop;
}
how to get Z coordination?
Edit: I find this example, but can't figure it out myself...
https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_voxelpainter.html
Thanks
Here is the answer...
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse2D.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse2D.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function render() {
mouse3D = projector.unprojectVector( mouse2D.clone(), camera );
...