ТРИ js изображения не отображаются на холсте

#javascript #three.js

#javascript #three.js

Вопрос:

У меня есть две сцены и для рендеринга. Я также использую Bootstrap 4 для модального окна. Одна сцена является основной, другая отображается в модальном окне, поэтому я использую два рендеринга: один для элемента на главном экране и один для модального окна.

Код:

Основная сцена:

<div class="output3d" id="WebGL-output"></div>

 function setMainScene() {
        scene = new THREE.Scene();
        scene.background = new THREE.Color("#ffffff");

        renderer = new THREE.WebGLRenderer({antialias: true, logarithmicDepthBuffer: true});
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 2000);
        camera.position.x = home[0];
        camera.position.y = home[1];
        camera.position.z = home[2];
        camera.lookAt(home[3], home[4], home[5])

        controls = initOrbitControls(camera, renderer, new THREE.Vector3(home[3], home[4], home[5]))
}
  

Сцена для модального окна:

 <div class="modal" data-backdrop="static" id="ObjectInfo" role="dialog" tabindex="-1">
    <div class="modal-dialog modal-xl modal-dialog-scrollable" role="document" style="bottom: 0">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="ObjectId"></h5>
                <button aria-label="Close" class="close" data-dismiss="modal" onclick="" type="button">
                    <span aria-hidden="true">amp;times;</span>
                </button>
            </div>
            <div class="modal-body">
                <div class="container">
                    <div class="row">
                        <div class="col">
                            <div>
                                <img src="css/360.jpg" alt="<-->">
                            </div>
                            <div id="FrontView"></div>
                        </div>
                        <div class="col">
                            <p id="ObjectType" class="mb-0"></p>
                            <p id="ObjectInfoText" class="mb-0"></p>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                </div>
            </div>
        </div>
    </div>
</div>
  
  function setModalWindowScene() {
        modalWindowScene = new THREE.Scene()
        modalWindowScene.background = new THREE.Color("#ffffff");

        modalWindowRenderer = new THREE.WebGLRenderer({antialias: true});
        modalWindowRenderer.setPixelRatio(window.devicePixelRatio);
        modalWindowRenderer.setSize(450, 450);
        document.getElementById("FrontView").appendChild(modalWindowRenderer.domElement);

        modalWindowCamera = new THREE.PerspectiveCamera(45, document.getElementById("FrontView").innerWidth / document.getElementById("FrontView").innerHeight, 1, 100);
        modalWindowControls = new THREE.OrbitControls(modalWindowCamera, modalWindowRenderer.domElement);
  

Инициализация:

 function init() {
    setMainScene()
    setModalWindowScene()

    // adding objects to main scene
    addRoom()
    addRacks()
    addExtinguishingCylinders()
    addHotHalls()
    addWires()
    addLights()

    window.addEventListener('resize', onWindowResize, false);
}
  

Рендеринг:

 function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    renderer.render(scene, camera);
    if (modalWindowOpen) {
        modalWindowRenderer.render(modalWindowScene, modalWindowCamera);
    }
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    modalWindowCamera.aspect = document.getElementById("FrontView").offsetWidth / document.getElementById("FrontView").offsetHeight;

    camera.updateProjectionMatrix();
    modalWindowCamera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
    modalWindowRenderer.setSize(document.getElementById("FrontView").offsetWidth, document.getElementById("FrontView").offsetHeight)
}
  

HTML:

 <script type="text/javascript">
    init();
    animate();
</script>
  

Когда пользователь открывает модальное окно, объект добавляется в модальную сцену, и пользователь может взаимодействовать с ним в модальной сцене с помощью модальных элементов управления.

Проблема:

Когда пользователь впервые открывает модальное окно, изображение объекта не отображается, несмотря на то, что объект добавляется <div id="FrontView"></div> в модальное окно, но оно пустое. Но когда пользователь изменяет размер окна, изображение появляется и остается навсегда.

Интересная вещь. Когда в модальном окне нет изображения, я могу вращать объект с элементами управления, который был привязан к модальной сцене.

Демонстрация: перед изменением размера
после изменения размера

Ответ №1:

Вам нужно вызвать render в вашей функции инициализации.
Похоже, вы вызываете render только в своей функции onWindowResize, которая не будет запускаться до тех пор, пока размер окна не будет фактически изменен (не при загрузке страницы).
Вероятно, вам также нужен цикл рендеринга.

Взгляните на пример ниже.
Вы увидите вверху, я вызываю функцию init для установки сцены, затем функцию animate для запуска цикла рендеринга.

 var camera, scene, renderer, mesh, material;
// init scene.
init();
// Start animation/render loop.
animate();

function init() {
    // Renderer.
    renderer = new THREE.WebGLRenderer();
    //renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    // Add renderer to page
    document.body.appendChild(renderer.domElement);

    // Create camera.
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 400;

    // Create scene.
    scene = new THREE.Scene();

    // Create material
    material = new THREE.MeshPhongMaterial();

    // Create cube and add to scene.
    var geometry = new THREE.BoxGeometry(200, 200, 200);
    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    // Create ambient light and add to scene.
    var light = new THREE.AmbientLight(0x404040); // soft white light
    scene.add(light);

    // Create directional light and add to scene.
    var directionalLight = new THREE.DirectionalLight(0xffffff);
    directionalLight.position.set(1, 1, 1).normalize();
    scene.add(directionalLight);

    // Add listener for window resize.
    window.addEventListener('resize', onWindowResize, false);

}

function animate() {
    requestAnimationFrame(animate); // this makes the animate function a loop that runs every frame.
    mesh.rotation.x  = 0.005;
    mesh.rotation.y  = 0.01;
    renderer.render(scene, camera);
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}  
 <script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>  

Комментарии:

1. У меня тоже есть animate() функция, и я вызываю ее после init() функции. Если бы я этого не сделал, у меня не было бы никакого изображения, но у меня есть визуализация основной сцены. Также в функции onWindowResize() я не вызываю средство визуализации, я только меняю его «настройки», как в примере.

2. Если вы не показываете весь соответствующий код … т.е. вашу анимированную функцию.. мы не можем оказать вам необходимую помощь. Как я уже сказал, вам, вероятно, нужен цикл рендеринга, который в случае примера, который я опубликовал в функции animate. Что делает его циклом, так это requestAnimationFrame(animate); вызов.

3. Хорошо, я обновил сообщение. Но это не решает проблему.

Ответ №2:

Хорошо, похоже, что я установил нулевой аспект при создании modelWindowCamera , потому что объект document.getElementById("FrontView") не имел размера до первого рендеринга. И когда я изменил масштаб окна, document.getElementById("FrontView") у него не было нулевых размеров, а аспект камеры обновлялся без нулевого аспекта.

Для решения я просто установил значение aspect равным константе 1, и теперь код выглядит так:

    modalWindowCamera = new THREE.PerspectiveCamera(45, 1, 1, 100);