2015-04-18 75 views
0

我正在爲我的項目構建多通道渲染器。事情是,我甚至不能顯示一張照片。我用WebGL Inspector查看,但一切似乎都很好(我檢查了一個更簡單的版本,我知道它正在工作,而且一切看起來都差不多)。無法用着色器顯示圖片


[編輯]這裏是一個minimal codepen。我只提取了WebGL調用,因爲其餘代碼超出了範圍。我將其留在下面以供參考。


這裏是codepen,則debug codepen,以供參考源代碼(儘管它的規模,它實際上並沒有做很多的工作):

class Shader { 

    constructor({ fragment, vertex, INPUT_SOURCES = 1 }) { 

     this.INPUT_SOURCES = INPUT_SOURCES; 

     this.fragment = fragment; 
     this.vertex = vertex; 

    } 

    getResolution(previous) { 

     return previous; 

    } 

    buildProgram(context) { 

     let fragmentPrefix = ` 
      #define uInputSample uInputSample_Prev0 
      #define uInputResolution uInputResolution_Prev0 
     `; 

     let vertexPrefix = ` 
      #define uInputSample uInputSample_Prev0 
      #define uInputResolution uInputResolution_Prev0 
     `; 

     let fragment = context.createShader(context.gl.FRAGMENT_SHADER, fragmentPrefix + this.fragment); 
     let vertex = context.createShader(context.gl.VERTEX_SHADER, vertexPrefix + this.vertex); 

     return context.createProgram(fragment, vertex); 

    } 

} 

class RenderOutput { 

    constructor() { 

     this.resolution = { width : 0, height : 0 }; 

     this.framebuffer = null; 
     this.texture = null; 

    } 

} 

class RenderPass { 

    constructor({ }) { 

     this.previous = null; 
     this.next = null; 

    } 

    static link(from, to) { 

     if (to.previous) 
      to.remove(); 

     if (from.next) 
      from.next.remove(); 

     from.next = to; 
     to.previous = from; 

     from.refreshOutput(); 

    } 

    static unlink(element) { 

     if (! element.previous) 
      return ; 

     let previous = element.previous; 

     element.previous = null; 
     previous.next = null; 

     element.refreshInputs(); 
     previous.refreshOutput(); 

    } 

    append(element) { 

     RenderPass.link(this, element); 

    } 

    remove() { 

     RenderPass.unlink(this); 

    } 

} 

class RenderPassShader extends RenderPass { 

    constructor({ context, shader }, previous = null) { 

     super(); 

     this.context = context; 

     this.shader = shader; 
     this.program = shader.buildProgram(this.context); 

     this.uInputSampleLocations = [ ]; 
     this.uInputResolutionLocations = [ ]; 

     this.inputs = null; 
     this.output = new RenderOutput(); 

     this.resolution = null; 

     // -- switch on uniforms 

     this.context.gl.useProgram(this.program); 

     // -- locate uniforms 

     this.uOutputResolutionLocation = this.context.gl.getUniformLocation(this.program, 'uOutputResolution'); 
     this.uScreenResolutionLocation = this.context.gl.getUniformLocation(this.program, 'uScreenResolution'); 

     for (let t = 0, T = this.shader.INPUT_SOURCES; t < T; ++ t) { 
     this.uInputSampleLocations.push(this.context.gl.getUniformLocation(this.program, `uInputSample_Prev${t}`)); 
     this.uInputResolutionLocations.push(this.context.gl.getUniformLocation(this.program, `uInputResolution_Prev${t}`)); 
     } 

     // -- locate attributes 

     this.aVertexPositionLocation = this.context.gl.getAttribLocation(this.program, 'aVertexPosition'); 
     this.aVertexTextureUvLocation = this.context.gl.getAttribLocation(this.program, 'aVertexTextureUv'); 

     this.context.gl.bindBuffer(this.context.vertexPositionBuffer.bufferTarget, this.context.vertexPositionBuffer); 
     this.context.gl.vertexAttribPointer(this.aVertexPositionLocation, this.context.vertexPositionBuffer.itemSize, this.context.gl.FLOAT, false, 0, 0); 
     this.context.gl.bindBuffer(this.context.vertexPositionBuffer.bufferTarget, null); 

     this.context.gl.bindBuffer(this.context.vertexTextureUvBuffer.bufferTarget, this.context.vertexTextureUvBuffer); 
     this.context.gl.vertexAttribPointer(this.aVertexTextureUvLocation, this.context.vertexTextureUvBuffer.itemSize, this.context.gl.FLOAT, false, 0, 0); 
     this.context.gl.bindBuffer(this.context.vertexTextureUvBuffer.bufferTarget, null); 

     // -- switch off shader 

     this.context.gl.useProgram(null); 

     // -- initialize 

     this.refreshInputs(); 

     // -- attach 

     previous && previous.append(this); 

    } 

