diff --git a/src/materials/SpotLightMaterial.tsx b/src/materials/SpotLightMaterial.tsx
index e97f02105..53615df77 100644
--- a/src/materials/SpotLightMaterial.tsx
+++ b/src/materials/SpotLightMaterial.tsx
@@ -18,70 +18,78 @@ export class SpotLightMaterial extends THREE.ShaderMaterial {
       transparent: true,
       depthWrite: false,
       vertexShader: /* glsl */ `
-      varying vec3 vNormal;
-      varying vec3 vWorldPosition;
-      varying float vViewZ;
-      varying float vIntensity;
-      uniform vec3 spotPosition;
-      uniform float attenuation;      
-
-      void main() {
-        // compute intensity
-        vNormal = normalize( normalMatrix * normal );
-        vec4 worldPosition	= modelMatrix * vec4( position, 1.0 );
-        vWorldPosition = worldPosition.xyz;
-        vec4 viewPosition = viewMatrix * worldPosition;
-        vViewZ = viewPosition.z;
-        float intensity	= distance(worldPosition.xyz, spotPosition) / attenuation;
-        intensity	= 1.0 - clamp(intensity, 0.0, 1.0);
-        vIntensity = intensity;        
-        // set gl_Position
-        gl_Position	= projectionMatrix * viewPosition;
-
-      }`,
-      fragmentShader: /* glsl */ `
-      #include <packing>
-
-      varying vec3 vNormal;
-      varying vec3 vWorldPosition;
-      uniform vec3 lightColor;
-      uniform vec3 spotPosition;
-      uniform float attenuation;
-      uniform float anglePower;
-      uniform sampler2D depth;
-      uniform vec2 resolution;
-      uniform float cameraNear;
-      uniform float cameraFar;
-      varying float vViewZ;
-      varying float vIntensity;
-      uniform float opacity;
-
-      float readDepth( sampler2D depthSampler, vec2 coord ) {
-        float fragCoordZ = texture2D( depthSampler, coord ).x;
-        float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar);
-        return viewZ;
-      }
-
-      void main() {
-        float d = 1.0;
-        bool isSoft = resolution[0] > 0.0 && resolution[1] > 0.0;
-        if (isSoft) {
-          vec2 sUv = gl_FragCoord.xy / resolution;
-          d = readDepth(depth, sUv);
+        varying vec3 vNormal;
+        varying float vViewZ;
+        varying float vIntensity;
+        uniform vec3 spotPosition;
+        uniform float attenuation;
+
+        #include <common>
+        #include <logdepthbuf_pars_vertex>
+
+        void main() {
+          // compute intensity
+          vNormal = normalize(normalMatrix * normal);
+          vec4 worldPosition = modelMatrix * vec4(position, 1);
+          vec4 viewPosition = viewMatrix * worldPosition;
+          vViewZ = viewPosition.z;
+
+          vIntensity = 1.0 - saturate(distance(worldPosition.xyz, spotPosition) / attenuation);
+
+          gl_Position = projectionMatrix * viewPosition;
+
+          #include <logdepthbuf_vertex>
         }
-        float intensity = vIntensity;
-        vec3 normal	= vec3(vNormal.x, vNormal.y, abs(vNormal.z));
-        float angleIntensity	= pow( dot(normal, vec3(0.0, 0.0, 1.0)), anglePower );
-        intensity	*= angleIntensity;
-        // fades when z is close to sampled depth, meaning the cone is intersecting existing geometry
-        if (isSoft) {
-          intensity	*= smoothstep(0., 1., vViewZ - d);
+      `,
+      fragmentShader: /* glsl */ `
+        varying vec3 vNormal;
+        varying float vViewZ;
+        varying float vIntensity;
+
+        uniform vec3 lightColor;
+        uniform float anglePower;
+        uniform sampler2D depth;
+        uniform vec2 resolution;
+        uniform float cameraNear;
+        uniform float cameraFar;
+        uniform float opacity;
+
+        #include <packing>
+        #include <logdepthbuf_pars_fragment>
+
+        float readDepth(sampler2D depthSampler, vec2 uv) {
+          float fragCoordZ = texture(depthSampler, uv).r;
+
+          // https://github.com/mrdoob/three.js/issues/23072
+          #ifdef USE_LOGDEPTHBUF
+            float viewZ = 1.0 - exp2(fragCoordZ * log(cameraFar + 1.0) / log(2.0));
+          #else
+            float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar);
+          #endif
+
+          return viewZ;
         }
-        gl_FragColor = vec4(lightColor, intensity * opacity);
 
-        #include <tonemapping_fragment>
-	      #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
-      }`,
+        void main() {
+          #include <logdepthbuf_fragment>
+
+          vec3 normal = vec3(vNormal.x, vNormal.y, abs(vNormal.z));
+          float angleIntensity = pow(dot(normal, vec3(0, 0, 1)), anglePower);
+          float intensity = vIntensity * angleIntensity;
+
+          // fades when z is close to sampled depth, meaning the cone is intersecting existing geometry
+          bool isSoft = resolution[0] > 0.0 && resolution[1] > 0.0;
+          if (isSoft) {
+            vec2 uv = gl_FragCoord.xy / resolution;
+            intensity *= smoothstep(0.0, 1.0, vViewZ - readDepth(depth, uv));
+          }
+
+          gl_FragColor = vec4(lightColor, intensity * opacity);
+
+          #include <tonemapping_fragment>
+          #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
+        }
+      `,
     })
   }
 }