# Depth order lost with shader material in Volume Rendering

**URL:** <https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941>\
**Category:** Questions\
**Tags:** volume-rendering, materials, shaders\
**Created:** [March 22, 2025, 2:15pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941 "2025-03-22T14:15:40Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![gaussix](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gaussix/32/58020_2.png) [@gaussix](https://discourse.threejs.org/u/gaussix)\
**Post date:** [March 22, 2025, 2:15pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/1 "2025-03-22T14:15:40Z")

</div>

Hello everyone, I’m trying to implement a Volume Rendering using Medical Images (DICOM & NIFTI). I’m using a custom ShaderMaterial to execute the VR. All is OK, but when I add other objects l(ROIs) the order is lost. Have you any suggestion? Thanks in advance.

Here an example where I’ve just added a box to check that…

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/1/e15d28c5506954298289cfffed7b38f92c881dc6.jpeg)

Here is the right result with the Surface Rendering (withouth shaderMaterial)

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/8/48f5b17f8f25de573ed8063a15e6b813d6fab4fd.jpeg)

Here my pieces of code:  
this.\_renderer = new THREE.WebGLRenderer({  
canvas: this.canvas,  
antialias: true,  
logarithmicDepthBuffer: true,  
preserveDrawingBuffer: true,  
});

this.\_shaderMaterial = new THREE.ShaderMaterial({  
uniforms: currUniforms,  
vertexShader: vertex,  
fragmentShader: fragments,  
side: THREE.FrontSide,  
});

here my shading:  
vertex:  
//[three.js/src/renderers/shaders/ShaderChunk at dev · neeh/three.js · GitHub](https://github.com/neeh/three.js/tree/dev/src/renderers/shaders/ShaderChunk)  
export const vertex = `

#include   
#include \<logdepthbuf\_pars\_vertex\>  
struct Ray {  
vec3 origin;  
vec3 dir;  
};

out vec3 \_normal;  
out Ray vRay;  
out mat4 \_modelViewProjectionMatrix;  
uniform vec3 uVolScale;  
#include \<clipping\_planes\_pars\_vertex\>  
void main()  
{  
vec3 pos1 = position_uVolScale;  
\_modelViewProjectionMatrix = projectionMatrix \* modelViewMatrix;//projectionMatrix_(viewMatrix\*modelMatrix);  
gl\_Position = \_modelViewProjectionMatrix \* vec4(pos1, 1.0);  
vec3 eyePos = cameraPosition/uVolScale;  
vRay.dir = position-eyePos;  
vRay.origin = eyePos ;  
\_normal = vec3(normal);  
#include \<logdepthbuf\_vertex\>  
}`;

fragment:

