the url : previewer
I did use ”textureLoader.colorSpace=THREE.SRGBColorSpace ;“, but it didn’t work. I don’t know why. Sorry to disturb everyone.
<script type="module">
import * as THREE from 'three';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
// 初始化场景、相机和渲染器
const scene = new THREE.Scene();
scene.background = new THREE.Color('#F3F4F6');
const camera = new THREE.PerspectiveCamera(
60, // 降低视角,移动端更适合
window.innerWidth / window.innerHeight,
0.1,
1000
);
const container = document.getElementById('viewerContainer');
const renderer = new THREE.WebGLRenderer({antialias: true});
// 关键修改:设置像素比,解决移动端模糊和尺寸问题
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // 限制最大像素比为2
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
// 初始化控制器(优化移动端体验)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableRotate = false;
controls.enablePan = false;
controls.zoomSpeed = 0.5;
// 关键修改:适配移动端触摸事件
controls.touches = {
ONE: THREE.TOUCH.PAN,
TWO: THREE.TOUCH.DOLLY_PAN
};
controls.enableDamping = true; // 增加阻尼,使触摸更流畅
controls.dampingFactor = 0.1;
let initialParams = null;
// 加载图片
const textureLoader = new THREE.TextureLoader();
//
textureLoader.colorSpace=THREE.SRGBColorSpace ;
textureLoader.load(
'<?=$img?>',
(texture) => {
// 获取图片原始尺寸(关键:使用naturalWidth/naturalHeight获取真实尺寸)
const imageWidth = texture.image.naturalWidth;
const imageHeight = texture.image.naturalHeight;
const imageAspect = imageWidth / imageHeight;
const windowAspect = window.innerWidth / window.innerHeight;
// 计算平面尺寸(为移动端增加安全边距)
const safetyMargin = 0.9; // 90%的屏幕空间,留10%边距
let planeWidth, planeHeight;
if (imageAspect > windowAspect) {
// 图片更宽,按宽度适配
planeWidth = 20 * safetyMargin;
planeHeight = planeWidth / imageAspect;
} else {
// 图片更高,按高度适配
planeHeight = 15 * safetyMargin;
planeWidth = planeHeight * imageAspect;
}
// 创建图片平面
const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight);
const material = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.DoubleSide
});
const imagePlane = new THREE.Mesh(geometry, material);
scene.add(imagePlane);
// 计算相机位置
const fovRadians = THREE.MathUtils.degToRad(camera.fov);
const cameraZ = (planeHeight / 2) / Math.tan(fovRadians / 2);
camera.position.z = cameraZ;
// 存储初始参数用于窗口调整
initialParams = {
imageAspect,
planeWidth,
planeHeight,
cameraZ,
fovRadians
};
// 渲染循环
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// 窗口大小调整(优化移动端旋转屏幕适配)
window.addEventListener('resize', () => {
if (!initialParams) return;
renderer.setSize(window.innerWidth, window.innerHeight);
const newWindowAspect = window.innerWidth / window.innerHeight;
camera.aspect = newWindowAspect;
camera.updateProjectionMatrix();
// 重新设置渲染器尺寸和像素比
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// 重新计算平面尺寸
let newPlaneWidth, newPlaneHeight;
if (initialParams.imageAspect > newWindowAspect) {
newPlaneWidth = 20 * safetyMargin;
newPlaneHeight = newPlaneWidth / initialParams.imageAspect;
} else {
newPlaneHeight = 15 * safetyMargin;
newPlaneWidth = newPlaneHeight * initialParams.imageAspect;
}
// 更新平面和相机位置
imagePlane.geometry.dispose();
imagePlane.geometry = new THREE.PlaneGeometry(newPlaneWidth, newPlaneHeight);
camera.position.z = (newPlaneHeight / 2) / Math.tan(initialParams.fovRadians / 2);
});
// 关键修复:延迟执行一次resize,解决移动端初始加载尺寸问题
setTimeout(() => {
window.dispatchEvent(new Event('resize'));
}, 100);
},
undefined,
(error) => console.error('图片加载失败:', error)
);
</script>