When combining the ShaderMaterial with WebGLRenderer's logarithmicDepthBuffer feature enabled

In my scene, I apply the ShaderMaterial shown below to my objects. It works fine. However, when I enable the WebGLRenderer option logarithmicDepthBuffer to true, the Material defined is no longer displayed correctly.

new THREE.ShaderMaterial({
    uniforms: {
      color1: {
        value: new THREE.Color('#3a0000')
      },
      color2: {
        value: new THREE.Color('#ffa9b0')
      }
    },
    vertexShader: `
    varying vec3 vNormal;
    void main(void){
      vNormal      = normalMatrix * normalize(normal);
      gl_Position  = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    }`,

    fragmentShader: `
    uniform vec3 color1;
    uniform vec3 color2;
    varying vec3 vNormal;
    void main(void){
      vec3 view_nv  = normalize(vNormal);
      vec3 nv_color = view_nv * 0.5 + 0.5;
      vec3 c = mix(color1, color2, nv_color.r);
      gl_FragColor  = vec4(c, 1.0);
    }`,
    side: THREE.DoubleSide,
  });

Upon researching a solution to this issue, I came across a helpful SO answer. In a nutshell, the solution involves integrating 4 code snippets into the vertexShader and fragmentShader.

Where should I exactly place the provided code snippets within the Vertex shader body and Fragment shader body?

Despite trying various placements, I kept encountering WebGL errors.

THREE.WebGLProgram: shader error: 0 gl.VALIDATE_STATUS false gl.getProgramInfoLog Must have a compiled vertex shader attached. ERROR: 0:63: 'EPSILON' : undeclared identifier 

UPDATE playground added: https://codepen.io/anon/pen/gQoaye

If you include the logarithmicDepthBuffer option in the constructor, you will notice that the ShaderMaterial stops functioning correctly.

var renderer = new THREE.WebGLRenderer(logarithmicDepthBuffer:true);

Answer №1

Can you clarify where the provided code snippets, specifically the Vertex shader body and Fragment shader body, need to be integrated?

Within the vertex shader, it is necessary to define the EPSILON value.
Upon inclusion of the code snippets logdepthbuf_pars_vertex.glsl and logdepthbuf_vertex.glsl, the final vertex shader appears as follows:

#ifdef USE_LOGDEPTHBUF
#define EPSILON 1e-6
#ifdef USE_LOGDEPTHBUF_EXT
varying float vFragDepth;
#endif
uniform float logDepthBufFC;
#endif

varying vec3 vNormal;

void main(void){
    vNormal      = normalMatrix * normalize(normal);
    gl_Position  = projectionMatrix * modelViewMatrix * vec4(position,1.0);

#ifdef USE_LOGDEPTHBUF
    gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;
#ifdef USE_LOGDEPTHBUF_EXT
    vFragDepth = 1.0 + gl_Position.w;
#else
    gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;
#endif
#endif
}

Following the addition of the code snippets, the final fragment shader is as below:

#ifdef USE_LOGDEPTHBUF
uniform float logDepthBufFC;
#ifdef USE_LOGDEPTHBUF_EXT
#extension GL_EXT_frag_depth : enable
varying float vFragDepth;
#endif
#endif

uniform vec3 color1;
uniform vec3 color2;
varying vec3 vNormal;
void main(void){
    vec3 view_nv  = normalize(vNormal);
    vec3 nv_color = view_nv * 0.5 + 0.5;
    vec3 c = mix(color1, color2, nv_color.r);
    gl_FragColor  = vec4(c, 1.0);

#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)
    gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;
#endif
} 

Refer to the example below:

