Hi, I added some code inside my three.js script to be specific for mobile devices, however I cant disable zoom on orbitcontrols, also the rotation is way too fast. Can someone explain this?
Edit: Didn’t realize I was recording w. music, sorry:))
if (window.innerWidth < 767) {
camera.position.z = 1.95;
pointOfIntersection = false;
const controls = new OrbitControls( camera, renderer.domElement );
controls.enabled = true; // Ensure that controls are enabled
controls.enableZoom = false; // Disable zoom
controls.update();
}
You’re gonna have to show more code than that. Could be anything.
You’re creating the orbitcontrols inside the renderloop so… creating a new one 60 times a second
I’m surprised your machine didn’t catch fire.
instead of this:
function animate() {
requestAnimationFrame(animate);
// Remove mouse move event listener when window width meets a certain condition
renderer.render(scene, camera);
if (window.innerWidth < 767) { camera.position.z=1.95; pointOfIntersection=false; const controls=new OrbitControls(camera, renderer.domElement); controls.enableRotation=true; // Ensure that controls are enabled controls.enableZoom=false; // Disable zoom controls.autoRotate=false; } } animate();
you want:
const controls=new OrbitControls(camera, renderer.domElement); controls.enableRotation=true; // Ensure that controls are enabled controls.enableZoom=false; // Disable zoom controls.autoRotate=false; }
function animate() {
requestAnimationFrame(animate);
// Remove mouse move event listener when window width meets a certain condition
if (window.innerWidth < 767) { camera.position.z=1.95; pointOfIntersection=false; }
renderer.render(scene, camera);
}
animate();
The lack of formatting is hiding issues, and possibly creating them.
That window.innerWidth check looks suspect… not sure what that’s about.
Put your js in a .js file and just include it from the html too.
Here’s your formatted/fixed code.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
canvas {
cursor: pointer;
width: 100% !important;
height: 100% !important;
z-index: 9999999999; //whyyy
}
</style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.skypack.dev/three@0.129.0/build/three.module.js",
"three/addons/": "https://cdn.skypack.dev/three@0.129.0/examples/jsm/",
}
}</script>
</head>
<body>
<div id="container3D"></div>
<script type="module" src = "./yourcode.js"></script>
</body>
</html>
yourcode.js
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
//scene
const scene = new THREE.Scene();
//camera
const camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.1,
10
);
camera.position.z = 1.27;
camera.position.y = 0.75;
//renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("container3D").appendChild(renderer.domElement);
window.addEventListener("resize", () => {
const newWidth = window.innerWidth;
const newHeight = window.innerHeight;
renderer.setSize(newWidth, newHeight);
});
let skeleton = null; // Declare the skeleton variable
//loader + set scale
const loader = new GLTFLoader();
let model = null;
loader.load("/test.glb", (gltf) => {
model = gltf.scene;
scene.add(model);
model.scale.set(0.5, 0.5, 0.5); // Adjust scale for the first model
model.traverse((child) => {
if (child.isMesh) {
child.material = new THREE.MeshStandardMaterial({
color: 0xffffff,
}); // Adjust properties as needed
}
//adding the rig (I think, found this online)
skeleton = new THREE.SkeletonHelper(model); //add a skeleton helper to ensure everythings set up correct
skeleton.visible = false;
scene.add(skeleton);
skeleton.bones.forEach((bone, index) => {
console.log(`Bone ${index}:`, bone);
});
});
});
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x080820); // Sky color, ground color, intensity
scene.add(hemisphereLight);
var mouse = new THREE.Vector2();
let plane = new THREE.Plane(new THREE.Vector3(0, 0, 2), -1);
let raycaster = new THREE.Raycaster();
let pointOfIntersection = new THREE.Vector3();
window.addEventListener("mousemove", function (e) {
mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
skeleton.bones[2].lookAt(pointOfIntersection);
});
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableRotation = true; // Ensure that controls are enabled
controls.enableZoom = false; // Disable zoom
controls.autoRotate = false;
function animate() {
requestAnimationFrame(animate);
controls.update();
// Remove mouse move event listener when window width meets a certain condition
renderer.render(scene, camera);
if (window.innerWidth < 767) { //Don't know what this is.. you probably want 'blur'/'focus' event for this?
camera.position.z = 1.95;
pointOfIntersection = false;
}
}
animate();
I want to enable Orbitcontrols for mobile devices only, not tablets or computers. That’s why I put it inside the window.innerWidth tag, your solution unfortunately also enables on PC’s/Tablet, which is what I wanted to avoid.
The reason I included the js inside the html is because I am using a web builder and so I have to include everything in one HTML widget ![:slight_smile: :slight_smile:](https://emoji.discourse-cdn.com/twitter/slight_smile.png?v=12)
PS. My computer almost did catch fire! I didn’t realize I placed it inside the loop lmao
1 Like
Using window width is not a good check. There are many mobile devices that have higher resolution than my 4-years-old computer.
Maybe some library (like https://detector.js.org/) might provide a better identification?
PS. I do not advocate for detector-js, I have never used it, it is just the first one showing up in my search
1 Like
@mattias_98 maybe try including a mobile check to determine the state of controls, here is an example included in the code @manthrax posted:
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
//scene
const scene = new THREE.Scene();
//camera
const camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.1,
10
);
camera.position.z = 1.27;
camera.position.y = 0.75;
//renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("container3D").appendChild(renderer.domElement);
window.addEventListener("resize", () => {
const newWidth = window.innerWidth;
const newHeight = window.innerHeight;
renderer.setSize(newWidth, newHeight);
});
let skeleton = null; // Declare the skeleton variable
//loader + set scale
const loader = new GLTFLoader();
let model = null;
loader.load("/test.glb", (gltf) => {
model = gltf.scene;
scene.add(model);
model.scale.set(0.5, 0.5, 0.5); // Adjust scale for the first model
model.traverse((child) => {
if (child.isMesh) {
child.material = new THREE.MeshStandardMaterial({
color: 0xffffff,
}); // Adjust properties as needed
}
//adding the rig (I think, found this online)
skeleton = new THREE.SkeletonHelper(model); //add a skeleton helper to ensure everythings set up correct
skeleton.visible = false;
scene.add(skeleton);
skeleton.bones.forEach((bone, index) => {
console.log(`Bone ${index}:`, bone);
});
});
});
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x080820); // Sky color, ground color, intensity
scene.add(hemisphereLight);
var mouse = new THREE.Vector2();
let plane = new THREE.Plane(new THREE.Vector3(0, 0, 2), -1);
let raycaster = new THREE.Raycaster();
let pointOfIntersection = new THREE.Vector3();
window.addEventListener("mousemove", function (e) {
mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
skeleton.bones[2].lookAt(pointOfIntersection);
});
const isMobile = (/iPad|iPhone|iPod/.test( navigator.platform ))
|| (/Android|webOS|iPhone|iPad|iPod|CriOS|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent ))
|| (navigator.maxTouchPoints !== undefined && navigator.maxTouchPoints > 2 && /MacIntel/.test( navigator.platform ));
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableRotation = true;
if (isMobile === true) {
controls.enableZoom = false; // Disable zoom
controls.autoRotate = false;
camera.position.z = 1.95;
pointOfIntersection = false;
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
This would remove the window width check from the animate loop.
You can modify isMobile
conditions to whatever devices you would treat as mobile.
1 Like
@mattias_98 you can also try adjusting any other OrbitControls settings, including rotation speed:
controls.zoomToCursor = true;
controls.zoomSpeed = 0.4;
controls.rotateSpeed = 0.4;
controls.keyPanSpeed = 0.4;
controls.panSpeed = 0.4;
//controls.enableDamping = true;
//controls.dampingFactor = 0.3;
//controls.enableKeys = false;
//controls.enableZoom = true;
//controls.maxPolarAngle = 2.2;
//controls.minPolarAngle = 1.1;
//controls.minDistance = 2;
//controls.maxDistance = 500;