使用 OGL Flowmap 效果为此 WebGL 设置透明背景?

Setting transparent background to this WebGL with OGL Flowmap effect?

我正在尝试从 OGL examples 创建 Flowmap 效果,但使用部分透明的 PNG 图像。我在这个问题上苦苦挣扎了好几个小时,我什至不知道是纹理的错误、流图效果还是其他任何事情。如何将背景设置为透明而不是黑色?

渲染方式canvas看起来

  const vertex = /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = vec4(position, 0, 1);
}
`
  const fragment = /* glsl */ `
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform sampler2D tFlow;
uniform float uTime;
varying vec2 vUv;
uniform vec4 res;

void main() {

    // R and G values are velocity in the x and y direction
    // B value is the velocity length
    vec3 flow = texture2D(tFlow, vUv).rgb;
    // Use flow to adjust the uv lookup of a texture
    vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
    uv += flow.xy * 0.05;
    vec3 tex = texture2D(texture, uv).rgb;
    gl_FragColor.rgb = tex;
    gl_FragColor.a = 1.0;

}
`
  {
    const renderer = new Renderer({
      dpr: 2,
      alpha: true,
      premultiplyAlpha: false,
    })
    const gl = renderer.gl
    const canvas = document.body.appendChild(gl.canvas)
    gl.clearColor(1, 1, 1, 1)

    // Variable inputs to control flowmap
    let aspect = 1
    const mouse = new Vec2(-1)
    const velocity = new Vec2()
    let imgSize = [600, 600]

    const flowmap = new Flowmap(gl, { falloff: 0.2, dissipation: 0.9 })
    // Triangle that includes -1 to 1 range for 'position', and 0 to 1 range for 'uv'.
    const geometry = new Geometry(gl, {
      position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
      uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
    })
    const texture = new Texture(gl, {
      minFilter: gl.LINEAR,
      magFilter: gl.LINEAR,
      premultiplyAlpha: true,
    })
    const img = new Image()
    img.onload = () => (texture.image = img)

    img.src = "/static/sowa@2x-863f69426831e1cc05d417dc45111419.png"
    let a1, a2
    var imageAspect = imgSize[1] / imgSize[0]
    if (imgSize[1] / imgSize[0] < imageAspect) {
      a1 = 1
      a2 = imgSize[1] / imgSize[0] / imageAspect
    } else {
      a1 = (imgSize[0] / imgSize[1]) * imageAspect
      a2 = 1
    }
    const program = new Program(gl, {
      vertex,
      fragment,
      uniforms: {
        uTime: { value: 0 },
        texture: { value: texture },
        res: {
          value: new Vec4(imgSize[0], imgSize[1], a1, a2),
        },
        // Note that the uniform is applied without using an object and value property
        // This is because the class alternates this texture between two render targets
        // and updates the value property after each render.
        tFlow: flowmap.uniform,
      },
    })

    const mesh = new Mesh(gl, { geometry, program })
    // Create handlers to get mouse position and velocity
    const isTouchCapable = "ontouchstart" in window
    if (isTouchCapable) {
      window.addEventListener("touchstart", updateMouse, false)
      window.addEventListener("touchmove", updateMouse, false)
    } else {
      window.addEventListener("mousemove", updateMouse, false)
    }
    let lastTime
    const lastMouse = new Vec2()

    function resize() {
      renderer.setSize(imgSize[0], imgSize[1])
      aspect = imgSize[0] / imgSize[1]
    }
    window.addEventListener("resize", resize, false)
    resize()

    function updateMouse(e) {
      if (e.changedTouches && e.changedTouches.length) {
        e.x = e.changedTouches[0].pageX
        e.y = e.changedTouches[0].pageY
      }
      const positionX = e.x - canvas.getBoundingClientRect().x
      const positionY = e.y - canvas.getBoundingClientRect().y
      // Get mouse value in 0 to 1 range, with y flipped
      mouse.set(
        positionX / gl.renderer.width,
        1.0 - positionY / gl.renderer.height
      )
      // Calculate velocity
      if (!lastTime) {
        // First frame
        lastTime = performance.now()
        lastMouse.set(positionX, positionY)
      }

      const deltaX = positionX - lastMouse.x
      const deltaY = positionY - lastMouse.y

      lastMouse.set(positionX, positionY)

      let time = performance.now()

      // Avoid dividing by 0
      let delta = Math.max(14, time - lastTime)
      lastTime = time
      velocity.x = deltaX / delta
      velocity.y = deltaY / delta
      // Flag update to prevent hanging velocity values when not moving
      velocity.needsUpdate = true
    }
    requestAnimationFrame(update)
    function update(t) {
      requestAnimationFrame(update)
      // Reset velocity when mouse not moving
      if (!velocity.needsUpdate) {
        mouse.set(-1)
        velocity.set(0)
      }
      velocity.needsUpdate = false
      // Update flowmap inputs
      flowmap.aspect = aspect
      flowmap.mouse.copy(mouse)
      // Ease velocity input, slower when fading out
      flowmap.velocity.lerp(velocity, velocity.len ? 0.5 : 0.1)
      flowmap.update()
      program.uniforms.uTime.value = t * 0.01
      renderer.render({ scene: mesh })
    }
  }

我应该在哪里寻找答案?这是 OGL 内部的东西吗?

您需要进行两项更改。

  1. 在您的程序声明中,您需要添加 transparent: true
  2. 在片段着色器中,将输出更改为 gl_FragColor = texture2D(texture, uv);

第一个更改是将混合类型更改为使用 alpha - 默认情况下在 WebGL 中禁用混合。

第二个使用纹理的 alpha 通道。在原始示例中,仅使用 rgb(红色、绿色、蓝色)通道。