在纹理顶部的WebGL纹理

时间:2016-05-03 11:59:50

标签: javascript glsl webgl

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

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

目前我的网络摄像头图像如下所示: 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 );
        }

以下片段着色器,目前正在绘制“视频”,即网络摄像头流。

        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度摄像头,应该在球体内部定位。

2 个答案:

答案 0 :(得分:0)

如果您的紫外线穿过球体,您可以将其整体用于背景图像采样,并将其用于采样视频纹理的较小部分。

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;
}

编辑:

这是工作的shartrtoy:https://www.shadertoy.com/view/MsdSWs

答案 1 :(得分:0)

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

换句话说,背景的紫外线

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

但视频紫外线

-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);
    }