(function onLoad() {
  var container, camera, scene, renderer, orbitControls;
  
  function createModel() {

    var material = new THREE.ShaderMaterial({
    uniforms: {
      color1: {
        value: new THREE.Color('#3a0000')
      },
      color2: {
        value: new THREE.Color('#ffa9b0')
      }
    },
    vertexShader: `
    #ifdef USE_LOGDEPTHBUF
    #define EPSILON 1e-6
    #ifdef USE_LOGDEPTHBUF_EXT
    varying float vFragDepth;
    #endif
    uniform float logDepthBufFC;
    #endif

    varying vec3 vNormal;
    
    void main(void){
        vNormal      = normalMatrix * normalize(normal);
        gl_Position  = projectionMatrix * modelViewMatrix * vec4(position,1.0);

    #ifdef USE_LOGDEPTHBUF
        gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;
    #ifdef USE_LOGDEPTHBUF_EXT
        vFragDepth = 1.0 + gl_Position.w;
    #else
        gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;
    #endif
    #endif
    }`,

    fragmentShader: `
    #ifdef USE_LOGDEPTHBUF
    #ifdef USE_LOGDEPTHBUF_EXT
    #extension GL_EXT_frag_depth : enable
    varying float vFragDepth;
    #endif
    uniform float logDepthBufFC;
    #endif

    uniform vec3 color1;
    uniform vec3 color2;
    varying vec3 vNormal;
    void main(void){
        vec3 view_nv  = normalize(vNormal);
        vec3 nv_color = view_nv * 0.5 + 0.5;
        vec3 c = mix(color1, color2, nv_color.r);
        gl_FragColor  = vec4(c, 1.0);
        
    #if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)
        gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;
    #endif
    }`,
    side: THREE.DoubleSide,
  });

    var geometry = new THREE.BoxGeometry( 1, 1, 1 );
    var mesh = new THREE.Mesh(geometry, material);

    scene.add(mesh);
  }

  function init() {
    container = document.getElementById('container');
    
    renderer = new THREE.WebGLRenderer({
      antialias: true,
      logarithmicDepthBuffer: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100);
    camera.position.set(0, 1, -2);

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    scene.add(camera);
    window.onresize = resize;

    orbitControls = new THREE.OrbitControls(camera, container);
    
    var helper = new THREE.GridHelper(100, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper(1000);
    scene.add(axis);

    createModel();
  }

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

  function animate() {
    requestAnimationFrame(animate);
    orbitControls.update();
    render();
  }

  function render() {
    renderer.render(scene, camera);
  }
  
  init();
  animate();
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>

Answer №2

Have you attempted to include that code in both of your shaders? From my perspective, it seems like it should be accurate.

The issue seems to stem from the shader failing to compile, as it references EPSILON in the vertex shader without declaring it beforehand.

You could try defining EPSILON within the shader itself, perhaps using a macro like this:

#define EPSILON 1e-6

Alternatively, you could pass it to the shader as a uniform variable. Please note that the value of EPSILON provided here is just an example; it would be wise to determine the appropriate value for EPSILON in your specific scenario.

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

Struggling to update a document fetched through a Mongoose model and handled as a promise

Check out update #2 for more detailed information I am encountering difficulties while trying to make a simple update to a document that has been retrieved by querying a container through a Mongoose model. The query using find has two populations, but oth ...

Unable to retrieve React state within the callback function

As I work with the following components: const ParentComponent: React.FC = () => { // Setting newType to some value within the code const [newType, setNewType] = useState<any>(undefined); // Enabling addEdge to true in another part o ...

"Return to the top" feature that seamlessly integrates with jQuery's pop-up functionality

Currently, I am facing an issue with a jQuery selectmenu list that opens as a popup due to its length. My goal is to add a "back to top" button at the end of the list. While researching online, I came across this tutorial which seems promising, but unfor ...

What is the best way to connect multiple web pages together?

Hello everyone, I could really use some assistance with a problem I'm facing. As a newcomer to web development, I have a question about navigation bars. I've successfully created a basic webpage with a navigation bar, but now I'm unsure how ...

such as in the post schema, the word "like" does not

like not removing from post model likeSchema .findOne({$and: [{post: postId ,user: userId}]}) .exec((err, result) =>{ if (result) { db.likeSchema .findOne( { $and ...

Guide to utilizing JSDoc within your local project

Objective My goal is to utilize jsdocs with npm in my project. Experience I am new to working with npm and its plugins. Recently, I came across jsdoc and attempted to incorporate it into my project without success. Attempted Solution Initially, I inst ...

Is the $scope object shared among all controllers in AngularJS when nested controllers are used?

Is it possible to use nested controllers in AngularJS? When using nested controllers, is the $scope object shared across all controllers? The issue at hand is:- While I can access the $scope values of the first controller across all controllers, I am una ...

Angular.js fails to load successfully every other time

My angular application is running into some issues with bower. At times, when I start up the server, I encounter the following error: Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to: Error: [$injector:modulerr] Failed to in ...

Slicknav is failing to appear on the screen, although it is being

After spending hours trying to implement a slicknav menu into my school project, I'm stuck and seeking guidance. Despite having some coding experience, I can't seem to find the solution to my problem. Any help, insight, or tips on fixing or impro ...

Having trouble sending data from the controller to the view in Laravel 8

I am struggling to display data retrieved from the database in my view through the controller. Despite trying various solutions found on similar questions, none of them seem to be effective. My main goal is to showcase a list of employees on my admin page. ...

"The presence of the $_GET URL parameter following the execution of the pushstate

Running a WordPress website and facing the challenge of updating the URL server-side without reloading the page. On my homepage, there is a button triggered by this code: <button onclick="javascript:window.history.pushState('test','&apo ...

Having trouble importing JS into HTML file with NodeJS

I have created a web server using NodeJS that serves the file index.html. However, when I attempt to add a JavaScript file to my HTML document, the browser displays an error message stating The resource "http://localhost:3000/includes/main.js" was blocked ...

Extract values from HTML IDs and store them in an array

Currently, I am working on a project where I need to capture a QR code and display it on the screen. After that, I want to iterate through the elements using a for loop and save the values in an array. Specifically, I am using the ID id="scanned-resul ...

Can someone explain the purpose of this code snippet: `const { foo = "bar" } = "baz"`?

I came across this code not too long ago and had trouble finding the answer online, so I'm turning to you for help. The specific code snippet is from a webpack configuration file: const { NODE_ENV = 'production', } = process.env; Appreci ...

The responses for several HTTP POST requests are not being received as expected

I am facing a challenge in retrieving a large number of HTTP POST requests' responses from the Database. When I try to fetch hundreds or even thousands of responses, I encounter issues with missing responses. However, when I test this process with onl ...

The angular application fails to load the page properly and keeps refreshing itself

I'm currently working on an Angular app that searches for a Github user based on their username and then displays the list of repositories. When a user clicks on a repo name, it should show the open issues and contributors associated with that reposit ...

Changes have been made to the Vue object, however, it does not trigger a re-render

Whenever I hit the right arrow key, it adjusts the object without re-rendering it : <div class="map"> <div class="map-page" tabindex="0" @keyup.arrow-keys="show" ref="mapPage"> <template v-for="mapRow in mapMatrix"> < ...

Updating a value within destructuring and a loop: A step-by-step guide

My Goal: I aim to modify a value in an object that is part of an array element. Take a look at the code snippet below for a clearer understanding. An issue arises when I update the object's value through reference instead of creating a new copy, cau ...

Passing a value to a component to delete a table row in ReactJS using Material UI

My task is to delete a specific table row after clicking. I have two components and have already written a function, handleDelete(), to remove a row from the table. The issue is that whenever I click, it always deletes the last row instead of the one I cli ...

What is the best way to empty the input field after a download event is completed in Node.JS?

For hours on end, I've been struggling with a persistent issue in my video downloader app. After successfully downloading a video, the input field where the URL is entered remains filled instead of clearing out. The screenshot below illustrates the p ...