Flickering effects in THREE.js using Frame Buffer Objects

I've encountered a strange flickering issue while working on a THREE.js scene that involves using a Frame Buffer Object. The flickering disappears when I comment out the line:

mesh.material.uniforms.fboData.value = renderTargetA.texture
.

THREE.FBO = function(w, m) {
  this.scene = new THREE.Scene();
  this.camera = new THREE.OrthographicCamera(-w/2, w/2, w/2, -w/2, -1, 1);
  this.scene.add(new THREE.Mesh(new THREE.PlaneGeometry(w, w), m));
};

function resize() {
  var w = window.innerWidth,
      h = window.innerHeight;
  camera.aspect = w / h;
  camera.updateProjectionMatrix();
  renderer.setSize(w, h, false);
}

function getTexture(src) {
  var image = document.createElement('img');
  var tex = new THREE.Texture(image);
  image.addEventListener('load', function(event) {
    tex.needsUpdate = true;
  });
  image.src = src;
  return tex;
}

function getDataTexture(fboData, config) {
  var dataTexture = new THREE.DataTexture(fboData, config.w, config.w, config.format, config.type);
  dataTexture.minFilter = config.minFilter;
  dataTexture.magFilter = config.magFilter;
  dataTexture.needsUpdate = true;
  return dataTexture;
}

/**
* Scene
**/

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 1000);
var renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
camera.position.set(0, 0, 2);
document.body.appendChild(renderer.domElement);

/**
* Geometry
**/

// fbo config
var config = {
  w: 512, // number of pixels in each dimension
  type: THREE.FloatType,
  format: THREE.RGBAFormat,
  stride: 4, // number of units per cell in format
  minFilter: THREE.NearestFilter,
  magFilter: THREE.NearestFilter,
}

var n = 2**10,
    rootN = Math.pow(n, 0.5),
    translations = new Float32Array(n * 3),
    fboData = new Float32Array(config.w**2 * config.stride),
    fboOffsets = new Float32Array(n * 2),
    translationIterator = 0,
    fboOffsetIterator = 0;

for (var i=0; i<n; i++) {
  // set rendered vertex offsets
  var x = (((i % rootN) / rootN) * 2) - 1;
  var y = ((Math.floor(i / rootN) / rootN) * 2) - 1;

  translations[translationIterator++] = x;
  translations[translationIterator++] = y;
  translations[translationIterator++] = 0;

  // set uvs for looking up FBO data that corresponds to this cell
  fboOffsets[fboOffsetIterator++] = (i % config.w) / config.w;
  fboOffsets[fboOffsetIterator++] = (Math.floor(i / config.w)) / config.w;

  // write the x, y components of the fboData array
  fboData[(i*config.stride)    ] = Math.random(); // make data non-negative
  fboData[(i*config.stride) + 1] = Math.random(); // make data non-negative
  fboData[(i*config.stride) + 2] = 1;
  if (config.stride === 4) fboData[(i*config.stride) + 3] = 1;
}

// create the FBO
var fboTexture = getDataTexture(fboData, config);
fboMaterial = new THREE.RawShaderMaterial({
  uniforms: {
    fboTexture: {
      type: 't',
      value: fboTexture,
    },
  },
  vertexShader: document.querySelector('#fbo-vertex').textContent,
  fragmentShader: document.querySelector('#fbo-fragment').textContent,
});
fboMaterial.uniforms.fboTexture.needsUpdate = true;
fbo = new THREE.FBO(config.w, fboMaterial);

// create render targets a + b to which the simulation will be rendered
renderTargetA = new THREE.WebGLRenderTarget(config.w, config.w, {
  format: config.format,
  type: config.type,
  minFilter: config.minFilter,
  magFilter: config.magFilter,
  wrapS: THREE.RepeatWrapping,
  wrapT: THREE.RepeatWrapping,
  stencilBuffer: false,
});
renderTargetB = renderTargetA.clone();

// render the initial data to target a
renderer.setRenderTarget(renderTargetA);
renderer.render(fbo.scene, fbo.camera);
renderer.setRenderTarget(null);
// render the initial data to target b
renderer.setRenderTarget(renderTargetB);
renderer.render(fbo.scene, fbo.camera);
renderer.setRenderTarget(null);

// create the geometry
var geometry = new THREE.InstancedBufferGeometry();
var position = new THREE.BufferAttribute(new Float32Array([0, 0, 0]), 3);
var translation = new THREE.InstancedBufferAttribute(translations, 3, false, 1);
var fboOffset = new THREE.InstancedBufferAttribute(fboOffsets, 2, false, 1);
geometry.setAttribute('position', position);
geometry.setAttribute('translation', translation);
geometry.setAttribute('fboOffset', fboOffset);

