I am working on developing a simple portal game using three.js, but I am facing a challenge with creating recursive portals.
One solution I have considered is placing the camera on one portal and rendering its image as a texture on the other portal. While this method works well, it does not support recursion because WebGL cannot render a texture onto itself by default. Therefore, when I position the portals in succession and look through one of them, the second portal is not visible. Is there an easy way to overcome this issue?
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++
}
})
While attempting to create a loop with the portals, I encountered the error message 'GL_INVALID_OPERATION : glDrawArrays: Source and destination textures of the draw are the same.' This resulted in the portal being invisible within itself. Is it possible to resolve this issue, or should I consider a different approach entirely?