[SOLVED] orbitCamera touchinput help

I know theres the default touchinput and mouseinput scripts,
i am able to alter mouseinput to move camera left and right panning via left click hold. but im not sure how the touchinput works.

anyone have an idea on how to change camera pan from 2 fingers to 1?

Hi @bestdenki7,

Here is the relevant method from the orbit camera model viewer scripts:

TouchInput.prototype.onTouchMove = function(event) {
    var pinchMidPoint = TouchInput.pinchMidPoint;
    
    // We only care about the first touch for camera rotation. Work out the difference moved since the last event
    // and use that to update the camera target position 
    var touches = event.touches;
    if (touches.length == 1) {
        var touch = touches[0];
        
        this.orbitCamera.pitch -= (touch.y - this.lastTouchPoint.y) * this.orbitSensitivity;
        this.orbitCamera.yaw -= (touch.x - this.lastTouchPoint.x) * this.orbitSensitivity;
        
        this.lastTouchPoint.set(touch.x, touch.y);
    
    }else if (touches.length == 2) {
        // Calculate the difference in pinch distance since the last event
        var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
        var diffInPinchDistance = currentPinchDistance - this.lastPinchDistance;
        this.lastPinchDistance = currentPinchDistance;
                
        this.orbitCamera.distance -= (diffInPinchDistance * this.distanceSensitivity * 0.1) * (this.orbitCamera.distance * 0.1);
        
        // Calculate pan difference
        this.calcMidPoint(touches[0], touches[1], pinchMidPoint);
        this.pan(pinchMidPoint);
        this.lastPinchMidPoint.copy(pinchMidPoint);
    }

With a single touch it orbits, with two touches it pans. So if you swap these two statements you will get panning with a single finger touch.

Do you mean it like this? sorry but im not too sure how else i should be accessing them, because of touches[] array calculations

TouchInput.prototype.onTouchMove = function(event) {
var pinchMidPoint = TouchInput.pinchMidPoint;

// We only care about the first touch for camera rotation. Work out the difference moved since the last event
// and use that to update the camera target position 
var touches = event.touches;

    var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
    var diffInPinchDistance = currentPinchDistance - this.lastPinchDistance;
if (touches.length == 1) {
    
    this.lastPinchDistance = currentPinchDistance;
            
    this.orbitCamera.distance -= (diffInPinchDistance * this.distanceSensitivity * 0.1) * (this.orbitCamera.distance * 0.1);
    
    // Calculate pan difference
    this.calcMidPoint(touches[0], touches[1], pinchMidPoint);
    this.pan(pinchMidPoint);
    this.lastPinchMidPoint.copy(pinchMidPoint);

} else if (touches.length == 2) {
    // Calculate the difference in pinch distance since the last event
    this.lastPinchDistance = currentPinchDistance;
            
    this.orbitCamera.distance -= (diffInPinchDistance * this.distanceSensitivity * 0.1) * (this.orbitCamera.distance * 0.1);
    
    // Calculate pan difference
    this.calcMidPoint(touches[0], touches[1], pinchMidPoint);
    this.pan(pinchMidPoint);
    this.lastPinchMidPoint.copy(pinchMidPoint);
}

};

Ah, almost there, here is a corrected version that will do panning with a single touch and orbiting with two touches:

TouchInput.prototype.onTouchMove = function(event) {
    var pinchMidPoint = TouchInput.pinchMidPoint;
    
    // We only care about the first touch for camera rotation. Work out the difference moved since the last event
    // and use that to update the camera target position 
    var touches = event.touches;
    if (touches.length == 1) {
        // Calculate the difference in pinch distance since the last event
        var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
        var diffInPinchDistance = currentPinchDistance - this.lastPinchDistance;
        this.lastPinchDistance = currentPinchDistance;
                
        this.orbitCamera.distance -= (diffInPinchDistance * this.distanceSensitivity * 0.1) * (this.orbitCamera.distance * 0.1);
        
        // Calculate pan difference
        this.calcMidPoint(touches[0], touches[1], pinchMidPoint);
        this.pan(pinchMidPoint);
        this.lastPinchMidPoint.copy(pinchMidPoint);    
    }else if (touches.length == 2) {
        var touch = touches[0];
        
        this.orbitCamera.pitch -= (touch.y - this.lastTouchPoint.y) * this.orbitSensitivity;
        this.orbitCamera.yaw -= (touch.x - this.lastTouchPoint.x) * this.orbitSensitivity;
        
        this.lastTouchPoint.set(touch.x, touch.y);
    }

oh, i forgot to add in that…i still need the 2-touch pinch zoom in/out, but panning with a single touch, and i dont need orbiting at all. sorry.

and, i tried swapping the codes around and testing it via mobile, it gave me error loading scripts…

Panning as it’s calculated right now requires two touches, here is a simpler form of panning on the XZ axis that retains pinch zooming with two touches (and gets rid of orbiting).

You will have to expand this script if you would like panning to be relative to the camera angle and not in world space, but I think it’s a good start.

var TouchInput = pc.createScript('touchInput');

TouchInput.attributes.add('orbitSensitivity', {
    type: 'number', 
    default: 0.4, 
    title: 'Orbit Sensitivity', 
    description: 'How fast the camera moves around the orbit. Higher is faster'
});

TouchInput.attributes.add('distanceSensitivity', {
    type: 'number', 
    default: 0.2, 
    title: 'Distance Sensitivity', 
    description: 'How fast the camera moves in and out. Higher is faster'
});

// initialize code called once per entity
TouchInput.prototype.initialize = function() {
    this.orbitCamera = this.entity.script.orbitCamera;
    
    // Store the position of the touch so we can calculate the distance moved
    this.lastTouchPoint = new pc.Vec2();
    this.lastPinchMidPoint = new pc.Vec2();
    this.lastPinchDistance = 0;
    
    if (this.orbitCamera && this.app.touch) {
        // Use the same callback for the touchStart, touchEnd and touchCancel events as they 
        // all do the same thing which is to deal the possible multiple touches to the screen
        this.app.touch.on(pc.EVENT_TOUCHSTART, this.onTouchStartEndCancel, this);
        this.app.touch.on(pc.EVENT_TOUCHEND, this.onTouchStartEndCancel, this);
        this.app.touch.on(pc.EVENT_TOUCHCANCEL, this.onTouchStartEndCancel, this);
        
        this.app.touch.on(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
        
        this.on('destroy', function() {
            this.app.touch.off(pc.EVENT_TOUCHSTART, this.onTouchStartEndCancel, this);
            this.app.touch.off(pc.EVENT_TOUCHEND, this.onTouchStartEndCancel, this);
            this.app.touch.off(pc.EVENT_TOUCHCANCEL, this.onTouchStartEndCancel, this);

            this.app.touch.off(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
        });
    }
};


TouchInput.prototype.getPinchDistance = function (pointA, pointB) {
    // Return the distance between the two points
    var dx = pointA.x - pointB.x;
    var dy = pointA.y - pointB.y;    
    
    return Math.sqrt((dx * dx) + (dy * dy));
};


TouchInput.prototype.calcMidPoint = function (pointA, pointB, result) {
    result.set(pointB.x - pointA.x, pointB.y - pointA.y);
    result.scale(0.5);
    result.x += pointA.x;
    result.y += pointA.y;
};


TouchInput.prototype.onTouchStartEndCancel = function(event) {
    // We only care about the first touch for camera rotation. As the user touches the screen, 
    // we stored the current touch position
    var touches = event.touches;
    if (touches.length == 1) {
        this.lastTouchPoint.set(touches[0].x, touches[0].y);
    
    } else if (touches.length == 2) {
        // If there are 2 touches on the screen, then set the pinch distance
        this.lastPinchDistance = this.getPinchDistance(touches[0], touches[1]);
        this.calcMidPoint(touches[0], touches[1], this.lastPinchMidPoint);
    }
};

TouchInput.worldDiff = new pc.Vec3();

TouchInput.prototype.pan = function(pointA, pointB) {
    var worldDiff = TouchInput.worldDiff;
    worldDiff.z = -(pointA.x - pointB.x);
    worldDiff.x = pointA.y - pointB.y;
    
    this.orbitCamera.pivotPoint.add(worldDiff.scale(0.01));    
};


TouchInput.pinchMidPoint = new pc.Vec2();

TouchInput.prototype.onTouchMove = function(event) {
    var pinchMidPoint = TouchInput.pinchMidPoint;
    
    // We only care about the first touch for camera rotation. Work out the difference moved since the last event
    // and use that to update the camera target position 
    var touches = event.touches;
    if (touches.length == 1) {
        var touch = touches[0];

        this.pan(touches[0], this.lastTouchPoint);
        this.lastTouchPoint.set(touch.x, touch.y);
    
    }if (touches.length == 2) {
        // Calculate the difference in pinch distance since the last event
        var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
        var diffInPinchDistance = currentPinchDistance - this.lastPinchDistance;
        this.lastPinchDistance = currentPinchDistance;
                
        this.orbitCamera.distance -= (diffInPinchDistance * this.distanceSensitivity * 0.1) * (this.orbitCamera.distance * 0.1);
    }
};

no no!! omg that actually helped a BLAST!! its exactly what im looking for, but it was slightly off with the x/z axis, i altered it to:

TouchInput.prototype.pan = function(pointA, pointB) {
var worldDiff = TouchInput.worldDiff;
worldDiff.z = -(pointA.y - pointB.y);
worldDiff.x = -(pointA.x - pointB.x);

this.orbitCamera.pivotPoint.add(worldDiff.scale(0.01));    

};

so if touch moves left, camera goes right.
touch moves up,camera goes down, and so.

this is the exact panning i needed! thank you so much!

1 Like