u
This commit is contained in:
143
index.html
143
index.html
@@ -73,6 +73,8 @@
|
|||||||
<p>🖱️ Left click + drag: Rotate around model</p>
|
<p>🖱️ Left click + drag: Rotate around model</p>
|
||||||
<p>🖱️ Right click + drag: Pan</p>
|
<p>🖱️ Right click + drag: Pan</p>
|
||||||
<p>⚙️ Mouse wheel: Zoom in/out</p>
|
<p>⚙️ Mouse wheel: Zoom in/out</p>
|
||||||
|
<p>📱 Touch drag: Rotate around model</p>
|
||||||
|
<p>🤏 Pinch: Zoom in/out</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -90,6 +92,17 @@
|
|||||||
let scene, camera, renderer, controls;
|
let scene, camera, renderer, controls;
|
||||||
let cube;
|
let cube;
|
||||||
|
|
||||||
|
// Touch controls variables
|
||||||
|
let touchState = {
|
||||||
|
touching: false,
|
||||||
|
touchCount: 0,
|
||||||
|
lastTouches: [],
|
||||||
|
initialDistance: 0,
|
||||||
|
lastDistance: 0,
|
||||||
|
rotationStart: { x: 0, y: 0 },
|
||||||
|
lastRotation: { x: 0, y: 0 }
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize the 3D scene
|
// Initialize the 3D scene
|
||||||
function init() {
|
function init() {
|
||||||
// Create container
|
// Create container
|
||||||
@@ -135,6 +148,9 @@
|
|||||||
controls.enablePan = true;
|
controls.enablePan = true;
|
||||||
controls.enableRotate = true;
|
controls.enableRotate = true;
|
||||||
|
|
||||||
|
// Setup touch controls
|
||||||
|
setupTouchControls(renderer.domElement);
|
||||||
|
|
||||||
// Add lighting
|
// Add lighting
|
||||||
setupLighting();
|
setupLighting();
|
||||||
|
|
||||||
@@ -218,6 +234,133 @@
|
|||||||
window.environmentMap = texture;
|
window.environmentMap = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupTouchControls(domElement) {
|
||||||
|
// Touch start event
|
||||||
|
domElement.addEventListener('touchstart', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
touchState.touching = true;
|
||||||
|
touchState.touchCount = event.touches.length;
|
||||||
|
touchState.lastTouches = Array.from(event.touches);
|
||||||
|
|
||||||
|
if (event.touches.length === 1) {
|
||||||
|
// Single touch - prepare for rotation
|
||||||
|
const touch = event.touches[0];
|
||||||
|
touchState.rotationStart.x = touch.clientX;
|
||||||
|
touchState.rotationStart.y = touch.clientY;
|
||||||
|
touchState.lastRotation.x = touch.clientX;
|
||||||
|
touchState.lastRotation.y = touch.clientY;
|
||||||
|
|
||||||
|
// Disable OrbitControls to prevent conflicts
|
||||||
|
controls.enabled = false;
|
||||||
|
} else if (event.touches.length === 2) {
|
||||||
|
// Two touches - prepare for pinch zoom
|
||||||
|
const touch1 = event.touches[0];
|
||||||
|
const touch2 = event.touches[1];
|
||||||
|
|
||||||
|
touchState.initialDistance = getTouchDistance(touch1, touch2);
|
||||||
|
touchState.lastDistance = touchState.initialDistance;
|
||||||
|
|
||||||
|
// Disable OrbitControls to prevent conflicts
|
||||||
|
controls.enabled = false;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// Touch move event
|
||||||
|
domElement.addEventListener('touchmove', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (!touchState.touching) return;
|
||||||
|
|
||||||
|
if (event.touches.length === 1 && touchState.touchCount === 1) {
|
||||||
|
// Single touch drag - rotation
|
||||||
|
const touch = event.touches[0];
|
||||||
|
const deltaX = touch.clientX - touchState.lastRotation.x;
|
||||||
|
const deltaY = touch.clientY - touchState.lastRotation.y;
|
||||||
|
|
||||||
|
// Apply rotation to the controls
|
||||||
|
const rotationSpeed = 0.005;
|
||||||
|
controls.enabled = true; // Temporarily enable to apply rotation
|
||||||
|
|
||||||
|
// Simulate mouse movement for OrbitControls
|
||||||
|
const spherical = new THREE.Spherical();
|
||||||
|
spherical.setFromVector3(camera.position.clone().sub(controls.target));
|
||||||
|
|
||||||
|
spherical.theta -= deltaX * rotationSpeed;
|
||||||
|
spherical.phi += deltaY * rotationSpeed;
|
||||||
|
|
||||||
|
// Constrain phi to prevent camera flipping
|
||||||
|
spherical.phi = Math.max(0.1, Math.min(Math.PI - 0.1, spherical.phi));
|
||||||
|
|
||||||
|
const newPosition = new THREE.Vector3();
|
||||||
|
newPosition.setFromSpherical(spherical).add(controls.target);
|
||||||
|
camera.position.copy(newPosition);
|
||||||
|
camera.lookAt(controls.target);
|
||||||
|
|
||||||
|
controls.enabled = false; // Disable again to prevent conflicts
|
||||||
|
|
||||||
|
touchState.lastRotation.x = touch.clientX;
|
||||||
|
touchState.lastRotation.y = touch.clientY;
|
||||||
|
} else if (event.touches.length === 2) {
|
||||||
|
// Two touches - pinch zoom
|
||||||
|
const touch1 = event.touches[0];
|
||||||
|
const touch2 = event.touches[1];
|
||||||
|
const currentDistance = getTouchDistance(touch1, touch2);
|
||||||
|
|
||||||
|
const scaleFactor = currentDistance / touchState.lastDistance;
|
||||||
|
|
||||||
|
// Apply zoom
|
||||||
|
const zoomSpeed = 0.1;
|
||||||
|
const direction = camera.position.clone().sub(controls.target).normalize();
|
||||||
|
const currentDistance3D = camera.position.distanceTo(controls.target);
|
||||||
|
|
||||||
|
let newDistance;
|
||||||
|
if (scaleFactor > 1) {
|
||||||
|
// Pinching out - zoom in
|
||||||
|
newDistance = Math.max(1, currentDistance3D * (1 - zoomSpeed * (scaleFactor - 1)));
|
||||||
|
} else {
|
||||||
|
// Pinching in - zoom out
|
||||||
|
newDistance = currentDistance3D * (1 + zoomSpeed * (1 - scaleFactor));
|
||||||
|
}
|
||||||
|
|
||||||
|
camera.position.copy(controls.target.clone().add(direction.multiplyScalar(newDistance)));
|
||||||
|
|
||||||
|
touchState.lastDistance = currentDistance;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// Touch end event
|
||||||
|
domElement.addEventListener('touchend', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
touchState.touchCount = event.touches.length;
|
||||||
|
|
||||||
|
if (event.touches.length === 0) {
|
||||||
|
// No more touches - re-enable OrbitControls
|
||||||
|
touchState.touching = false;
|
||||||
|
controls.enabled = true;
|
||||||
|
} else if (event.touches.length === 1 && touchState.touchCount > 1) {
|
||||||
|
// Switched from multi-touch to single touch
|
||||||
|
const touch = event.touches[0];
|
||||||
|
touchState.rotationStart.x = touch.clientX;
|
||||||
|
touchState.rotationStart.y = touch.clientY;
|
||||||
|
touchState.lastRotation.x = touch.clientX;
|
||||||
|
touchState.lastRotation.y = touch.clientY;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// Prevent context menu on long press
|
||||||
|
domElement.addEventListener('contextmenu', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTouchDistance(touch1, touch2) {
|
||||||
|
const dx = touch1.clientX - touch2.clientX;
|
||||||
|
const dy = touch1.clientY - touch2.clientY;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
function loadCubeModel() {
|
function loadCubeModel() {
|
||||||
// Create loaders
|
// Create loaders
|
||||||
const mtlLoader = new THREE.MTLLoader();
|
const mtlLoader = new THREE.MTLLoader();
|
||||||
|
|||||||
Reference in New Issue
Block a user