ThreeJS Shader的效果樣例雷達圖和大氣層(二)

火星写程序發表於2024-08-24

一、雷達圖

實現原理:圖中是一個旋轉的漸變扇形,可以透過先實現一個扇形、然後再實現一個漸變扇形,最後再將扇形旋轉來達到最終效果

1. 實現一個夾角為O的扇形,已X軸正方向為單位向量M,UV點到(0,0)形成向量N,透過M和N的點乘就可以得到一個夾角,然後判斷角度小於O就可以了

2. 實現扇形的漸變色,主要是透過smoothstep實現,smoothstep是在兩個值之間取漸變值,這樣就可以實現離X軸越遠越暗的效果

3. 如何讓扇形旋轉起來呢,上面已經實現了一個扇形A,透過將扇形B按照一定角度旋轉到A,就可以得到對應的漸變色顏色值了,這樣一個漸變的旋轉角度就可以實現一個旋轉的漸變扇形

4. 實現藍色線圈,也是透過smoothstep函式,一個smoothstep最後會生成0-1的跳變值,如果是兩個smoothstep相減會生成一個波峰的顏色值

主要原理是先實現一個扇形漸變的區域,這個不是很複雜,然後透過不斷渲染頁面時,將該扇形旋轉到某個角度即可

const vertex = '\
    varying vec2 vUv;\
    void main() {\
      vUv = uv;\
      vec4 modelPosition = modelMatrix * vec4(position, 1.0);\
      gl_Position = projectionMatrix * viewMatrix * modelPosition;\
    }\
  ';

  const frag = '\
    uniform float uTime;\
    varying vec2 vUv;\
    float drawCircle(vec2 vUv, float radius) {\
      float res = length(vUv);\
      float width = 0.005;\
      return smoothstep(radius - width, radius, res) - smoothstep(radius, radius + width, res);\
    }\
    float drawSector(vec2 vUv, float radius) {\
      float angle = uTime;\
      vec2 newvUv = mat2(cos(angle), sin(angle), -sin(angle), cos(angle)) * vUv;\
      vec2 x = vec2(1.0, 0.0);\
      vec2 y = vec2(0.0, 1.0);\
      float res = dot(newvUv, y);\
      float angle2 = acos(dot(x, normalize(newvUv)));\
      if (angle2 > 0.0 && angle2 < 1.5707 && length(newvUv) < 0.45 && res > 0.0) {\
        return 1.0 - smoothstep(0.0, 1.5707, angle2);\
      } else {\
        return 0.0;\
      }\
    }\
    void main() {\
      vec2 newvUv = vUv;\
      newvUv -= vec2(0.5);\
      vec3 color = vec3(0.0, 0.0, 0.0);\
      float circle = drawCircle(newvUv, 0.45);\
      float circle2 = drawCircle(newvUv, 0.3);\
      float circle3 = drawCircle(newvUv, 0.1);\
      color += circle + circle2 + circle3;\
      color += drawSector(newvUv, 0.45);\
      gl_FragColor = vec4(color * vec3(0.0, 1.0, 0.0), 1.0);\
    }\
  ';

三、遮罩層

1. 第一種方法:採用shader中法向量的概念,取法向量和球體上各個座標點與相機形成的向量之間的點積,離相機位置越近,

  越靠近相機位置,點積值越大,且為正值,反之越遠,則點積越小,同時可能為負值,這時候用產生的點積資料作為透明度,

  即可得到漸變的效果

var vertex    =
    'varying vec3    vVertexWorldPosition;\
    varying vec3    vVertexNormal;\
    varying vec4    vFragColor;\
    void main(){\
        vVertexNormal    = normalize(normalMatrix * normal);\
        vVertexWorldPosition    = (modelMatrix * vec4(position, 1.0)).xyz;\
        gl_Position    = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\
    }';

  var frag    =
    'uniform vec3    glowColor;\
    uniform float    coeficient;\
    varying vec3    vVertexNormal;\
    varying vec3    vVertexWorldPosition;\
    varying vec4    vFragColor;\
    void main(){\
            vec3 worldVertexToCamera = cameraPosition - vVertexWorldPosition;\
            vec3 viewCameraToVertex    = (viewMatrix * vec4(worldVertexToCamera, 0.0)).xyz;\
            viewCameraToVertex = normalize(viewCameraToVertex);\
            float intensity = coeficient + dot(vVertexNormal, viewCameraToVertex);\
            if (intensity < 0.0) {\
              gl_FragColor = vec4(vec3(0.0, 1.0, 0.0), 1.0);\
            } else {\
              gl_FragColor = vec4(glowColor, intensity);\
            }\
    }';

2. 第二種方法透過ThreeJS官方提供的樣例,使用EffectCompose的方式來實現,其中也是透過新增shader著色器的原理實現的

相關文章