    refreshOutput() { 

     if (this.next && ! this.output.texture) { 

      let { width, height } = this.output.resolution; 

      this.output.framebuffer = this.context.createFramebuffer(); 
      this.output.texture = this.context.createTexture(); 

      this.context.setTextureSize(this.output.texture, width, height); 

      this.context.gl.bindFramebuffer(this.context.gl.FRAMEBUFFER, this.output.framebuffer); 
      this.context.gl.framebufferTexture2D(this.context.gl.FRAMEBUFFER, this.context.gl.COLOR_ATTACHMENT0, this.context.gl.TEXTURE_2D, this.output.texture, 0); 
      this.context.gl.bindFramebuffer(this.context.gl.FRAMEBUFFER, null); 

      this.next.refreshInputs(); 

     } else if (! this.next && this.output.texture) { 

      this.context.deleteFramebuffer(this.output.framebuffer); 
      this.context.deleteTexture(this.output.texture); 

      this.output.framebuffer = null; 
      this.output.texture = null; 

     } 

    } 

    refreshInputs() { 

     this.context.useProgram(this.program, () => { 

      this.inputs = this.previous ? this.previous.getOutputs() : [ ]; 
      this.valid = this.shader.INPUT_SOURCES <= this.inputs.length; 

      let { width, height } = this.getResolution(); 
      this.output.resolution = { width, height }; 

      if (this.output.texture) 
       this.context.setTextureSize(this.output.texture, width, height); 

      for (let t = 0, T = Math.min(this.inputs.length, this.shader.INPUT_SOURCES); t < T; ++ t) { 
      this.context.gl.uniform1i(this.uInputSampleLocations[ t ], this.inputs[ t ].texture); 
      this.context.gl.uniform2f(this.uInputResolutionLocations[ t ], this.inputs[ t ].resolution.width, this.inputs[ t ].resolution.height); 
      } 

     }); 

     if (this.next) { 
      this.next.refreshInputs(); 
     } 

    } 

    getResolution() { 

     return this.shader.getResolution(this); 

    } 

    getOutputs() { 

     let previous = this.previous ? this.previous.getOutputs() : [ ]; 

     return [ this.output ].concat(previous); 

    } 

    render() { 

     if (! this.valid) 
      throw new Error('Invalid pass'); 

     this.context.gl.useProgram(this.program); 
     this.context.gl.viewport(0, 0, this.output.resolution.width, this.output.resolution.height); 

     this.context.gl.bindFramebuffer(this.context.gl.FRAMEBUFFER, this.output.framebuffer); 
     this.context.gl.clear(this.context.gl.COLOR_BUFFER_BIT); 

     this.context.gl.bindBuffer(this.context.vertexIndexBuffer.bufferTarget, this.context.vertexIndexBuffer); 
     this.context.gl.drawElements(this.context.gl.TRIANGLE_STRIP, this.context.vertexIndexBuffer.itemCount, this.context.gl.UNSIGNED_SHORT, 0); 

     this.next && this.next.render(); 

    } 

} 