void main()  
{  
#include \<logdepthbuf\_fragment\>  
Ray ray;  
ray.origin = vRay.origin;  
ray.dir = normalize(vRay.dir);  
vec2 bounds = computeNearFar(ray);  
if (bounds.x \> bounds.y) discard;  
bounds.x = max(bounds.x, 0.0);  
float near = bounds.x;  
float far = bounds.y;  
vec3 rayStart = ray.origin + near \* ray.dir;  
vec3 rayStop = ray.origin + far \* ray.dir;

```
  // Transform from object space to texture coordinate space:
  rayStart = 0.5 * (rayStart + 1.0);
  rayStop = 0.5 * (rayStop + 1.0);
  vec3 dir = rayStop - rayStart;
  float len = length(dir);
  dir = normalize(dir);
  vec3 deltaDir = dir * uStepSize;
  float offset = wang_hash(int(gl_FragCoord.x + 640.0 * gl_FragCoord.y));
  vec3 samplePos = rayStart + deltaDir * offset;

  vec4 acc = vec4(0.0);
  switch(uRenderStyle){
    case 0: acc = CalculateOpacityShadingModelNone(samplePos,deltaDir,len);break;
    case 1: acc = CalculateOpacityShadingModelIllustrative(samplePos, deltaDir, len, dir); break;
    case 2: acc = CalculateOpacityShadingModelMIP(samplePos, deltaDir, len, dir); break;
  }
  if (acc.a < 0.1)
    discard;
  if (acc.a < 1.0)
   acc.rgb = mix(uClearColor, acc.rgb, acc.a);
  gl_FragColor.rgba = acc;
}

```

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [March 23, 2025, 6:31pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/2 "2025-03-23T18:31:56Z")

</div>

As far as the GL layer is concerned.. the depth value is the depth of the primitive that contains your raymarching shader.  
(presumably a plane or cube)

You’re not doing anything in your raymarching code to also produce a depth value that is consistent with the sample you are outputting.

afaik, you will need to compute a depth value and output it via gl\_FragDepth, or manually generate a depth buffer in a separate pass.

---

<div class="post-metadata">

**Author:** ![Lawrence3DPK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lawrence3dpk/32/29184_2.png) [@Lawrence3DPK](https://discourse.threejs.org/u/Lawrence3DPK)\
**Post date:** [March 23, 2025, 8:31pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/3 "2025-03-23T20:31:33Z")

</div>

Have a look at the recently added `Data3DTexture` class, it could give some insights

> **[three.js webgpu - RenderTargetArray and RenderTarget3D](https://threejs.org/examples/webgpu_rendertarget_2d-array_3d)**

---

<div class="post-metadata">

**Author:** ![gaussix](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gaussix/32/58020_2.png) [@gaussix](https://discourse.threejs.org/u/gaussix)\
**Post date:** [March 26, 2025, 9:19pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/4 "2025-03-26T21:19:55Z")

</div>

Hi,  
many thanks for your replies.

@Lawrence3DPK I’m already using DataTexture3D to load the medical data. Thanks

@manthrax: you right, I forgot to post a piece of code where the fragDepth is calculated.  
I’m trying to do the same like [here](https://stackoverflow.com/questions/10264949/glsl-gl-fragcoord-z-calculation-and-setting-gl-fragdepth):

Here ist my complete code:  
Vertex:

```javascript
export const vertex = /*glsl*/ `
/**
Already defined in threejs
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
uniform vec3 normal;
uniform vec3 position;
uniform vec2 uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
 */
struct Ray {
  vec3 origin;
  vec3 dir;
};

out vec3 _normal;
out Ray vRay;
out mat4 _modelViewProjectionMatrix;

void main()
  {

    _modelViewProjectionMatrix = projectionMatrix * viewMatrix * modelMatrix;
    gl_Position = _modelViewProjectionMatrix * vec4(position, 1.0);
    vec3 eyePos = cameraPosition/uVolScale;
    vRay.dir = position-eyePos;
    vRay.origin = eyePos ;
    _normal = vec3(normal);
  }`;

```

Fragment:

```javascript
export const fragments = /* glsl */ `layout(location = 2) out float fragDepth;
    precision highp float;
    precision highp sampler3D;
    uniform float uOpacity;
    uniform sampler3D uVolume;
    uniform sampler2D uMapColor;

    struct Ray
    {
      vec3 origin;
      vec3 dir;
    };

    in Ray vRay;
    in vec3 _normal;

    in mat4 _modelViewProjectionMatrix;

    uniform float uStepSize, uSliceSize;
    uniform int uRenderStyle;
    vec2 computeNearFar(Ray ray);
    float getSample(vec3 modelPosition);
    float getSample(float x, float y, float z);
    vec4 GetColorByPosition(vec3 samplePosition);
    vec4 CalculateOpacityShadingModelNone(vec3 samplePos, vec3 delta, float len);
    vec4 CalculateOpacityShadingModelIllustrative(vec3 samplePos, vec3 delta, float len, vec3 dir);
    vec4 CalculateOpacityShadingModelMIP( vec3 samplePos, vec3 delta, float len, vec3 dir);
    vec4 apply_colormap(float val);
    vec3 GetNormal(vec3 loc, vec3 step);
    vec4 GetGradientNormal(vec3 P, vec3 Delta);

 
    float wang_hash(int seed)
    {
      seed = (seed ^ 61) ^ (seed >> 16);
      seed *= 9;
      seed = seed ^ (seed >> 4);
      seed *= 0x27d4eb2d;
      seed = seed ^ (seed >> 15);
      return float(seed % 2147483647) / float(2147483647);
    }
    void main()
    {
      Ray ray;
      ray.origin = vRay.origin;
      ray.dir = normalize(vRay.dir);
      vec2 bounds = computeNearFar(ray);
      if (bounds.x > bounds.y) discard;
      bounds.x = max(bounds.x, 0.0);
      float near = bounds.x;
      float far = bounds.y;
      vec3 rayStart = ray.origin + near * ray.dir;
      vec3 rayStop = ray.origin + far * ray.dir;

      // Transform from object space to texture coordinate space:
      rayStart = 0.5 * (rayStart + 1.0);
      rayStop = 0.5 * (rayStop + 1.0);
      vec3 dir = rayStop - rayStart;
      float len = length(dir);
      dir = normalize(dir);

      vec3 deltaDir = dir * uStepSize;
      float offset = wang_hash(int(gl_FragCoord.x + 640.0 * gl_FragCoord.y));
      vec3 samplePos = rayStart + deltaDir * offset;
      vec4 acc = vec4(0.0);
      float opCorr = uStepSize / uSliceSize;
      float stepSizex2 = 2.0 * uStepSize;
      vec4 acc, colorSample = vec4(0.0);
      float lenAcc = 0.0;
      while (lenAcc < len)
      {

        colorSample = GetColorByPosition(samplePos);
        colorSample.a = 1.0 - pow((1.0 - colorSample.a), opCorr);//opacity correction
        if (colorSample.a > 0.01 && lenAcc > stepSizex2)
        {
          colorSample.rgb *= colorSample.a;
          acc = (1.0 - acc.a) * colorSample + acc;
          if (acc.a >= 0.95)
          {
                  break;
          }
        }
        samplePos += delta;
        lenAcc += uStepSize;
      }

      if (acc.a < 0.1)
        discard;
      if (acc.a < 1.0)
       acc.rgb = mix(uClearColor, acc.rgb, acc.a);
     
       gl_FragColor.rgba = vec4(acc.rgb,uOpacity) ;// acc;

       //calculate fragDepth
      vec4 clipSpace = _modelViewProjectionMatrix*vec4(samplePos, 1.0);// gl_ProjectionMatrix * eye_space_pos;
      float ndc_depth = clipSpace.z/clipSpace.w;// clip_space_pos.z / clip_space_pos.w;
      fragDepth = 0.5 * ndc_depth + 0.5;

    }

```

Unfortunately it does not work. The same code works in a C# application.

I don’t understand the where is the problem..  
If you have a suggestion.

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [March 26, 2025, 11:30pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/5 "2025-03-26T23:30:37Z")

</div>

Shouldn’t

```javascript
      fragDepth = 0.5 * ndc_depth + 0.5;

```

be

```javascript
gl_FragDepth = 0.5 * ndc_depth + 0.5;

```

(I’m hazy on the semantics, but your setup may imply attempting to write depth to a separate target which isn’t what you want..)  
?

You’re welcome in advance. 😃

---

<div class="post-metadata">

**Author:** ![gaussix](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gaussix/32/58020_2.png) [@gaussix](https://discourse.threejs.org/u/gaussix)\
**Post date:** [April 6, 2025, 1:56pm UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/6 "2025-04-06T13:56:39Z")

</div>

fragDepth or gl\_FragDepth is not important. Simply, does not work. I can set also a random value it does not make any difference.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [April 7, 2025, 12:37am UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/7 "2025-04-07T00:37:14Z")

</div>

Sounds like a good time to make a minimal reproduction that shows the issue, in a jsfiddle / codepen and we can take a look.

---

<div class="post-metadata">

**Author:** ![gaussix](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gaussix/32/58020_2.png) [@gaussix](https://discourse.threejs.org/u/gaussix)\
**Post date:** [April 7, 2025, 6:31am UTC](https://discourse.threejs.org/t/depth-order-lost-with-shader-material-in-volume-rendering/79941/8 "2025-04-07T06:31:39Z")

</div>

I’ll do that as soon I have time.  
Thanks
