我是Vanilla WebGL的新手,正在尝试将帧缓冲区用于后期处理/高级着色器。运行代码时,我得到警告:
GL_INVALID_OPERATION:glDrawArrays:绘制的源纹理和目标纹理是相同的。
到目前为止是我的代码。如果有人可以指出正确的方向,如何正确利用帧缓冲区将纹理传递到下一个传递。它包装在vue.js组件中,但这没关系。
<template lang='pug'>
canvas
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'webGl',
created ()
{
this.static = {
af: null,
gl: null,
fr: 0,
shaders:
{
vertex: `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}`,
fragment: `
#ifdef GL_ES
precision mediump float;
#endif
uniform float u_time;
uniform vec2 u_size;
uniform int u_frame;
uniform sampler2D u_texture;
const int maxIter = 15;
vec2 getPos() {
vec2 pos = ( gl_FragCoord.xy / u_size.xy ) - vec2(0.5);
pos.x *= u_size.x / u_size.y;
return pos;
}
vec2 cmult(vec2 a, vec2 b){
return vec2(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
float length2(vec2 v){
return v.x*v.x+v.y*v.y;
}
vec2 map(vec2 pos){
return pos;
return vec2(pos.x * sqrt(1.-pos.y*pos.y*3.), pos.y * sqrt(1.-pos.x*pos.x*2.));
}
vec2 iterate(vec2 p, vec2 c){
vec2 p2 = cmult(p,p);
return p2 + c;
}
bool checkAbort(vec2 p, vec2 c){
return length2(p) > 400.;
}
float l2 = log(2.);
vec4 defaultColor ( void )
{
return vec4(0.35,0.35,0.35,1.0);
}
vec4 color(int iterations, vec2 p){
float col = .20 + (float(iterations) - log(log(length2(p)))/l2) / float(maxIter);
return defaultColor() * vec4(col);
}
void main( void ){
if (u_frame < 300)
{
vec2 c = map(getPos())*0.8 - vec2(0.5);
vec2 p = c + vec2(sin(-u_time), cos(u_time)) * 0.2;
float m;
for(int i = 0; i < maxIter ;i++) {
p = iterate(p,c);
if(checkAbort(p,c)){
gl_FragColor = color(i,p);
return;
}
}
gl_FragColor = defaultColor();
}
else
{
gl_FragColor = texture2D(u_texture, gl_FragCoord.xy / u_size.xy);
}
}`,
program: null,
attributes: {},
uniforms: {},
time: 0
}
}
},
mounted ()
{
this.setInitWebGlContext()
this.setInitShaderProgram()
this.setInitAttributes(['a_position'])
this.setInitUniforms(['u_size', 'u_time', 'u_frame', 'u_texture'])
this.setInitGeometryBuffer()
this.setRenderLoop()
},
beforeDestroy ()
{
window.cancelAnimationFrame(this.static.af)
},
computed:
{
...mapGetters([
'getCalcs'
])
},
methods:
{
setInitWebGlContext ()
{
this.static.gl = this.$el.getContext('webgl')
if (this.static.gl === null)
{
console.log('Unable to initialize WebGL. Your browser or machine may not support it.')
}
},
setInitShaderProgram ()
{
const gl = this.static.gl
this.static.shaders.program = gl.createProgram()
const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(vertexShader, this.static.shaders.vertex)
gl.shaderSource(fragmentShader, this.static.shaders.fragment)
gl.compileShader(vertexShader)
gl.compileShader(fragmentShader)
gl.attachShader(this.static.shaders.program, vertexShader)
gl.attachShader(this.static.shaders.program, fragmentShader)
gl.linkProgram(this.static.shaders.program)
gl.useProgram(this.static.shaders.program)
},
setInitAttributes (keys)
{
const gl = this.static.gl
const program = this.static.shaders.program
for (let i = 0; i < keys.length; i++)
{
this.static.shaders.attributes[keys[i]] = gl.getAttribLocation(program, keys[i])
}
},
setInitUniforms (keys)
{
const gl = this.static.gl
const program = this.static.shaders.program
for (let i = 0; i < keys.length; i++)
{
this.static.shaders.uniforms[keys[i]] = gl.getUniformLocation(program, keys[i])
}
},
setInitGeometryBuffer ()
{
const gl = this.static.gl
const buffer = gl.createBuffer()
gl.bindBuffer(this.static.gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0]), gl.STATIC_DRAW)
},
setCreateTexture ()
{
const gl = this.static.gl
const width = this.getCalcs.vw
const height = this.getCalcs.vh
const texture = gl.createTexture()
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)
return texture
},
setCreateFramebuffer ()
{
const gl = this.static.gl
const buffer = gl.createFramebuffer()
gl.bindFramebuffer(gl.FRAMEBUFFER, buffer)
const texture = this.setCreateTexture()
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)
return {
texture: texture,
buffer: buffer
}
},
setRenderLoop ()
{
this.static.af = window.requestAnimationFrame(this.setRenderLoop)
const gl = this.static.gl
const fb = this.static.fb
const width = this.getCalcs.vw
const height = this.getCalcs.vh
const attributes = this.static.shaders.attributes
const uniforms = this.static.shaders.uniforms
const mouse = this.static.shaders.mouse
const fr = this.static.fr
this.$el.width = width
this.$el.height = height
const bufferA = this.setCreateFramebuffer()
gl.viewport(0, 0, width, height)
gl.clearColor(0.0, 0.0, 0.0, 0.0)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.enableVertexAttribArray(attributes.a_position)
gl.vertexAttribPointer(attributes.a_position, 2, gl.FLOAT, false, 0, 0)
gl.uniform2f(uniforms.u_size, width, height)
gl.uniform1f(uniforms.u_time, window.performance.now() / 3000)
gl.uniform1i(uniforms.u_frame, fr)
gl.drawArrays(gl.TRIANGLES, 0, 6)
gl.bindTexture(gl.TEXTURE_2D, bufferA.texture)
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
gl.viewport(0, 0, width, height)
gl.clearColor(0.0, 0.0, 0.0, 0.0)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.enableVertexAttribArray(attributes.a_position)
gl.vertexAttribPointer(attributes.a_position, 2, gl.FLOAT, false, 0, 0)
gl.uniform2f(uniforms.u_size, width, height)
gl.uniform1f(uniforms.u_time, window.performance.now() / 3000)
gl.uniform1i(uniforms.u_frame, fr)
gl.uniform1i(uniforms.u_texture, 0)
gl.drawArrays(gl.TRIANGLES, 0, 6)
this.static.fr++
}
}
}
</script>
问题与错误中所述的完全一样。
绘制的源纹理和目标纹理相同。
[查看您的代码,有一个着色器,它引用了一个纹理,有一个纹理,它附加到帧缓冲区,并且绑定到默认的纹理单元0。因此,在绘制时,它既用作输入(u_texture
),又用作输出(当前帧缓冲区)。不允许的。
简单的解决方案是您需要另一个纹理。绘制到帧缓冲区时绑定该纹理。
更好的解决方案是您需要2个不同的着色器程序。一种用于绘制到不使用纹理作为输入的帧缓冲区,另一种用于绘制到画布。因为它是一个在u_frame
上分支的着色器。删除该分支,并将其分成2个着色器程序。然后计算颜色的u_frame <300,然后使用纹理的颜色。使用计算之一绘制到帧缓冲区,使用纹理之一绘制帧缓冲区的纹理到画布。
一些可能有用或无效的链接:drawing multiple things,render targets,image processing。