RenderPass.EntryPoint = class extends RenderPass { 

    constructor({ context }) { 

     super(); 

     this.context = context; 

     this.output = new RenderOutput(); 
     this.output.texture = this.context.createTexture(); 

     this.setInputSize(0, 0); 

    } 

    setInputSize(width, height) { 

     this.output.resolution.width = width; 
     this.output.resolution.height = height; 

     this.context.setTextureSize(this.output.texture, this.output.resolution.width, this.output.resolution.height); 

     this.next && this.next.refreshInputs(); 

    } 

    setInputData(data) { 

     let format = this.context.gl.RGBA; 
     let type = this.context.gl.UNSIGNED_BYTE; 

     this.context.gl.bindTexture(this.context.gl.TEXTURE_2D, this.output.texture); 
     this.context.gl.texImage2D(this.context.gl.TEXTURE_2D, 0, this.context.gl.RGBA, this.output.resolution.width, this.output.resolution.height, 0, format, type, data); 
     this.context.gl.bindTexture(this.context.gl.TEXTURE_2D, null); 

    } 

    refreshOutput() { 

     this.next && this.next.refreshInputs(); 

    } 

    getOutputs() { 

     return [ this.output ]; 

    } 

    render() { 

     this.next && this.next.render(); 

    } 

}; 

RenderPass.StandardOutput = class extends RenderPassShader { 

    constructor({ context }, parent) { 

     super({ context, shader : new Shader({ 

      fragment : ` 

       precision mediump float; 

       uniform sampler2D uInputSample; 

       varying vec2 vTextureCoordinates; 

       void main(void) { 
        gl_FragColor = texture2D(uInputSample, vTextureCoordinates); 
       } 

      `, 

      vertex : ` 

       precision mediump float; 

       uniform mat4 uMatrix; 

       attribute vec3 aVertexPosition; 
       attribute vec2 aVertexTextureUv; 

       varying vec2 vTextureCoordinates; 

       void main(void) { 
        vTextureCoordinates = vec2(aVertexTextureUv.s, 1.0 - aVertexTextureUv.t); 
        gl_Position = uMatrix * vec4(aVertexPosition, 1.0); 
       } 

      ` 

     }) }, parent); 

     this.outputWidth = 0; 
     this.outputHeight = 0; 

    } 

    setOutputSize(width, height) { 

     this.outputWidth = width; 
     this.outputHeight = height; 

     this.refreshInputs(); 

    } 

    refreshInputs() { 

     super.refreshInputs(); 

     this.context.useProgram(this.program, () => { 

      var inputWidth = this.inputs.length > 0 ? this.inputs[ 0 ].resolution.width : 0; 
      var inputHeight = this.inputs.length > 0 ? this.inputs[ 0 ].resolution.height : 0; 

      var outputWidth = this.output.resolution.width; 
      var outputHeight = this.output.resolution.height; 

      var isUndefined = value => value == null || value === ''; 

      if (isUndefined(outputWidth) && isUndefined(outputHeight)) 
       outputWidth = inputWidth, outputHeight = inputHeight; 

      if (isUndefined(outputWidth)) 
       outputWidth = inputWidth * (outputHeight/inputHeight); 

      if (isUndefined(outputHeight)) 
       outputHeight = inputHeight * (outputWidth/inputWidth); 

      var widthRatio = outputWidth/inputWidth; 
      var heightRatio = outputHeight/inputHeight; 

      var ratio = Math.min(widthRatio, heightRatio); 

      var viewportWidth = widthRatio/ratio; 
      var viewportHeight = heightRatio/ratio; 

      var matrix = this._createOrthoMatrix(- viewportWidth, viewportWidth, - viewportHeight, viewportHeight, - 100, 100); 
      this.context.gl.uniformMatrix4fv(this.context.gl.getUniformLocation(this.program, 'uMatrix'), false, matrix); 

     }); 

    } 

    getResolution() { 

     return { width : this.outputWidth, height : this.outputHeight }; 

    } 

    _createOrthoMatrix(left, right, bottom, top, near, far) { 

     var lr = 1/(left - right), bt = 1/(bottom - top), nf = 1/(near - far); 

     return [ - 2 * lr, 0, 0, 0, 0, - 2 * bt, 0, 0, 0, 0, 2 * nf, 0, (left + right) * lr, (bottom + top) * bt, (near + far) * nf, 1 ]; 

    } 

}; 

class RenderContext { 

