Three.js场景打印预览偏移求助:如何匹配截图显示效果
问题:Three.js场景打印预览偏移,无法与截图效果一致
我在运行Three.js项目时,使用window.print()打印场景,功能能运行但效果不符合预期:打印预览画面完全未居中且向左偏移。我希望实现打印预览和场景截图的显示效果完全一致,尝试过调整相机位置和视角但未达预期。
相关图示:
- 场景图:

- 正常截图(renderer.render生成):

- 打印预览图:

以下是项目相关代码:
初始化代码
function init() { renderer = new THREE.WebGLRenderer({ antialias: true }, { preserveDrawingBuffer: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.domElement.className = 'realCanvas'; container.appendChild(renderer.domElement); renderer.outputEncoding = THREE.sRGBEncoding; renderer.toneMapping = THREE.ACESFilmicToneMapping; pmremGenerator = new THREE.PMREMGenerator(renderer); pmremGenerator.compileEquirectangularShader(); controls = new OrbitControls(camera, renderer.domElement); controls.target.set(0, 50, 0); controls.maxPolarAngle = Math.PI / 2; controls.minDistance = 350; controls.maxDistance = 2550; controls.minZoom = 350; controls.maxZoom = 2550; controls.zoomSpeed = 0.75; controls.panSpeed = 0.75; controls.rotateSpeed = 0.55; var minPan = new THREE.Vector3( - 1500, - 1500, - 1500); var maxPan = new THREE.Vector3(1500, 1500, 1500); var _v = new THREE.Vector3(); controls.addEventListener("change", function () { _v.copy(controls.target); controls.target.clamp(minPan, maxPan); _v.sub(controls.target); camera.position.sub(_v); }) controls.update(); window.addEventListener('resize', onWindowResize, false); // stats stats = new Stats(); stats.dom.classList.add("myStats"); $('.myStats').css("display", "none"); container.appendChild(stats.dom); }
背景初始化代码
function initBackground() { container = document.createElement('div'); container.classList.add("myCanvas"); document.body.appendChild(container); container.style.cssText = 'position:fixed; top:0;'; camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 2.0, 100000); camera.position.set(-220, 100, -650); //(-220, 100, -650); scene = new THREE.Scene(); scene.background = new THREE.Color(0xcce0ff); scene.fog = new THREE.Fog(0xcce0ff, 5000, 10000); scene.add(new THREE.AmbientLight(0x222222, 0.75)); var light = new THREE.DirectionalLight(0xffffff, 0.01); light.position.set(200, 450, 500); light.castShadow = true; scene.add(light); var gt = new THREE.TextureLoader().load("examples/textures/terrain/street4.jpg"); var gg = new THREE.PlaneBufferGeometry(32000, 32000); var gm = new THREE.MeshPhongMaterial({ color: 0xffffff, map: gt }); ground = new THREE.Mesh(gg, gm); ground.rotation.x = - Math.PI / 2; ground.material.map.repeat.set(640, 640); ground.material.map.wrapS = THREE.RepeatWrapping; ground.material.map.wrapT = THREE.RepeatWrapping; ground.material.map.encoding = THREE.sRGBEncoding; // note that because the ground does not cast a shadow, .castShadow is left false ground.receiveShadow = false; ground.position.set(-20, -20, -20); scene.add(ground); $('div myCanvas').hide(); // before canvas but color picker colored square is also canvas }
正常截图代码
jQuery('#screenshot').click(function () { renderer.render(scene, camera); renderer.domElement.toBlob(function(blob) { saveAs(blob, "Configurator"); }); });
打印预览代码
const mediaQuery = window.matchMedia('print'); mediaQuery.addEventListener("change", () => { renderer.render(scene, camera); /*const c = document.getElementsByClassName("realCanvas"); if(c.width === -1){ renderer.setSize(window.innerWidth, window.innerHeight); c.width=window.innerWidth; } else { renderer.setSize(1050, 800); //renderer.setSize(window.innerWidth * 0.8, window.innerHeight * 0.8); c.width=-1; }*/ });
解决方案
方法1:CSS强制打印布局居中
打印偏移的核心原因是打印媒体下Canvas的布局与屏幕布局不一致,添加以下CSS直接控制打印时的Canvas样式:
@media print { .realCanvas { position: absolute !important; top: 50% !important; left: 50% !important; transform: translate(-50%, -50%) !important; max-width: 100% !important; max-height: 100% !important; } .myCanvas { width: 100vw !important; height: 100vh !important; position: relative !important; } body *:not(.myCanvas):not(.realCanvas) { display: none !important; } }
这段代码会在打印时隐藏无关元素,仅保留Canvas容器和Canvas本身,并强制Canvas居中显示。
方法2:基于截图生成图片打印
既然截图效果正常,可直接复用截图结果打印,绕过Canvas打印适配问题:
// 替换原打印监听逻辑,绑定到打印按钮 document.querySelector('#print-btn').addEventListener('click', () => { renderer.render(scene, camera); renderer.domElement.toBlob((blob) => { const img = document.createElement('img'); img.src = URL.createObjectURL(blob); img.style.position = 'fixed'; img.style.top = '0'; img.style.left = '0'; img.style.width = '100%'; img.style.height = '100%'; img.style.objectFit = 'contain'; // 临时添加图片到页面 document.body.appendChild(img); // 触发打印 window.print(); // 打印完成后清理临时资源 setTimeout(() => { document.body.removeChild(img); URL.revokeObjectURL(img.src); }, 100); }); });
方法3:调整相机适配打印比例
如果坚持使用Canvas直接打印,需在打印状态下重新计算相机宽高比,适配纸张比例:
const mediaQuery = window.matchMedia('print'); mediaQuery.addEventListener("change", () => { if (mediaQuery.matches) { // 适配A4纸张宽高比(约1.414) const printWidth = 800; const printHeight = printWidth / 1.414; renderer.setSize(printWidth, printHeight); // 更新相机参数 camera.aspect = printWidth / printHeight; camera.updateProjectionMatrix(); renderer.render(scene, camera); } else { // 回到屏幕状态,恢复原尺寸 renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.render(scene, camera); } });
内容的提问来源于stack exchange,提问作者sebi
相关产品推荐
相关产品推荐

