【问题标题】:How to make recursive portals in three.js如何在three.js中制作递归门户
【发布时间】:2019-05-09 03:17:14
【问题描述】:

我想用三个 js 制作一个非常简单的门户游戏,但是我在制作递归门户时遇到了问题。

我想出了将相机放置在一个门户上并在另一个门户上将其图像渲染为纹理的想法。它工作正常,除了门户不能递归,因为默认情况下 WebGL 不能将纹理呈现给自身。因此,当我一个接一个地放置门户并通过其中一个查看时,我看不到第二个。有什么简单的方法可以避免这个问题吗?

class Portal {
    constructor(source, destination) {
        this.render_target = new THREE.WebGLRenderTarget($(window).width(), $(window).height())
        this.camera = new THREE.PerspectiveCamera(45, 1, 0.1, 10000)
        this.camera.position.set(...destination)
        this.object = new THREE.Object3D()
        let materials = new Array(6).fill(0).map(x => new THREE.MeshBasicMaterial({color: 0x0000ff}))
        materials[4] = new THREE.MeshBasicMaterial({ map: this.render_target.texture })
        this.src_portal = new THREE.Mesh(new THREE.BoxGeometry(50, 50, 1), materials)
        this.src_portal.position.set(...source)
        this.object.add(this.src_portal)
        materials = new Array(6).fill(0).map(x => new THREE.MeshBasicMaterial({color: 0x0000ff}))
        materials[5] = new THREE.MeshBasicMaterial({ color: 0xff0000 })
        this.dst_portal = new THREE.Mesh(new THREE.BoxGeometry(50, 50, 1), materials)
        this.dst_portal.position.set(...destination)
        this.object.add(this.dst_portal)
    }
    render(renderer, scene, camera) {
        this.camera.lookAt(this.camera.position.x, this.camera.position.y, this.camera.position.z-1)
        this.camera.applyQuaternion(camera.quaternion)
        renderer.render(scene, this.camera, this.render_target)
    }
}

//main rendering

$(document).ready(function() {
    const scene = new THREE.Scene()
    camera = new THREE.PerspectiveCamera(45, $(window).width()/$(window).height(), 0.1, 10000)
    var renderer = new THREE.WebGLRenderer()
    renderer.setClearColor(0xffffff)
    renderer.setSize($(window).width(), $(window).height())
    $("#root").append(renderer.domElement)

    camera.position.set(100, 100, 100)
    camera.lookAt(scene.position)

    var orbitControl = new THREE.OrbitControls(camera, renderer.domElement);
    orbitControl.addEventListener('change', function () {
        renderer.render(scene, camera)
    });

    let grid = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 100, 100), new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, color: 0x000000, wireframe: true
    }))
    grid.rotation.x = Math.PI/2
    scene.add(grid)

    let portal = new Portal([0, 50, 0], [10, 50, 100])
    scene.add(portal.object)

    let materials = new Array(6).fill(0).map(x => new THREE.MeshBasicMaterial({
        color: Math.floor(Math.random()*0xffffff)
    }))

    let box = new THREE.Mesh(new THREE.BoxGeometry(50, 50, 50), materials)
    box.position.set(0, 0, -300)
    scene.add(box)

    let frames = 0
    setInterval(() => {
        $("#fps").html("FPS: "+frames)
        frames = 0
    }, 1000);
    render()
    function render() {

        portal.render(renderer, scene.clone(), camera)
        renderer.render(scene, camera)
        requestAnimationFrame(render)
        frames++
    }
})

当我尝试放置传送门进行循环时,它给了我警告“GL_INVALID_OPERATION:glDrawArrays:绘图的源和目标纹理相同。”门户在其内部是完全不可见的。有没有可能避免这种情况,还是我应该完全不同?

【问题讨论】:

标签: javascript three.js


【解决方案1】:

您必须从不同的相机将场景渲染到纹理,然后渲染主场景。查看您的代码,您只有一个摄像机并且只渲染一次场景。 有可能达到这个效果。 Lee Stemkoski 有一个很好的例子,你可能想看看。

https://stemkoski.github.io/Three.js/Camera-Texture.html

代码https://github.com/stemkoski/stemkoski.github.com/blob/master/Three.js/Camera-Texture.html

【讨论】:

  • 我有一个外部场景和相机,并在渲染主场景的同时在动画帧函数中调用 Portal.render() 方法
  • @SzymonKurowski 从您的评论中我只能看到主循环调用渲染一次。也许提供 jsfiddle 或至少提供其余代码?
  • 好的,感谢您提供此链接,我在其中找到了解决方案。重点是使用整个附加场景作为门户和场景之间的中介。
  • 您不必使用任何额外的场景......只需为具有不同相机和渲染目标的门户单独渲染它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
相关资源
最近更新 更多