Repository navigation
Expand file tree
/
Copy pathcamera.js
More file actions
276 lines (211 loc) · 10.6 KB
/
Copy pathcamera.js
File metadata and controls
276 lines (211 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
export function setupCamera(scene, target, engine) {
const camera = new BABYLON.ArcRotateCamera("arcCam", 3 * Math.PI / 2, 3 * Math.PI / 8, 200, target.position, scene);
camera.attachControl(document.getElementById('renderCanvas'), false);
scene.collisionsEnabled = true;
// camera.checkCollisions = true;
camera.collisionRadius = new BABYLON.Vector3(0.5, 0.5, 0.5);
camera.allowUpsideDown = false;
camera.panningSensibility = 0;
camera.radius = 70;
// More Professional Limited Camera, avoids collision
camera.wheelDeltaPercentage = 0.0200;
// camera.upperBetaLimit = 3.13;
camera.lowerRadiusLimit = 4; // Minimum distance to target (closest zoom)
camera.upperRadiusLimit = 656.8044;
camera.upperBetaLimit = Math.PI / 2; // Stops at the horizon (90 degrees)
camera.lowerBetaLimit = (Math.PI / 2) * 0.01; // Slightly below the top-down view
camera.alpha = 4.954;
camera.beta = 1.3437;
// if camera
// setupCameraCollision(scene, camera, target);
// setupCameraCollisionZoomInOnly(scene, camera, target);
setupTurnCamera(scene, camera, engine);
if (isMobileDevice()) {
// keep the left click and drag to rotate the camera
} else {
freeLeftClick(scene, camera);
};
return camera;
}
function setupCameraCollision(scene, camera, player) {
camera.upperBetaLimit = Math.PI // Full rotate
let cameraSnap = 0.01;
let targetRadius = 80;
let targetPosition = camera.position.clone();
let transitionSpeed = 0.1;
let ray = new BABYLON.Ray(camera.position, player.position.subtract(camera.position), 800);
// let rayHelper = new BABYLON.RayHelper(ray);
// rayHelper.show(scene);
let frameCounter = 0;
const updateInterval = 10; // Update every 3 frames
scene.registerBeforeRender(() => {
const offset = 0.00; // Adjust this value as needed
ray.direction = player.position.subtract(camera.position).normalize();
ray.origin = camera.position.add(ray.direction.scale(offset));
// Perform ray cast
let pickInfo = scene.pickWithRay(ray, (mesh) => mesh !== player);
let hitObjectName = pickInfo.pickedMesh ? pickInfo.pickedMesh.name : "Unknown";
// console.log("Hit object name:", hitObjectName);
// console.log("pickInfo.pickedMesh.cameraCollide", pickInfo.pickedMesh?.cameraCollide);
let distanceBetweenCameraAndProjected = BABYLON.Vector3.Distance(camera.position, BABYLON.Vector3.Lerp(camera.position, targetPosition, 0.2));
if (pickInfo.pickedMesh?.cameraCollide ?? true) {
let distanceToObject = pickInfo.distance;
let distanceToPlayer = BABYLON.Vector3.Distance(camera.position, player.position);
// Adjust these values as needed
let minDistanceFromWall = 0; // Minimum distance to keep from the wall
let minDistanceFromPlayer = 0; // Minimum distance to keep from the player
let forwardBias = 0.0; // Small forward bias
// Calculate target distance
let targetDistance = Math.min(
distanceToObject - minDistanceFromWall,
distanceToPlayer - minDistanceFromPlayer
);
// Ensure we don't go backwards
// targetDistance = Math.max(targetDistance, 0);
// Calculate new target position
targetPosition = camera.position.add(ray.direction.scale(targetDistance));
// console.log(distanceToPlayer);
// console.log(distanceToPlayer);
// camera.position = targetPosition;
let distanceBetweenCameraAndProjected = BABYLON.Vector3.Distance(camera.position, BABYLON.Vector3.Lerp(camera.position, targetPosition, 0.2));
// if (distanceBetweenCameraAndProjected > 0.10) {
camera.position = BABYLON.Vector3.Lerp(camera.position, targetPosition, 0.91);
// camera.position = targetPosition;
// } else {
// console.log("not moving");
// }
} else {
// if the camera has room to move inward, don't apply moving out force
if (distanceBetweenCameraAndProjected > cameraSnap) {
// If no collision, set target to a position behind the player
let defaultDistance = 70;
let judgedDistance = targetRadius;
let distanceToPlayer = BABYLON.Vector3.Distance(camera.position, player.position);
// if there would still be a collision, set distance to player, otherwise set target radius
if (distanceToPlayer < targetRadius)
judgedDistance = distanceToPlayer;
// defaultDistance = camera.radius;
// targetPosition = player.position.subtract(ray.direction.scale(defaultDistance));
// console.log(pickInfo.pickedMesh?.cameraCollide);
targetPosition = player.position.subtract(ray.direction.scale(targetRadius));
// targetPosition = player.position.subtract(ray.direction.scale(judgedDistance));
camera.position = BABYLON.Vector3.Lerp(camera.position, targetPosition, 0.02);
// camera.position = targetPosition;
}
}
// Smoothly move camera
// camera.position = BABYLON.Vector3.Lerp(camera.position, targetPosition, transitionSpeed);
// camera.radius = BABYLON.Vector3.Lerp(camera.radius, targetRadius, transitionSpeed);
});
// scene.onPointerObservable.add((pointerInfo) => {
// if (pointerInfo.type === BABYLON.PointerEventTypes.POINTERWHEEL) {
// // Adjust zoom speed as needed
// let zoomSpeed = 1;
// targetRadius += pointerInfo.event.wheelDelta * zoomSpeed;
// // Set min and max zoom limits
// targetRadius = Math.max(5, Math.min(targetRadius, 100));
// }
// });
}
function setupCameraCollisionZoomInOnly(scene, camera, player) {
camera.upperBetaLimit = Math.PI // Full rotate
let cameraSnap = 0.01;
let targetRadius = 80;
let targetPosition = camera.position.clone();
let transitionSpeed = 0.1;
let ray = new BABYLON.Ray(camera.position, player.position.subtract(camera.position), 800);
// let rayHelper = new BABYLON.RayHelper(ray);
// rayHelper.show(scene);
let frameCounter = 0;
const updateInterval = 10; // Update every 3 frames
scene.registerBeforeRender(() => {
const offset = 0.00; // Adjust this value as needed
ray.direction = player.position.subtract(camera.position).normalize();
ray.origin = camera.position.add(ray.direction.scale(offset));
// Perform ray cast
let pickInfo = scene.pickWithRay(ray, (mesh) => mesh !== player);
// console.log("Hit object name:", hitObjectName);
// console.log("pickInfo.pickedMesh.cameraCollide", pickInfo.pickedMesh?.cameraCollide);
if (pickInfo.pickedMesh?.cameraCollide ?? true) {
let distanceToObject = pickInfo.distance;
let distanceToPlayer = BABYLON.Vector3.Distance(camera.position, player.position);
// Adjust these values as needed
let minDistanceFromWall = 0; // Minimum distance to keep from the wall
let minDistanceFromPlayer = 0; // Minimum distance to keep from the player
let forwardBias = 0.0; // Small forward bias
// Calculate target distance
let targetDistance = Math.min(
distanceToObject - minDistanceFromWall,
distanceToPlayer - minDistanceFromPlayer
);
// Ensure we don't go backwards
// targetDistance = Math.max(targetDistance, 0);
// Calculate new target position
targetPosition = camera.position.add(ray.direction.scale(targetDistance));
// console.log(distanceToPlayer);
// console.log(distanceToPlayer);
// camera.position = targetPosition;
let distanceBetweenCameraAndProjected = BABYLON.Vector3.Distance(camera.position, BABYLON.Vector3.Lerp(camera.position, targetPosition, 0.2));
// if (distanceBetweenCameraAndProjected > 0.10) {
camera.position = BABYLON.Vector3.Lerp(camera.position, targetPosition, 0.91);
// camera.position = targetPosition;
// } else {
// console.log("not moving");
// }
}
});
// scene.onPointerObservable.add((pointerInfo) => {
// if (pointerInfo.type === BABYLON.PointerEventTypes.POINTERWHEEL) {
// // Adjust zoom speed as needed
// let zoomSpeed = 1;
// targetRadius += pointerInfo.event.wheelDelta * zoomSpeed;
// // Set min and max zoom limits
// targetRadius = Math.max(5, Math.min(targetRadius, 100));
// }
// });
}
function setupTurnCamera(scene, camera, engine) {
var cameraRotationSpeed = 2.25; // Adjust this value for faster or slower rotation
var keyStates = {};
// Function to handle keydown event
function onKeyDown(event) {
keyStates[event.key] = true;
}
// Function to handle keyup event
function onKeyUp(event) {
keyStates[event.key] = false;
}
// Add event listeners to the window
window.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
scene.onBeforeRenderObservable.add(() => {
if (keyStates['a']) {
(camera.alpha);
camera.alpha += cameraRotationSpeed * engine.getDeltaTime() / 1000;
}
// Check if 'D' is pressed for rotating right
if (keyStates['d']) {
camera.alpha -= cameraRotationSpeed * engine.getDeltaTime() / 1000;
}
});
}
// Function to update camera beta limit based on terrain height
// function updateCameraBetaLimit() {
// var ray = new Babylon.Ray(camera.target, new Babylon.Vector3(0, -1, 0));
// var pickInfo = scene.pickWithRay(ray, function(mesh) { return mesh === ground; });
// if (pickInfo.hit) {
// var terrainHeight = pickInfo.pickedPoint.y;
// var heightAboveTerrain = camera.position.y - terrainHeight;
// var minBeta = Math.atan2(heightAboveTerrain, camera.radius);
// camera.lowerBetaLimit = minBeta;
// }
// }
// updateCameraBetaLimit();
function isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// used in builder to make camera not intercept left click only
function freeLeftClick(scene, camera) {
// Modify pointer inputs
camera.inputs.attached.pointers.buttons = [1, 2]; // 0 = left, 1 = middle, 2 = right
}