问题描述
将HTML界面通过 CSS3Renderer
和 CSS3DObject
渲染到页面上后,当放大场景并旋转场景后HTML页面会变得模糊。如图:
问题代码
// 获取名称为 touchScreen 的模型
const touchScreen = model.scene.getObjectByName('touchScreen') as THREE.Mesh;
const div = document.createElement('div');
document.body.appendChild(div);
const app = createApp(touchScreenComponent);
app.mount(div);
// 将 div 转换为 CSS3DObject 对象
const css3DObject = new CSS3DObject(div);
// 设置 CSS3DObject 对象的位置
css3DObject.position.set(0, 0, 0.03);
css3DObject.scale.set(0.01, 0.01, 0.01);
css3DObject.visible = true;
// 将 CSS3DObject 对象添加到模型中
touchScreen.add(css3DObject);
<template>
<div class="w-[65px] h-[48px] bg-black">
<div class="text-white">你好</div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped></style>
问题解析
HTML页面通过 CSS3DObject
渲染为一个3D对象,然后浏览器会将该3D对象“压平”到2D平面,这样就会导致以下问题:
- 透视失真:当视角旋转时,浏览器无法正确计算3D空间中的透视关系,导致元素看起来模糊或扭曲。
- 渲染精度降低:在2D平面上渲染3D变换的结果时,浏览器可能会对元素进行重新采样,降低渲染精度,从而导致模糊。
问题解决
给 div
以及其包裹着的HTML界面添加 transform-style: preserve-3d
属性
-
transform-style
用于控制元素的子元素在 3D 空间中的呈现方式。它决定了子元素是否保留其 3D 位置和变换效果。
- 当设置为
preserve-3d
时,浏览器让子元素在 3D 空间中保持其位置和变换,允许它们相对于父元素进行 3D 变换。也就是说子元素会按照其在 3D 空间中的位置进行渲染,而不是被“压平”到一个 2D 平面而导致透视失真或渲染精度降低 - 默认值为
flat
,子元素会被扁平化到父元素的 2D 平面上,忽略 3D 变换。
- 当设置为
// ...省略代码...
const div = document.createElement('div');
div.style.backfaceVisibility = 'hidden'; // 避免背面渲染问题
div.style.transformStyle = 'preserve-3d'; // 保持3D变换!
document.body.appendChild(div);
// ...省略代码...
<template>
<div class="w-[65px] h-[48px] bg-black body">
<div class="text-white">你好</div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.body{
transform-style: preserve-3d;
}
</style>