class Plane_Three_Sketch extends Three_Sketch { addObjects() { this.camera.position.set(0, 0.85, 2); this.camera.near = 0.1; this.camera.far = 1000; this.camera.updateProjectionMatrix(); this.scene.background = new THREE.Color("#FFFFFF"); this.controls.enabled = false; this.background_moving_mode = false; // if (windowViewPort === "desktop") { // this.cursor_tracking_mode = false; // } this.renderer.shadowMap.enabled = true; this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; /** * Fog */ const fog = new THREE.Fog("white", 1, 8); this.scene.fog = fog; this.textureLoader = new THREE.TextureLoader(); const gltfLoader = new THREE.GLTFLoader(); let human_model; // let mixer = null; gltfLoader.load( "https://7rwxdy.csb.app/Services/v2/models/human_model.glb", (gltf) => { console.log("Success"); // Set the scale, rotation, and position of the model gltf.scene.scale.set(0.085, 0.085, 0.085); gltf.scene.rotation.x = -0.045; gltf.scene.rotation.y = -0.1; gltf.scene.rotation.z = 0.08; gltf.scene.position.y = -0.15; // Enable shadows and set initial color for the model const colorsObject = { model_color: "#191919", }; var basicMaterial = new THREE.MeshStandardMaterial({ color: colorsObject.model_color, // skinning: true, metalness: 0.3, roughness: 0.4, envMapIntensity: 0.5, }); gltf.scene.traverse((child) => { if (child.isMesh) { child.castShadow = true; child.receiveShadow = true; // // Set a color for the material child.material.color = new THREE.Color(colorsObject.model_color); // If the material is not using a basic material, it will support lighting child.material = basicMaterial; child.material.needsUpdate = true; } }); this.gui.addColor(colorsObject, "model_color").onChange((value) => { gltf.scene.traverse((child) => { if (child.isMesh) { child.material.color = new THREE.Color(value); child.material.needsUpdate = true; } }); }); this.scene.add(gltf.scene); human_model = gltf.scene.children[0]; // console.log(gltf.scene); this.gui .add(gltf.scene.rotation, "x", -20, 20, 0.01) .name("model rotation x"); this.gui .add(gltf.scene.rotation, "y", -20, 20, 0.01) .name("model rotation y"); this.gui .add(gltf.scene.rotation, "z", -20, 20, 0.01) .name("model rotation z"); this.gui .add(gltf.scene.position, "y", -20, 20, 0.01) .name("model position y"); }, (progress) => { console.log("progress"); // console.log(progress); }, (error) => { console.log("error"); // console.log(error); } ); this.water_segmentsX = 35; // Number of segments along X axis this.water_segmentsY = 25; // Number of segments along Y axis this.animating_speed = 1; this.animating_values = { rotation: { up: true, min_value: -0.1, value: 0, increment: 0.0002, max_value: 0.1, }, position: { up: true, min_value: 0, value: 0, increment: 0.002, max_value: 20, }, }; const tagTextureList = [ { width: 218, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47e775902832a199e61_instagram_post_218_42.png" ), }, { width: 296, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47e652633fd451edf29_influencer_outeach_296_42.png" ), }, { width: 166, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47e42a2a9c90c293c89_cheap_ads_166_42.png" ), }, { width: 133, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47e534ac77fde09de7c_ai_soup_133_42.png" ), }, { width: 202, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47ea1c039a81edc7abd_facebook_ad_202_42.png" ), }, { width: 157, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47ee953e44d801d8826_blog_post_157_42.png" ), }, { width: 350, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47e8ff81a5708d896bb_unwatched_youtube_video_350_42.png" ), }, { width: 272, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d47e32c8f04dd72077a1_sponsered_content_272_42.png" ), }, { width: 275, height: 42, texture: this.textureLoader.load( "https://uploads-ssl.webflow.com/647e14401fad9763940849d0/6698d68306a4bba56aa92cb5_thought_leadership_275_42.png" ), }, ]; const waterVertexShader = ` uniform float uTime; uniform float uBigWavesElevation; uniform vec2 uBigWavesFrequency; uniform float uBigWavesSpeed; uniform float uSmallWavesElevation; uniform float uSmallWavesFrequency; uniform float uSmallWavesSpeed; uniform float uSmallIterations; varying float vElevation; varying vec2 vUv; vec4 permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } vec3 fade(vec3 t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); } float cnoise(vec3 P) { vec3 Pi0 = floor(P); vec3 Pi1 = Pi0 + vec3(1.0); Pi0 = mod(Pi0, 289.0); Pi1 = mod(Pi1, 289.0); vec3 Pf0 = fract(P); vec3 Pf1 = Pf0 - vec3(1.0); vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec4 iy = vec4(Pi0.yy, Pi1.yy); vec4 iz0 = Pi0.zzzz; vec4 iz1 = Pi1.zzzz; vec4 ixy = permute(permute(ix) + iy); vec4 ixy0 = permute(ixy + iz0); vec4 ixy1 = permute(ixy + iz1); vec4 gx0 = ixy0 / 7.0; vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5; gx0 = fract(gx0); vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); vec4 sz0 = step(gz0, vec4(0.0)); gx0 -= sz0 * (step(0.0, gx0) - 0.5); gy0 -= sz0 * (step(0.0, gy0) - 0.5); vec4 gx1 = ixy1 / 7.0; vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5; gx1 = fract(gx1); vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); vec4 sz1 = step(gz1, vec4(0.0)); gx1 -= sz1 * (step(0.0, gx1) - 0.5); gy1 -= sz1 * (step(0.0, gy1) - 0.5); vec3 g000 = vec3(gx0.x, gy0.x, gz0.x); vec3 g100 = vec3(gx0.y, gy0.y, gz0.y); vec3 g010 = vec3(gx0.z, gy0.z, gz0.z); vec3 g110 = vec3(gx0.w, gy0.w, gz0.w); vec3 g001 = vec3(gx1.x, gy1.x, gz1.x); vec3 g101 = vec3(gx1.y, gy1.y, gz1.y); vec3 g011 = vec3(gx1.z, gy1.z, gz1.z); vec3 g111 = vec3(gx1.w, gy1.w, gz1.w); vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); g000 *= norm0.x; g010 *= norm0.y; g100 *= norm0.z; g110 *= norm0.w; vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); g001 *= norm1.x; g011 *= norm1.y; g101 *= norm1.z; g111 *= norm1.w; float n000 = dot(g000, Pf0); float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); float n111 = dot(g111, Pf1); vec3 fade_xyz = fade(Pf0); vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return 2.2 * n_xyz; } void main() { vec4 modelPosition = modelMatrix * vec4(position, 1.0); float elevation = sin(modelPosition.x * uBigWavesFrequency.x + uTime * uBigWavesSpeed) * sin(modelPosition.z * uBigWavesFrequency.y + uTime * uBigWavesSpeed) * uBigWavesElevation; for (float i = 1.0; i <= uSmallIterations; i++) { elevation -= abs(cnoise(vec3(modelPosition.xz * uSmallWavesFrequency * i, uTime * uSmallWavesSpeed)) * uSmallWavesElevation / i); } modelPosition.y += elevation; vec4 viewPosition = viewMatrix * modelPosition; vec4 projectedPosition = projectionMatrix * viewPosition; gl_Position = projectedPosition; vElevation = elevation; vUv = uv; } `; const waterFragmentShader = ` uniform vec3 uDepthColor; uniform vec3 uSurfaceColor; uniform float uColorOffset; uniform float uColorMultiplier; varying float vElevation; varying vec2 vUv; void main() { float lineWidth = 0.02; // Adjust line width here vec3 lineColor = vec3(0.0, 0.0, 0.0); // Black color for the lines vec3 surfaceColor = mix(uDepthColor, uSurfaceColor, (vElevation + uColorOffset) * uColorMultiplier); float lineX = step(fract(vUv.x * float(${this.water_segmentsX}.0)), lineWidth) + step(1.0 - fract(vUv.x * float(${this.water_segmentsX}.0)), lineWidth); float lineY = step(fract(vUv.y * float(${this.water_segmentsY}.0)), lineWidth) + step(1.0 - fract(vUv.y * float(${this.water_segmentsY}.0)), lineWidth); vec3 color = mix(surfaceColor, lineColor, max(lineX, lineY)); gl_FragColor = vec4(color, 1.0); } `; const debugObject = {}; debugObject.depthColor = "#FFFFFF"; debugObject.surfaceColor = "#FFFFFF"; // debugObject.surfaceColor = "#939393"; // debugObject.depthColor = "#186691"; // debugObject.surfaceColor = "#9bd8ff"; // this.gui.show(); this.gui.addColor(debugObject, "depthColor").onChange(() => { this.waterMaterial.uniforms.uDepthColor.value.set(debugObject.depthColor); }); this.gui.addColor(debugObject, "surfaceColor").onChange(() => { this.waterMaterial.uniforms.uSurfaceColor.value.set( debugObject.surfaceColor ); }); const waterGeometry = new THREE.PlaneGeometry( 0.25 * this.water_segmentsX, 0.25 * this.water_segmentsY, this.water_segmentsX, this.water_segmentsY ); this.waterMaterial = new THREE.ShaderMaterial({ // wireframe: true, vertexShader: waterVertexShader, fragmentShader: waterFragmentShader, uniforms: { uTime: { value: 0 }, uBigWavesElevation: { value: 0.2 }, uBigWavesFrequency: { value: new THREE.Vector2(2, 2.1) }, uBigWavesSpeed: { value: 0.75 }, uSmallWavesElevation: { value: 0.15 }, uSmallWavesFrequency: { value: 3 }, uSmallWavesSpeed: { value: 0.2 }, uSmallIterations: { value: 0 }, // uSmallIterations: { value: 4 }, uDepthColor: { value: new THREE.Color(debugObject.depthColor) }, uSurfaceColor: { value: new THREE.Color(debugObject.surfaceColor) }, uColorOffset: { value: 0.08 }, uColorMultiplier: { value: 5 }, }, }); const water = new THREE.Mesh(waterGeometry, this.waterMaterial); water.position.x = -0.5; water.position.z = -0.25; water.position.y = -0.05; water.rotation.z = -0.35; water.rotation.x = -Math.PI * 0.5; this.scene.add(water); this.world = new CANNON.World(); //Add gravity this.world.gravity.set(0, -9.82, 0); this.world.broadphase = new CANNON.SAPBroadphase(this.world); this.world.allowSleep = true; //Add materials like concrete, plastic.. // const concreteMaterial = new CANNON.Material("concrete"); // const plasticMaterial = new CANNON.Material("plastic"); const defaultMaterial = new CANNON.Material("default"); const default_ContactMaterial = new CANNON.ContactMaterial( defaultMaterial, defaultMaterial, { friction: 0.1, restitution: 0.35, } ); this.world.addContactMaterial(default_ContactMaterial); // Add the ContactMAterial to specify how two materials will act when they collide const floorShape = new CANNON.Plane(); const floorBody = new CANNON.Body({ mass: 0, }); floorBody.addShape(floorShape); floorBody.material = defaultMaterial; floorBody.quaternion.setFromAxisAngle( new CANNON.Vec3(-1, 0, 0), Math.PI * 0.5 ); this.world.addBody(floorBody); this.objectsToUpdate = []; this.objectsToUpdateRaycaster = []; // Create box const boxGeometry = new THREE.BoxGeometry(1, 1, 1); // const boxMaterial = new THREE.MeshStandardMaterial({ // metalness: 0.3, // roughness: 0.45, // // envMap: environmentMapTexture, // map: tile_floor_isometric, // envMapIntensity: 0.5, // }); const boxColor = "#EFEFEF"; this.initRaycaster = () => { const raycaster = new THREE.Raycaster(); raycaster.near = this.camera.near; raycaster.far = this.camera.far; document.addEventListener("mousedown", (event) => onMouseDown(event, this.renderer, this.camera, this.scene) ); function onMouseDown(event, renderer, camera, scene) { const coords = new THREE.Vector2( (event.clientX / renderer.domElement.clientWidth) * 2 - 1, -((event.clientY / renderer.domElement.clientHeight) * 2 - 1) ); raycaster.setFromCamera(coords, camera); const intersections = raycaster.intersectObjects(scene.children, true); if (intersections.length > 0) { let excludedItems = [human_model, water]; // Filter the array to exclude the specified items let filtered_intersections = intersections.filter( (item) => !excludedItems.includes(item.object) ); filtered_intersections.forEach((intersection) => { const selectedObject = intersection.object; // Store the initial scale const initialScale = { x: selectedObject.scale.x, y: selectedObject.scale.y, z: selectedObject.scale.z, }; // Animate the object using GSAP gsap.to(selectedObject.scale, { duration: 0.3, x: initialScale.x * 1.2, y: initialScale.y * 1.2, z: initialScale.z * 1.2, onComplete: () => { gsap.to(selectedObject.scale, { duration: 0.3, x: 0, y: 0, z: 0, onComplete: () => { // Remove the selected object from the scene scene.remove(selectedObject); // Dispose of the object's geometry and material to free up memory if (selectedObject.geometry) selectedObject.geometry.dispose(); if (selectedObject.material) { if (Array.isArray(selectedObject.material)) { // Dispose of each material in the array selectedObject.material.forEach((material) => material.dispose() ); } else { // Dispose of the single material selectedObject.material.dispose(); } } console.log(`${selectedObject.name} was removed!`); }, }); }, }); }); } else { console.log("intersections not found"); } } }; const createBox = (position, textureInfo) => { // console.log(textureInfo); textureInfo.texture.wrapS = THREE.RepeatWrapping; textureInfo.texture.wrapT = THREE.RepeatWrapping; textureInfo.texture.minFilter = THREE.NearestFilter; const box_topBottomMaterial = new THREE.MeshStandardMaterial({ map: textureInfo.texture, color: boxColor, }); const box_sideMaterial = new THREE.MeshStandardMaterial({ color: boxColor, }); const box_allSides_materials = [ box_sideMaterial, // Right face box_sideMaterial, // Left face box_topBottomMaterial, // Top face ** box_topBottomMaterial, // Bottom face ** box_topBottomMaterial, // Front face box_topBottomMaterial, // Back face ]; const unitSize = 0.0025; //sizes const width = unitSize * textureInfo.width; const height = unitSize * textureInfo.height; const depth = unitSize * textureInfo.height; // Three.js mesh const mesh = new THREE.Mesh(boxGeometry, box_allSides_materials); // const mesh = new THREE.Mesh(boxGeometry, box_sideMaterial); mesh.scale.set(width, height, depth); mesh.castShadow = true; mesh.position.copy(position); this.scene.add(mesh); // Cannon.js body const shape = new CANNON.Box( new CANNON.Vec3(width * 0.5, height * 0.5, depth * 0.5) ); const body = new CANNON.Body({ mass: 1, position: new CANNON.Vec3(0, 3, 0), shape: shape, material: defaultMaterial, }); body.position.copy(position); // body.addEventListener("collide", playHitSound); this.world.addBody(body); // Save in objects this.objectsToUpdate.push({ mesh, body }); this.objectsToUpdateRaycaster.push(mesh); }; ////Create sounds // let hitSound = new Audio( // "https://7rwxdy.csb.app/Services/v2/sounds/hit.mp3" // ); // let playHitSound = (collision) => { // let impactStrength = collision.contact.getImpactVelocityAlongNormal(); // if (impactStrength > 1.5) { // hitSound.volume = Math.random(); // hitSound.currentTime = 0; // hitSound.play(); // } // }; function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function createBoxesWithDelay() { for (let i = 0; i < 8; i++) { for (const item of tagTextureList) { // console.log(item); createBox( { x: (Math.random() - 0.5) * 6.5, y: 1.5, z: (Math.random() - 0.5) * 3.5, }, item ); // Wait for the specified time before the next iteration await delay(50); // Delay in milliseconds (e.g., 1000ms = 1 second) } } } // Call the async function to start the process this.createBoxes = () => createBoxesWithDelay(); /** * Lights */ // Increase the intensity of the ambient light // Adjust the intensity of the ambient light // Adjust the intensity of the ambient light const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // Moderate intensity this.scene.add(ambientLight); // Adjust the intensity of the directional light const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); // Moderate intensity directionalLight.castShadow = true; directionalLight.shadow.mapSize.set(1024, 1024); directionalLight.shadow.camera.far = 15; directionalLight.shadow.camera.left = -7; directionalLight.shadow.camera.top = 7; directionalLight.shadow.camera.right = 7; directionalLight.shadow.camera.bottom = -7; directionalLight.position.set(5, 10, 5); // Position to better illuminate (0, 0, 0) this.scene.add(directionalLight); // // Optionally, add a point light with lower intensity // const pointLight = new THREE.PointLight(0xffffff, 0.8); // Reduced intensity // pointLight.position.set(0, 5, 0); // Position it above the object at (0, 0, 0) // pointLight.castShadow = true; // this.scene.add(pointLight); // // Optionally, add a spotlight with lower intensity // const spotLight = new THREE.SpotLight(0xffffff, 0.8); // Reduced intensity // spotLight.position.set(5, 10, 5); // Position it above and to the side // spotLight.target.position.set(0, 0, 0); // Point it at the object // spotLight.castShadow = true; // this.scene.add(spotLight); // this.scene.add(spotLight.target); ///GUI UI this.gui.close(); this.gui .add(this.waterMaterial.uniforms.uBigWavesElevation, "value") .min(0) .max(1) .step(0.001) .name("uBigWavesElevation"); this.gui .add(this.waterMaterial.uniforms.uBigWavesFrequency.value, "x") .min(0) .max(10) .step(0.001) .name("uBigWavesFrequencyX"); this.gui .add(this.waterMaterial.uniforms.uBigWavesFrequency.value, "y") .min(0) .max(10) .step(0.001) .name("uBigWavesFrequencyY"); this.gui .add(this.waterMaterial.uniforms.uBigWavesSpeed, "value") .min(0) .max(4) .step(0.001) .name("uBigWavesSpeed"); this.gui .add(this.waterMaterial.uniforms.uSmallWavesElevation, "value") .min(0) .max(1) .step(0.001) .name("uSmallWavesElevation"); this.gui .add(this.waterMaterial.uniforms.uSmallWavesFrequency, "value") .min(0) .max(30) .step(0.001) .name("uSmallWavesFrequency"); this.gui .add(this.waterMaterial.uniforms.uSmallWavesSpeed, "value") .min(0) .max(4) .step(0.001) .name("uSmallWavesSpeed"); this.gui .add(this.waterMaterial.uniforms.uSmallIterations, "value") .min(0) .max(5) .step(1) .name("uSmallIterations"); this.gui .add(this.waterMaterial.uniforms.uColorOffset, "value") .min(0) .max(1) .step(0.001) .name("uColorOffset"); this.gui .add(this.waterMaterial.uniforms.uColorMultiplier, "value") .min(0) .max(10) .step(0.001) .name("uColorMultiplier"); this.gui.add(water.rotation, "x", -20, 20, 0.01).name("water rotation x"); this.gui.add(water.rotation, "y", -20, 20, 0.01).name("water rotation y"); this.gui.add(water.rotation, "z", -20, 20, 0.01).name("water rotation z"); this.gui .add(this.camera.position, "x", -20, 20, 0.01) .name("camera position x"); this.gui .add(this.camera.position, "y", -20, 20, 0.01) .name("camera position y"); this.gui .add(this.camera.position, "z", -20, 20, 0.01) .name("camera position z"); debugObject.createBox = () => createBoxesWithDelay(); debugObject.reset = () => { for (const object of this.objectsToUpdate) { // Remove body this.world.removeBody(object.body); // Remove mesh this.scene.remove(object.mesh); } this.objectsToUpdate.splice(0, this.objectsToUpdate.length); }; this.gui.add(debugObject, "createBox"); this.gui.add(debugObject, "reset"); } render() { if (!this.isPlaying) return; const elapsedTime = this.clock.getElapsedTime(); const deltaTime = elapsedTime - this.previousTime; this.previousTime = elapsedTime; // Update the time uniform this.waterMaterial.uniforms.uTime.value = elapsedTime; //Update the physic world for (const obj of this.objectsToUpdate) { obj.mesh.position.copy(obj.body.position); obj.mesh.quaternion.copy(obj.body.quaternion); // console.log(obj.mesh.position); // Check if the object (e.g., box) falls below a certain y-position //Remove objects that fall into the main character, and those that are out of the water zone if ( Math.abs(obj.mesh.position.x) > 2.5 || Math.abs(obj.mesh.position.z) > 2 || Math.abs(obj.mesh.position.x) < 0.25 || Math.abs(obj.mesh.position.z) < 0.25 ) { // Remove the mesh from the scene this.scene.remove(obj.mesh); // Remove the body from the physics simulation this.world.removeBody(obj.body); // Optionally, remove from objectsToUpdate array const index = this.objectsToUpdate.indexOf(obj); if (index !== -1) { this.objectsToUpdate.splice(index, 1); } } } // // Calculate values for position // let clamp_position = Clamp_value({ // up: this.animating_values.position.up, // value: this.animating_values.position.value, // min_value: this.animating_values.position.min_value, // max_value: this.animating_values.position.max_value, // increment: // this.animating_values.position.increment * this.animating_speed, // }); // this.animating_values.position.value = clamp_position.value; // this.animating_values.position.up = clamp_position.up; if (this.cursor_tracking_mode) { const parallaxX = this.cursor.x * 0.5; const parallaxY = this.cursor.y * 0.5; let smoothness = 7; this.cameraGroup.position.x += (parallaxX - this.cameraGroup.position.x) * smoothness * deltaTime; this.cameraGroup.position.y += (parallaxY - this.cameraGroup.position.y) * smoothness * deltaTime; } // if (this.cursor_tracking_mode) { // const parallaxX = this.cursor.x * 0.5 * -1; // Increase the multiplier (e.g., 1.0) // const parallaxY = this.cursor.y * 0.5 * -1; // Increase the multiplier (e.g., 1.0) // this.cameraGroup.position.x += // (parallaxX - this.cameraGroup.position.x) * 8 * deltaTime; // this.cameraGroup.position.y += // (parallaxY - this.cameraGroup.position.y) * 8 * deltaTime; // } // sphereBody.applyForce(new CANNON.Vec3(-0.5, 0, 0), sphereBody.position); //Update the physic world this.world.step(1 / 60, deltaTime, 3); for (const object of this.objectsToUpdate) { object.mesh.position.copy(object.body.position); object.mesh.quaternion.copy(object.body.quaternion); } this.renderer.render(this.scene, this.camera); this.controls.update(); window.requestAnimationFrame(this.render.bind(this)); } }