Hi.
I am trying to modify the model viewer project to rotate the model only when the player drags on the object itself. I am doing a raycast from the camera and saving a reference to the target entity and rotating it. It’s working as expected on desktop, but not on mobile. Raycast hit result is always null. I found another forum post saying that the raycast center is inaccurate on mobile, but I tried touching ever where on the screen and I am always getting null.
Here is a demo project:
https://playcanvas.com/project/1098879/overview/model-viewer
This is the only active/relevant script, attached to the camera:
var RaycastRotate = pc.createScript('raycastRotate');
RaycastRotate.attributes.add('orbitSensitivity', {
type: 'number',
default: 0.3,
title: 'Orbit Sensitivity',
description: 'How fast the camera moves around the orbit. Higher is faster'
});
RaycastRotate.prototype.initialize = function() {
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
this.app.mouse.on(pc.EVENT_MOUSEUP, this.onMouseUp, this);
console.log(this.app.touch);
if (this.app.touch) {
this.app.touch.on(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
this.app.touch.on(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
this.app.touch.on(pc.EVENT_TOUCHEND, this.onTouchEnd, this);
}
this.on('destroy', function () {
this.app.mouse.off(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
this.app.mouse.off(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
this.app.mouse.off(pc.EVENT_MOUSEUP, this.onMouseUp, this);
if (this.app.touch) {
this.app.touch.off(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
this.app.touch.off(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
this.app.touch.off(pc.EVENT_TOUCHEND, this.onTouchEnd, this);
}
}, this);
this.raycastTarget = undefined;
this.lastTouchPoint = new pc.Vec2();
};
RaycastRotate.horizontalQuat = new pc.Quat();
RaycastRotate.verticalQuat = new pc.Quat();
RaycastRotate.resultQuat = new pc.Quat();
RaycastRotate.prototype.rotate = function (dx, dy) {
if(!this.raycastTarget) return;
var horzQuat = RaycastRotate.horizontalQuat;
var vertQuat = RaycastRotate.verticalQuat;
var resultQuat = RaycastRotate.resultQuat;
// Create a rotation around the camera's orientation in order for them to be in
// screen space
horzQuat.setFromAxisAngle(this.entity.up, dx * this.orbitSensitivity);
vertQuat.setFromAxisAngle(this.entity.right, dy * this.orbitSensitivity);
// Apply both the rotations to the existing entity rotation
resultQuat.mul2(horzQuat, vertQuat);
resultQuat.mul(this.raycastTarget.getRotation());
this.raycastTarget.setRotation(resultQuat);
};
RaycastRotate.prototype.getRaycastTarget = function (screenPosition) {
// The pc.Vec3 to raycast from
var from = this.entity.getPosition();
// The pc.Vec3 to raycast to
var to = this.entity.camera.screenToWorld(screenPosition.x, screenPosition.y, this.entity.camera.farClip);
// Raycast between the two points
var result = this.app.systems.rigidbody.raycastFirst(from, to)
return result ? result.entity : undefined;
};
RaycastRotate.prototype.onMouseDown = function(e) {
this.raycastTarget = this.getRaycastTarget(e);
}
RaycastRotate.prototype.onMouseMove = function(e) {
if(!this.raycastTarget) return;
this.rotate(e.dx, e.dy);
}
RaycastRotate.prototype.onMouseUp = function(e) {
this.raycastTarget = undefined;
}
RaycastRotate.prototype.onTouchStart = function(e) {
console.log("Touch Start");
this.raycastTarget = this.getRaycastTarget(e);
var touch = e.touches[0];
this.lastTouchPoint.set(touch.x, touch.y);
console.log(this.raycastTarget, this.lastTouchPoint);
}
RaycastRotate.prototype.onTouchMove = function(e) {
console.log("Touch Move");
if(!this.raycastTarget) return;
var touch = e.touches[0];
var dx = touch.x - this.lastTouchPoint.x;
var dy = touch.y - this.lastTouchPoint.y;
this.rotate(dx, dy);
this.lastTouchPoint.set(touch.x, touch.y);
console.log(dx, dy, touch);
}
RaycastRotate.prototype.onTouchEnd = function(e) {
console.log("Touch End");
this.raycastTarget = undefined;
console.log(this.raycastTarget)
}