// build the rendered mesh
var material = new THREE.RawShaderMaterial({
  vertexShader: document.getElementById('vertex-shader').textContent,
  fragmentShader: document.getElementById('fragment-shader').textContent,
  uniforms: {
    fboData: {
      type: 't',
      value: fboTexture,
    }
  }
})
mesh = new THREE.Points(geometry, material);
mesh.frustumCulled = false;
scene.add(mesh);

// resize everything
resize();

// resize
window.addEventListener('resize', resize);

/**
* Main
**/

function updateFBO() {

  // at the start of the render block, A is one frame behind B
  var oldA = renderTargetA; // store A, the penultimate state
  renderTargetA = renderTargetB; // advance A to the updated state
  renderTargetB = oldA; // set B to the penultimate state

  // pass the updated values to the fbo
  fboMaterial.uniforms.fboTexture.value = renderTargetA.texture;

  // run a frame and store the new positional values in renderTargetB
  renderer.setRenderTarget(renderTargetB);
  renderer.render(fbo.scene, fbo.camera);
  renderer.setRenderTarget(null);

  // pass the new positional values to the scene users see
  if (mesh) mesh.material.uniforms.fboData.value = renderTargetA.texture;
}

function animate() {
  requestAnimationFrame(animate);
  updateFBO();
  renderer.render(scene, camera);
}

