Как предотвратить применение CSS к одной сцене Three.JS для всех сцен - PullRequest
1 голос
/ 20 июня 2019

Это может быть больше похоже на сделку типа "вам придется проделать долгий путь", но здесь все идет ...

Когда я применяю CSS для управления непрозрачностью только одного HTML-элемента, который является контейнером сцены Three.JS, в которой есть несколько элементов, каждый из которых является контейнером для своей собственной сцены, применяется CSS (даже в строке уровень) только к одному из тех элементов, которые содержат сцену, применяются ко всем элементам, которые содержат сцену, а не только к целевому. Это происходит с любым атрибутом CSS, применяемым после публикации, а не только с непрозрачностью.

Причина, по которой я пытаюсь использовать этот подход для контроля непрозрачности таким образом, заключается в том, что в моем исследовании не было прямого способа установить непрозрачность для группового объекта Three.JS, который содержит от 1 до N сеток. Я (в теории) пытаюсь не определять все материалы с прозрачностью, установленной на "true", а затем мне приходится делать рекурсивные обновления для всех сеток в объекте Three.JS Group, где анимация будет исчезать / исчезать.

Некоторые из групповых объектов, с которыми я работаю, будут иметь много сеток, определенных в них. Таким образом, вместо того, чтобы обновлять непрозрачность каждой отдельной сетки, содержащейся в объекте группы Three.JS, моей целью было / нужно, чтобы отдельные сцены для каждого типа анимации могли обеспечить любую прозрачность, примененную к ней, как есть. затем просто настройте HTML-элемент, содержащий свойство opacity этой анимации.

Я пытался использовать одну камеру и несколько камер, но безрезультатно. Я также попытался вложить контейнеры в один дополнительный элемент и установить 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, а не только с первой сценой.

Есть ли причина, по которой стили CSS, применяемые к одной HTML-сцене, содержащей элемент, применяются ко всем другим сценам, содержащим элементы? Должен ли я просто смириться с этим и пройти долгий путь в контроле прозрачности сетки?

Спасибо.

1 Ответ

1 голос
/ 20 июня 2019

Настройка прозрачности для THREE.Group:

A Group - это просто контейнер. Таким образом, у него есть дети, которые потенциально являются другими Group s. Но вы можете применить прозрачность только к Material, который назначен на уровне Mesh, а не Groups. Однако не все потеряно, потому что вы можете monkey patch 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>
...