Scattering calculation in browser

· 2 min read · views.
Jul 1, 2023

This is an attempt to compute scattering field profiles in real time using shaders to take advantage of the computational power of the gpu. I will show here such a mission can perform in browser without the need for specific software. It should be noted that the approch I introduced here is not necessarily the best practice nor contains full details, but only a lively demo.

The total field can be express using Mie scattering theory as follows1: $$ H_z = H_0\sum_{m}\left[\mathrm{i}^m \mathrm{J}_m(kr) +\mathrm{i}^mS_m\mathrm{H}^{(1)}_m(kr)\right]\mathrm{e}^{\mathrm i m \varphi},\tag{1} $$ more information about this expression can be found here. So we can get full information if we already have knowledge of the scattering coefficient $\S_m$. Moreover, $S_m$ converges quickly for subwavelength cases, only the first few terms are needed.

The Hankel functions can be pre-prepared, and here I stored them as textures. A JPEG file can store three different real functions as it has three channel. Here is a example of a texture contains $\mathrm{Re}\left[\mathrm{H}^{(1)}_m(kr)\right]$ with $m$ takes values 0, 1 and 2.

Hankel functions of three different orders are combined in three channels to display a fantastic pattern.

The shader is shown as follows:

#include <common>
      uniform vec3 iResolution;
      uniform float iTime;
      uniform sampler2D iChannel0;
      uniform sampler2D iChannel1;
      uniform sampler2D iChannel2;
      uniform sampler2D iChannel3;
      uniform sampler2D iChannel4;
      #define TILES 320
      #define M_PI 3.1415926535897932384626433832795
      void mainImage( out vec4 fragColor, in vec2 fragCoord )
      {
        vec2 uv = fragCoord.xy / iResolution.xy;
    
        vec4 re012 = texture2D(iChannel0, floor(uv * float(TILES)) / float(TILES))-0.5;
        vec4 im012 = texture2D(iChannel1, floor(uv * float(TILES)) / float(TILES))-0.5;
        vec4 re345 = texture2D(iChannel2, floor(uv * float(TILES)) / float(TILES))-0.5;
        vec4 im345 = texture2D(iChannel3, floor(uv * float(TILES)) / float(TILES))-0.5;
        float p = texture2D(iChannel4, floor(uv.yx * float(TILES)) / float(TILES)).r*2.*M_PI+M_PI*0.5;
        float t2 =5.0*iTime;
        float r = 2.*im012.g*sin(p)+2.*im345.r*sin(3.*p)+2.*im345.b*sin(5.*p);
        float i = 2.*re012.g*sin(p)+2.*re345.r*sin(3.*p)+2.*re345.b*sin(5.*p);
        float value = (-cos(t2-uv.x*320.0*0.35)-r*cos(t2)+i*sin(t2))*0.3;
        fragColor = vec4(clamp(value,0.,1.),0.0,clamp(-value,0.,1.),1.0);
      }

And then ShaderMaterial can use the custom shader as material.

const material = new THREE.ShaderMaterial( {
            shader,
            uniforms,
        } );
scene.add( new THREE.Mesh( plane, material ) );

See reference :

https://threejs.org/docs/#api/en/materials/ShaderMaterial;


  1. Ye, X., Wang, Y., Yao, J., Yuan, C., Zhou, Z., Astafiev, A. M., & Kudryavtsev, A. A. (2022). Radiation pattern in a tunable plasma window antenna. Journal of Physics D: Applied Physics, 55(34), 345201.https://doi.org/10.1088/1361-6463/ac7364 ↩︎