animate();
<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
    <style>* {margin: 0; height: 100%; width: 100%;}</style>
  </head>
  <body>
    <!-- rendered vert shader -->
    <script type='x-shader/x-vertex' id='vertex-shader'>
    precision highp float;

    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    uniform sampler2D fboData;

    attribute vec3 position;
    attribute vec3 translation;
    attribute vec2 fboOffset;

    varying vec4 vPixel;

    void main() {
      gl_PointSize = 7.0;
      vec3 pos = position + translation;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);

      vPixel = texture2D(fboData, fboOffset);
    }
    </script>

    <!-- rendered frag shader -->
    <script type='x-shader/x-fragment' id='fragment-shader'>
    precision highp float;

    varying vec4 vPixel;

    void main() {
      gl_FragColor = vPixel;
    }
    </script>

    <!-- FBO vert -->
    <script type='x-shader/x-vertex' id='fbo-vertex'>
    precision lowp float;

    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;

    attribute vec2 uv; // x,y offsets of each point in FBO texture
    attribute vec3 position;

    varying vec2 vUv;

    void main() {
      // vUv is the position of the current observation in the texture
      vUv = vec2(uv.x, 1.0 - uv.y);

      // the position of the cell in the texture
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
    </script>

    <!-- FBO frag -->
    <script type='x-shader/x-fragment' id='fbo-fragment'>
    precision lowp float;

    uniform sampler2D fboTexture;

    varying vec2 vUv;

    void main() {

      vec4 pixel = texture2D(fboTexture, vUv);

      // write the updated value to the screen so it can be read
      gl_FragColor = vec4(pixel);
    }
    </script>

    <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js'></script>
  </body>
</html>

Does anyone have any insights into what might be causing this strobing effect? Could it be related to the synchronization of the two render targets?

Answer №1

Upon reviewing the results from both your renderTargetA and B, it appears that one is displaying data on the top row of the image while the other is showing data at the bottom row. It seems like your "ping-pong" effect is functioning correctly, but the flickering occurs because your mesh is reading information from the same row which happens to be empty half of the time.

Frame buffer 0 (Data at top):

https://i.sstatic.net/b34QR.png


Frame buffer 1 (Data at bottom):

https://i.sstatic.net/onyY6.png

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

Having trouble displaying form in a different view, form is not appearing as expected

I am facing an issue with rendering a form inside a modal. The form is being rendered but the form_for does not show up, only the inputs are visible. This prevents me from targeting the submit button, which I need for ajax functionality. My file path: Adg ...

Utilize the input field value in an HTML dialog box to assign it to a variable in the code.gs file with the help

I'm trying to create a dialog box where the user can select a year, and then have the server process the selected value using the function doSomethingWithCompetitionYear(theYear). I've researched several discussions, but I'm having trouble ...

Discover the art of utilizing two distinct binding strings, wherein upon the selection of either, the alternate binding string shall automatically be

Having to use two different bindingstrings is a requirement due to a tool used for creating PDFs. My objective is to have the corresponding bindingstring turn "Off" when a user clicks on either the Yes or No button, and have the clicked button turn to "Yes ...

The comparison between importing TypeScript and ES2015 modules

I am currently facing an issue with TypeScript not recognizing the "default export" of react. Previously, in my JavaScript files, I used: import React from 'react'; import ReactDOM from 'react-dom'; However, in TypeScript, I found tha ...

Listen for the load event during an AJAX request without using jQuery's add

I have four HTML files and four corresponding JavaScript files. Each JavaScript file is externally loaded by its respective HTML file. Specifically, index.html loads javascript.js, 1.html loads javascript1.js, 2.html loads javascript2.js, and 3.html loads ...

Exploring JQuery and JavaScript for loop guide

Currently working on a small application where users are required to input information, and I am implementing text hints in the input fields. However, I have encountered an issue when using a for loop in my code. Oddly enough, the text hints display corre ...

The JS copy function is successful when operating on a single element, but it encounters issues when attempting to run on multiple elements, only copying

My code includes a copy function that copies the data from a textarea to the clipboard when a button is clicked. The functionality works perfectly for the first textarea, but for subsequent textareas, the buttons do not perform the copy action. Check out ...

Vanilla JavaScript: toggling text visibility with pure JS

Recently, I started learning javascript and I am attempting to use vanilla javascript to show and hide text on click. However, I can't seem to figure out what is going wrong. Here is the code snippet I have: Below is the HTML code snippet: <p cla ...

Struggling with error management while using react-redux during the SignUp process

https://i.sstatic.net/OD2fl.pngWithin my component code, I handle user sign up and error checking. Initially, the error value is null. let error = useSelector((state) => state.authReducer.error); const checkErrorLoading = () => { ...

The web method within the aspx page is failing to execute

On page load, I am attempting to make an ajax request using the AngularJS $http service to fetch JSON data from a web method located in my User.aspx.cs page. The web method is defined as follows: [WebMethod] [ScriptMethod(ResponseFormat=ResponseForma ...

Ways to identify if one object is positioned above another

So, here's the scenario: I'm trying to figure out how to detect when one element is positioned on top of another. Specifically, I'm dealing with SVG elements: <circle r="210.56" fill="#1ABCDB" id="01" priority="4" cx="658" cy="386">& ...

Altering the text and functionality of buttons with jQuery

A JavaScript method I have is designed to change based on the state of a button, which is determined by using indexOf("..some text.."). $('#add1').click(function(){ if($(this).text().indexOf("Add Me!")) { $.ajax({ type: & ...

Is it true that threejs does not perform depth division?

Question: Is it necessary for threejs to set the w value of vertices equal to their depth? During the process of projecting objects onto a screen, those that are farther away from the focal point tend to get projected closer towards the center of the scre ...

Elegant switch in jQuery

I am trying to use jQuery to create an animated toggle button. The toggle function is working correctly, but I am having trouble adjusting the speed and smoothness of the animation. After researching different methods and attempting to modify the values i ...

What is the recommended Vue js lifecycle method for initializing the materialize dropdown menu?

https://i.stack.imgur.com/cjGvh.png Upon examining the materialize documentation, it is evident that implementing this on a basic HTML file is straightforward: simply paste the HTML code into the body and add the JavaScript initializer within a script tag ...

JavaScript can be used to extract a specific value from a SOAP response

In order to extract the Patient ID (PATAA000000040) from the SOAP response below using JavaScript and insert it into a Mirth destination, we need to target the value under the livingSubjectId tag. It's important to note that this tag may repeat, but w ...

Looking for support for glBlendEquationEXT in your WebGL project?

WebGL currently supports ADD, SUBTRACT, and REVERSE_SUBTRACT operations. For more information, visit I am in need of support for MAX and MIN operations in WebGL as well. You can find more information on this idea at Does anyone know of a workaround to ac ...

Autonomous JQuery Modules

Is it possible to separate the functions in JQuery and use only the ones needed by splitting the file with PHP? By doing this, I aim to improve page speed, save bandwidth, and have more control over the functions used through the backend. Can the functio ...

Communicating between iframes and parent elements via events

I'm trying to trigger an event in my iframe using the following code: $('body').trigger('my_event'); However, I want to bind this event on my main page that contains the iframe like this: $('iframe').find('body&ap ...

Exploring the Inner Workings of a React ES6 Class Component

I'm currently exploring the best practices in React and I find myself questioning the structure of a React Component when utilizing ES6 classes. I am particularly interested in where to declare variables or properties that the class or .js file will u ...