css - 如何防止应用于一个 Three.JS 场景的 CSS 应用于所有场景
问题描述
这可能更像是“你将不得不做很长的路要走”类型的交易,但它就在这里......
当我应用 CSS 来控制只有一个 HTML 元素的不透明度时,该元素是 Three.JS 场景的容器,其中有多个元素,每个元素都是它们自己场景的容器,CSS 应用(即使在内联级别)只有一个包含场景的元素被应用于所有包含场景的元素,而不是特定的目标元素。任何帖子应用的 CSS 属性都会发生这种情况,而不仅仅是不透明度。
我尝试这种方法来控制不透明度的原因是,根据我的研究,没有直接的方法可以在包含 1 到 N 个网格的 Three.JS 组对象上设置不透明度。我(理论上)试图不必定义透明度设置为“true”的所有材质,然后必须对动画会淡入/淡出的 Three.JS Group 对象中的所有网格进行递归更新。
我正在使用的一些组对象将在其中定义许多网格。因此,与其更新包含在 Three.JS 组对象中的每个单独网格本身的不透明度,我的目标是/是为每种类型的动画提供单独的场景,这些动画能够应用任意数量的透明度,并按原样运行然后只需调整包含该动画的 opacity 属性的 HTML 元素。
我试过使用一台相机和多台相机都无济于事。我还尝试将容器嵌套在一个附加元素中并在父元素上设置 CSS,但出现了同样的问题。我没有尝试过使用多个渲染器,因为我在研究中收集到的是,这样做是不受欢迎的,并且可能导致性能问题和上下文限制。渲染循环还将“autoClear”设置为 false,以便所有场景一起渲染。
这是 HTML 语法。您会注意到第一个元素的不透明度设置为 0.5 的内联样式,而第二个元素没有应用内联样式:
<div class="three-js-container" id="scene-container-1" style="opacity:0.5;"></div>
<div class="three-js-container" id="scene-container-2"></div>
这是Javascript代码:
/* Only one renderer instance is created */
var universalRenderer = new THREE.WebGLRenderer({antialias: true, alpha:true});
/* references to all containers are made */
var containerForScene1 = document.getElementById("scene-container-1");
var containerForScene2 = document.getElementById("scene-container-2");
/* two different cameras are created */
var cameraForScene1 = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.001, 1000);
var cameraForScene2 = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.001, 1000);
/* two different scenes are created, one for each element container */
var scene1 = new THREE.Scene();
scene1.userData.element = containerForScene1;
var scene2 = new THREE.Scene();
scene2.userData.element = containerForScene2;
/* the renderer is applied to both scene containers */
containerForScene1.appendChild(universalRenderer.domElement);
containerForScene2.appendChild(universalRenderer.domElement);
当两个动画都播放时,两个场景都以 1/2 的不透明度渲染,而不仅仅是第一个场景本身。
为什么将应用于包含元素的 HTML 场景的 CSS 样式应用于包含元素的所有其他场景是有原因的?我是否只需要吸收它并在控制网格不透明度方面走很长一段路?
谢谢。
解决方案
为 a 设置透明度THREE.Group
:
AGroup
只是一个容器。因此,它有孩子,可能是其他Group
的。但是您只能将透明度应用于在级别Material
分配的 a ,而不是。但是,并非所有内容都丢失了,因为您可以使用猴子补丁来无缝执行操作。Mesh
Groups
Group
// MONKEY PATCH
Object.defineProperty(THREE.Group.prototype, "transparent", {
set: function(newXP) {
this.traverse(node => {
if (node.material) {
node.material.transparent = newXP
node.material.opacity = (newXP) ? 0.5 : 1
}
})
}
})
// Set up the renderer
const renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
})
document.body.appendChild(renderer.domElement)
renderer.setSize(window.innerWidth, window.innerHeight)
const scene = new THREE.Scene()
const size = new THREE.Vector2()
renderer.getSize(size)
const camera = new THREE.PerspectiveCamera(28, size.x / size.y, 1, 1000)
camera.position.set(0, 20, 100)
camera.lookAt(scene.position)
scene.add(camera)
camera.add(new THREE.PointLight(0xffffff, 1))
function render() {
renderer.render(scene, camera)
}
const axis = new THREE.Vector3(0, 1, 0)
function animate() {
requestAnimationFrame(animate)
camera.position.applyAxisAngle(axis, 0.005)
camera.lookAt(scene.position)
render()
}
animate()
// Populate the scene
const cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5)
let opaqueCubes = []
let transparentCubes = []
const randomInRange = () => Math.random() * ((Math.random() <= 0.5) ? -10 : 10)
const opaqueGroup = new THREE.Group()
scene.add(opaqueGroup)
for (let i = 0; i < 10; ++i) {
opaqueGroup.add(new THREE.Mesh(cubeGeo, new THREE.MeshPhongMaterial({
color: "red"
})))
opaqueGroup.children[i].position.set(randomInRange(), randomInRange(), randomInRange())
}
const transparentGroup = new THREE.Group()
scene.add(transparentGroup)
for (let i = 0; i < 10; ++i) {
transparentGroup.add(new THREE.Mesh(cubeGeo, new THREE.MeshPhongMaterial({
color: "green"
})))
transparentGroup.children[i].position.set(randomInRange(-10, 10), randomInRange(-10, 10), randomInRange(-10, 10))
}
// Control the transparency from the input
const xparent = document.getElementById("xparent")
xparent.addEventListener("change", (e) => {
transparentGroup.transparent = xparent.checked
})
html,
body {
padding: 0;
margin: 0;
overflow: hidden;
}
#control {
position: absolute;
top: 0;
left: 0;
padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.js"></script>
<div id="control">
<label>Make the green ones transparent:<input id="xparent" type="checkbox" /></label>
<div>
推荐阅读
- python - 如何获取 NetworkX 图形集中的图形数量?
- javascript - 如何在 html 代码中注入 javascript 函数代码?
- prolog - 术语的安全排序
- php - Laravel orWherehas 过滤多列关系
- r - R bslib 更改导航栏颜色引导版本 5
- javascript - 使用参数访问网站时出现404错误(vuejs)
- javascript - JS - 正则表达式适用于 regex101 但不适用于我的节点脚本
- dnssec - 如何启用 SSHFP?
- apache-kafka - Confluent Operator 添加额外的连接器
- javascript - 为什么 array.map 嵌套在 array.forEach 中(在这种情况下)比其他方式快得多?