    constructor({ gl }) { 

     this.gl = gl; 

     this.vertexPositionBuffer = this.createBuffer(this.gl.ARRAY_BUFFER, 4, new Float32Array([ -1, -1, 0, /**/ 1, -1, 0, /**/ 1, 1, 0, /**/ -1, 1, 0 ])); 
     this.vertexTextureUvBuffer = this.createBuffer(this.gl.ARRAY_BUFFER, 4, new Float32Array([ 0, 0, /**/ 1, 0, /**/ 1, 1, /**/ 0, 1 ])); 
     this.vertexIndexBuffer = this.createBuffer(this.gl.ELEMENT_ARRAY_BUFFER, 4, new Uint16Array([ 0, 1, 3, 2 ])); 

    } 

    createBuffer(target, count, content) { 

     var buffer = this.gl.createBuffer(); 

     buffer.bufferTarget = target; 
     buffer.itemCount = count; 
     buffer.itemSize = content.length/count; 

     this.gl.bindBuffer(buffer.bufferTarget, buffer); 
     this.gl.bufferData(buffer.bufferTarget, content, this.gl.STATIC_DRAW); 
     this.gl.bindBuffer(buffer.bufferTarget, null); 

     return buffer; 

    } 

    createShader(type, script) { 

     let shader = this.gl.createShader(type); 

     this.gl.shaderSource(shader, script); 
     this.gl.compileShader(shader); 

     if (! this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) 
      throw new Error(`Shader compilation failed: ${this.gl.getShaderInfoLog(shader)}`); 

     return shader; 

    } 

    createProgram(fragment, vertex) { 

     let program = this.gl.createProgram(); 

     this.gl.attachShader(program, vertex); 
     this.gl.attachShader(program, fragment); 

     this.gl.linkProgram(program); 

     if (! this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) 
      throw new Error(`Shader linking failed: ${this.gl.getError()}`); 

     return program; 

    } 

    createFramebuffer() { 

     let framebuffer = this.gl.createFramebuffer(); 

     return framebuffer; 

    } 

    createTexture() { 

     let texture = this.gl.createTexture(); 

     this.gl.bindTexture(this.gl.TEXTURE_2D, texture); 
     this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); 
     this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); 
     this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); 
     this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); 
     this.gl.bindTexture(this.gl.TEXTURE_2D, null); 

     return texture; 

    } 

    setTextureSize(texture, width, height) { 

     this.gl.bindTexture(this.gl.TEXTURE_2D, texture); 
     this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null); 
     this.gl.bindTexture(this.gl.TEXTURE_2D, null); 

    } 

    useProgram(program, callback) { 

     this.gl.useProgram(program); 
     callback(); 
     this.gl.useProgram(null); 

    } 

} 

function getPixelData(image) { 

    let canvas = document.createElement('canvas'); 
    let context = canvas.getContext('2d'); 

    canvas.width = image.width; 
    canvas.height = image.height; 
    context.drawImage(image, 0, 0); 

    let canvasData = context.getImageData(0, 0, canvas.width, canvas.height).data; 
    let pixelData = new Uint8Array(canvasData.length); 

    for (let t = 0; t < pixelData.length; ++ t) 
     pixelData[ t ] = canvasData[ t ]; 

    return pixelData; 

} 

(function () { 

    let image = new Image(); 
    image.crossOrigin = 'anonymous'; 
    image.src = 'http://i.imgur.com/xUm3XMz.png'; 
    image.addEventListener('load', () => { 

     image.data = getPixelData(image); 

     let canvas = document.createElement('canvas'); 
     document.body.appendChild(canvas); 

     canvas.width = image.width * 1; 
     canvas.height = image.height * 1; 

     let gl = canvas.getContext('webgl'); 
     gl.clearColor(0.0, 0.0, 0.0, 1.0); 

     let context = new RenderContext({ gl }); 

     let entry = new RenderPass.EntryPoint({ context }), pipeline = entry; 
     let output = new RenderPass.StandardOutput({ context }); 

     pipeline.append(output); 

     entry.setInputSize(image.width, image.height); 
     entry.setInputData(image.data); 

     output.setOutputSize(canvas.width, canvas.height); 

     var render = () => { 
      requestAnimationFrame(render); 
      entry.render(); 
     }; 

     render(); 

    }); 

})(); 

回答

0

我忘了啓用屬性。以下代碼修復了它:

this.context.gl.enableVertexAttribArray(this.aVertexPositionLocation)