Hey folks!
I have a question regarding ArcRotate camera panning when colliding with an object.
Ideally, I’d like my character to be able to aim up, when colliding with the ground object or if the camera’s beta is below a certain limit.
I also tried to use the built-in collision logic for the arc rotate camera, where the radius is reduced upon collision. But this did not really give me the desired affect.
private createCamera() {
const focusPoint = this.createCameraFocusPoint(); // Create the camera focus point
// Parent the focus point to the player mesh
focusPoint.parent = this.mesh;
// Check if the device is mobile and adjust the radius accordingly
const isMobile = isMobileDevice();
let radius: number;
if (isMobile) {
if (isLandscape()) {
radius = 19; // Example: Smaller radius for mobile landscape (adjust as needed)
console.log("Mobile Landscape: Setting camera radius to " + radius);
} else {
radius = 24; // Radius for mobile portrait
console.log("Mobile Portrait: Setting camera radius to " + radius);
}
} else {
radius = 20; // Radius for desktop
console.log("Desktop: Setting camera radius to " + radius);
}
// Parameters: name, alpha (rotation), beta (height), radius (distance), target position, scene
this.camera = new ArcRotateCamera("playerCamera", 0, 1.5, radius, focusPoint.position, this.scene);
this.camera.attachControl(this.scene.getEngine().getRenderingCanvas(), true);
this.camera.inertia = 0.4;
this.camera.lockedTarget = focusPoint;
this.camera.inputs.removeByType("ArcRotateCameraKeyboardMoveInput");
this.camera.inputs.removeByType("ArcRotateCameraMouseWheelInput");
this.camera.lowerBetaLimit = 0.02; // Prevent the camera from looking directly up
this.camera.upperBetaLimit = Math.PI / 2 + 1; // Prevent the camera from looking directly down
const pointersInput = this.camera.inputs.attached.pointers as ArcRotateCameraPointersInput;
if (pointersInput) {
pointersInput.angularSensibilityX = 650;
pointersInput.angularSensibilityY = 650;
}
this.camera._useCtrlForPanning = false;
// Enable collisions for the scene
this.scene.collisionsEnabled = true;
// Enable collisions for the camera
this.camera.checkCollisions = true;
this.camera.collisionRadius = new Vector3(0.35, 0.35, 0.35);
// Enable collisions only for specific meshes (e.g., ground)
const ground = this.scene.getMeshByName("ground");
if (ground) {
ground.checkCollisions = true;
}
// Handle camera collision response
this.handleCameraCollisions();
}
private handleCameraCollisions() {
// Save the initial radius of the camera
const initialRadius = this.camera.radius;
// Add an observable to check camera position before each render
this.scene.registerBeforeRender(() => {
if (this.camera.radius < initialRadius) {
// Reset camera radius to initial value if it moved closer due to a collision
this.camera.radius = initialRadius;
}
});
}
private createCameraFocusPoint() {
// Create an invisible mesh that will act as the focus point for the camera
const focusPoint = new Mesh("focusPoint", this.scene);
focusPoint.position = (new Vector3(1.1, 2, 3.8)); // Set position relative to player mesh
focusPoint.isVisible = false; // Make the mesh invisible
return focusPoint;
}
I was then trying to implement something to allow the camera y panning while colliding with the ground or the camera beta reaches the lower limit. But couldn’t really make this work. I’ve created a playground I have set up this ground collisions logic here:
Any suggestions would be appreciated!
1 Like
I’m thinking about effectively shooting a sphere backwards from the camera
So basically updating the cameraFocusPoint y position in my example? I tried making this work, but failed also 
effective camera placement and orientation is a lot of the feel of a game
it’s the boundaries of genres,… camera and control is the whole game really [imho]
1 Like
So true, now that I’ve added shooting to the game I really need to re-work the camera logic so that the aiming works better…
Right now I have allowed the camera to go below the ground and set backFaceCulling to false, but this just doesn’t feel right.
And when I turn the collision on with the ground I can’t aim upwards enough to hit targets in the air.
But when I turn the handleCameraCollisions Logic off to let the camera go towards the player, it still doesn’t feel quite right…
1 Like
in the last example if the camera kept it’s horizon it might be very nice
it pans up to the sky to nobody’s benefit
I’ll try to play around with this approach. I know eventually, I’ll get it right 
1 Like
I wonder if the forum could find a tide whereupon to collectively test multiplayer projects.
I’m pretty sure yes!
I know it’s not quite the playground, but I’m actually working on a new Babylon + Colyseus template for Multiplayer I want to opensource once it’s ready!
camera collisions didn’t work in my case as well. I ended up using a few raycast to check if there’s anything between the camera and the player, if there’s I switch from 3rd person view to first person until it’s clear again
1 Like
Thanks for the suggestion! Since I’m super conscious of performance (want to achieve 40-50 fps even on low-tier mobiles) I think using raycast might be an overkill, especially that my camera can only collide with the ground.
Using the built-in collision logic works well for moving the camera towards the player, but resetting logic was a but glitchy and I couldn’t really get it to work properly…
I’m playing round with reducing the radius if there the beta value goes below a certain amount and see how that goes.
If nothing gives, I’ll eventually simply set the camera’s positions high enough and the radius low enough so that camera would never clip through the ground.
If I’m not mistaken, rays are quite cheap, cheaper than I thought.
They snag when tested against a bazillion meshes iirc.
1 Like
Ohhh okay that’s pretty good to know!
After a bit of thinking I went with reducing radius if the beta angle goes below a certain amount. The main reason for this is I wanted to have the same behaviour while airborne, not just when the camera was colliding with the ground.
I really like how the camera works now, need to fine tune the parameters but it’s already pretty close to what I was aiming for (no pun intended
)
Maybe it’s overcomplicated, but this is how I implemented this:
private adjustCameraRadiusBasedOnBeta(): void {
if (!this.camera || this.initialCameraRadius === undefined) {
// Ensure camera and initial radius are set
return;
}
const currentBeta = this.camera.beta;
// Check if beta is above the threshold where radius reduction starts
if (currentBeta > this.betaThresholdNormalToReduced) {
// Calculate the range of beta angles over which the reduction occurs
const betaRangeForReduction = this.camera.upperBetaLimit - this.betaThresholdNormalToReduced;
if (betaRangeForReduction <= 0.001) { // Using a small epsilon
// If range is too small or invalid, just set to the minimum radius factor
this.camera.radius = this.initialCameraRadius * this.minRadiusAtUpperBetaFactor;
return;
}
// Calculate 't' - a normalized value (0 to 1) representing progress through the reduction range.
// t = 0 when currentBeta is at betaThresholdNormalToReduced.
// t = 1 when currentBeta is at camera.upperBetaLimit.
let t = (currentBeta - this.betaThresholdNormalToReduced) / betaRangeForReduction;
t = Math.max(0, Math.min(t, 1)); // Clamp t between 0 and 1 for robustness
// Interpolate the radius.
// When t=0, newRadius = initialCameraRadius.
// When t=1, newRadius = initialCameraRadius * minRadiusAtUpperBetaFactor.
const newRadius = this.initialCameraRadius * (1 - t * (1 - this.minRadiusAtUpperBetaFactor));
this.camera.radius = newRadius;
${newRadius.toFixed(2)}`);
} else {
if (this.camera.radius !== this.initialCameraRadius) {
this.camera.radius = this.initialCameraRadius;
${this.initialCameraRadius.toFixed(2)}`);
}
}
}
1 Like