Creating Recursive Portals with three.js

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?

Answer №1

To achieve the desired effect, you need to render the scene to a texture using a different camera before rendering the main scene. It appears that in your code, you are only utilizing one camera and rendering the scene just once. Luckily, there is a helpful example created by Lee Stemkoski that demonstrates how to accomplish this.

Check out the example here:

You can find the code for this example on GitHub: https://github.com/stemkoski/stemkoski.github.com/blob/master/Three.js/Camera-Texture.html

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the process for including body text in a Bootstrap tooltip?

I am attempting to enhance a Bootstrap tooltip by adding body text, as it typically only includes a basic title. After reviewing the Bootstrap 5 documentation, it seems that the simplest approach is to utilize the template option: template Base HTML used ...

In a React component, what is the significance of "this" in relation to accessing state values (this.state...)?

I encountered a challenging issue with the usage of the this keyword while setting a state within an ajax call. It seems like I may have misunderstood something about how React components operate. How should I properly utilize the this keyword in this sp ...

Issues with loading CSS and JS resources in vue.js running on Kubernetes, encountering a 404 error

We are facing an issue with getting our vue.js application to work on Kubernetes (running in a container using nginx). We are using ingress to route to the site, and below is our configuration: Dockerfile: # build stage FROM public.ecr.aws/docker/library/ ...

Load upcoming and previous slides in advance

Currently, I have implemented a basic slideshow on my website. It functions properly, but I am interested in preloading the previous and next slides to enhance its speed. Is there anyone who can assist me with this request? ...

The React DOM element undergoes mounting and unmounting on each render cycle when it should be simply altered/updated

As per the React documentation, callback refs are invoked during both component mounting (with the DOM element's value) and unmounting (with null): When a React component mounts, the ref callback is triggered with the actual DOM element, and when it ...

Attempting to eliminate quotation marks from JSON keys that are stored in an array

I am working with an array of JavaScript objects that represent musical notes in my front-end development. To store this data, I had to convert the object array into a JSON string using JSON.stringify(objectArray) before placing it into a hidden input fiel ...

How can we guide the user to a different page when a particular result is retrieved by AJAX?

Whenever my PHP function makes a database call, I receive multiple results. The ajax then displays these results in a div element. My question is: How can I redirect the user to the next page once I obtain a specific result from the PHP function? Current ...

Google App Script - Mapping Error - TypeError: Property 'map' is not defined for this object

Thanks to the amazing insight from the community, I recently discovered this helpful tip on BatchUpdating background colors of a specific google sheet. Excited to apply this to my own sheet, I encountered an error saying: TypeError: Cannot read property & ...

Error: Namespace declaration does not have a type annotation - TypeScript/Babel

After creating my app using the command npx create-react-app --typescript, I encountered an issue with generated code and namespaces causing Babel to throw an error. Here are the steps I took to try and resolve the issue: I ejected the project Updated b ...

retrieving information via AJAX call using jQuery

I've been tasked with customizing a book website, and I'm trying to integrate reviews from the Goodreads API. However, my Ajax request isn't returning any data. Here is the code snippet: $.ajax({ 'type': 'GET', & ...

Is it possible to add a class to the parent element when the input value of a sub-child element is

Is there a way to select and add a class to an li element in which the sub-child input is empty when clicking on button #btn-modal-clear? If so, what is the best approach to achieve this? Example HTML Code: <li>...<li> <li> <a c ...

Searching MySQL data with ng-repeat filter

I am facing a challenge in populating a div tag with ng-repeat and data from a MySQL database. My intention is to utilize ng-repeat for its filtering capabilities in the future. The dilemma lies in the integration of Angular and SQL. My desired HTML struc ...

The onClick event in React/NextJS is not functioning properly when applied to an external component

One dilemma I am facing involves my main page and a button component that I have created to be reused throughout my project. Strangely, when I add the onClick event to the external component, the click event does not seem to work. However, if I create the ...

What is the process for making a POST request with the Google Chrome Puppeteer library?

Hello everyone, I'm currently attempting to make a POST request using the puppeteer headless chrome library. I'm running into some issues with the code below and can't seem to figure out what's wrong. // Obtain the csrf token ...

Is it possible to both break down a function parameter and maintain a named reference to it at the same time?

When working with stateless functional components in React, it is common to destructure the props object right away. Like this: export function MyCompoment({ title, foo, bar }) { return <div> title: {title}, ...</div> } Now ...

Upon calling the createModalAddPost() function, a single window is triggered to open

Hey there, I'm having a JavaScript question. So, I have a panel that opens a window, and it works fine. But the issue arises when I close the window and try to open it again - it doesn't work. I have to reload the page every time in order to open ...

Working with AngularJS: Implementing a Service in a Controller

A service has been developed in AngularJS, but it is not being utilized in the controller. Service.js var appService = angular.module("appService", []); appService.service("bddService", function() { var bdds = bdd; this.getBdds = function(){ ...

Concealing URL in client-side fetch request within Next.js

A contact form built in Next.js makes use of the FormSubmit API to send emails upon clicking the submit button. Below is the code for the onSubmit handler: const handleSubmit = async (e) => { e.preventDefault(); const res = await fetch("https:/ ...

To retrieve the first td element by clicking a button within the corresponding row using JQuery

This may seem like a straightforward inquiry, but despite my best efforts, I have been unable to find a solution. I am looking to create a function that will allow me to click a button located in the 3rd td element and display the text from the first td e ...

Tips for identifying when a View has completed rendering?

I am facing a situation where I have multiple GWT widgets displayed within a single view. Within this view, the content is structured as follows: FlowPanel mainPanel = new FlowPanel(); RootPanel.get().add(mainPanel); Label label = new Label("test"); mai ...