纹理之上的 WebGL 纹理

WebGL texture on top of texture

我正在开展一个项目,将网络摄像头流整合到球形几何体中。由于我是着色器的新手并且想了解它是如何工作的,所以我想使用相对正常的尺寸将网络摄像头投影到球体中,在静态背景图像之上。

因此网络摄像头视频只需覆盖球体的一小部分,但背景图像必须覆盖整个球体。

目前我的网络摄像头图像如下所示: current situation

但我希望它看起来像这样: desired situation

我有以下顶点着色器:

            uniform mat4 projectionMat;
        uniform mat4 modelViewMat;
        attribute vec3 position;
        attribute vec2 texCoord;
        attribute vec2 texVideoCoord;
        varying vec2 vTexCoord;
        varying vec2 vTexVideoCoord;

        void main() {
          vTexCoord = texCoord;
          vTexVideoCoord = texVideoCoord;
          gl_Position = projectionMat * modelViewMat * vec4( position, 1.0 );
        }

以及当前绘制 "video" 网络摄像头流的以下片段着色器。

        precision mediump float;

        // Textures
        uniform sampler2D u_background;
        uniform sampler2D u_video;

        varying vec2 vTexCoord;
        varying vec2 vTexVideoCoord;

        void main() {
          vec4 background = texture2D(u_background, vTexCoord);
          vec4 video = texture2D(u_video, vTexVideoCoord);
          gl_FragColor = video;
        }

我的渲染函数设置如下:

    this.program.use();

    //setup attributes
    //setup uniforms
    context.gl.uniformMatrix4fv(this.program.uniform.projectionMat, false, projectionMat);
    context.gl.uniformMatrix4fv(this.program.uniform.modelViewMat, false, modelViewMat);

    context.gl.bindBuffer(context.gl.ARRAY_BUFFER, this.vertBuffer);
    context.gl.bindBuffer(context.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);

    context.gl.enableVertexAttribArray(this.program.attrib.position);
    context.gl.enableVertexAttribArray(this.program.attrib.texCoord);
    context.gl.enableVertexAttribArray(this.program.attrib.texVideoCoord);

    context.gl.vertexAttribPointer(this.program.attrib.position, 3, context.gl.FLOAT, false, 20, 0);
    context.gl.vertexAttribPointer(this.program.attrib.texCoord, 2, context.gl.FLOAT, false, 20, 12);
    context.gl.vertexAttribPointer(this.program.attrib.texVideoCoord, 2, context.gl.FLOAT, false, 20, 12);

    var u_backgroundLocation = context.gl.getUniformLocation(this.program.program, "u_background");
    var u_videoLocation = context.gl.getUniformLocation(this.program.program, "u_video");
    context.gl.uniform1i(u_backgroundLocation, 0);
    context.gl.uniform1i(u_videoLocation, 1);

    //activetexture/bind
    context.gl.activeTexture(context.gl.TEXTURE0);
    context.gl.bindTexture(context.gl.TEXTURE_2D, self.textureBackground);
    context.gl.texImage2D(context.gl.TEXTURE_2D, 0, context.gl.RGBA, context.gl.RGBA, context.gl.UNSIGNED_BYTE, self.canvasElement);
    context.gl.activeTexture(context.gl.TEXTURE1);
    context.gl.bindTexture(context.gl.TEXTURE_2D, self.textureVideo);
    context.gl.texImage2D(context.gl.TEXTURE_2D, 0, context.gl.RGBA, context.gl.RGBA, context.gl.UNSIGNED_BYTE, self.videoElement);

    //drawarrays/drawelements
    context.gl.drawElements(context.gl.TRIANGLES, this.indexCount, context.gl.UNSIGNED_SHORT, 0);

我不知道如何继续使网络摄像头显示为缩放比例和球体的一部分,而不是在其上拉伸。网络摄像头是一个 100 度的摄像头,应该放在球体内。

如果你的 UV 横跨整个球体,你可以将它整个用于背景图像采样,而将它的一小部分用于视频纹理采样。

vec2 vid_uv_start = vec2(0.2, 0.3);
vec2 vid_uv_end = vec2(0.6, 0.7);

uniform sampler2D u_background;
uniform sampler2D u_video;

varying vec2 vTexCoord;

void main()
{
    vec4 col = texture(u_background, vTexCoord);
    if((vTexCoord.x>=vid_uv_start.x && vTexCoord.x<=vid_uv_end.x)
        && (vTexCoord.y>=vid_uv_start.y && vTexCoord.y<=vid_uv_end.y))
    {
        vec2 adjustedUV = (vTexCoord-vid_uv_start)/(vid_uv_end-vid_uv_start);
        col = texture(u_video, adjustedUV);
    }
    gl_FragColor = col;
}

编辑:

这是可用的 shadertoy:https://www.shadertoy.com/view/MsdSWs

另一种方法是设置您的视频 UV 坐标,使 0<->1 范围代表您想要观看视频的区域

换句话说,背景的 UV 消失了

0,0       0.3    0.7    1.0
    +------+------+------+
    |      |      |      |
    |      |      |      |
    |      |      |      |
0.3 +------+------+------+
    |      |      |      |
    |      |      |      |
    |      |      |      |
0.7 +------+------+------+
    |      |      |      |
    |      |      |      |
    |      |      |      |
1.0 +------+------+------+

但是视频 UV 消失了

-1,-1      0      1      2
    +------+------+------+
    |      |      |      |
    |      |      |      |
    |      |      |      |
  0 +------+------+------+
    |      |......|      |
    |      |......|      |
    |      |......|      |
  1 +------+------+------+
    |      |      |      |
    |      |      |      |
    |      |      |      |
  2 +------+------+------+

这使得 ...... 部分成为 0 和 1 之间的部分

那么你的着色器就是

   precision mediump float;

    // Textures
    uniform sampler2D u_background;
    uniform sampler2D u_video;

    varying vec2 vTexCoord;
    varying vec2 vTexVideoCoord;

    void main() {
      vec4 background = texture2D(u_background, vTexCoord);
      vec4 video = texture2D(u_video, vTexVideoCoord);
      vec2 m = step(vec2(0), vTexVideoCoord) * step(vTexVideoCoord, vec2(1));
      gl_FragColor = mix(background, video, m.x * m.y);
    }