javascript - 渲染到纹理和属性位置

标签 javascript webgl vertex-attributes

我正在使用 webgl,我想做的是首先渲染到纹理,然后使用该纹理在屏幕上渲染,我在第一步渲染中遇到了属性问题。

我将尝试用几句话来解释我正在尝试做的事情。首先,我想使用片段着色器将使用属性的东西渲染到纹理,然后使用该纹理渲染到屏幕,并为下一帧重复这些步骤。但是,当我尝试使用帧缓冲区绑定(bind)进行渲染时,该属性 (pos) 具有无效值,我的意思是,根本没有任何值。

我写了一个小演示来展示我的问题:

var canvas = document.getElementById("c");
var gl = getWebGLContext(canvas);	

var program_init, program_pers, tex, fb;

function init() {
	var verts = [
		  1,  1,
		 -1,  1,
		 -1, -1,
		  1,  1,
		 -1, -1,
		  1, -1,
	];
    
    var vertBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
	gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
	gl.enableVertexAttribArray(0);
    
    tex = gl.createTexture();
    fb = gl.createFramebuffer();

    program_init = createProgramFromScripts(gl, ["vshader-init", "fshader-init"], ["pos"]);
    program_pers = createProgramFromScripts(gl, ["vshader-pers", "fshader-pers"], ["a_position"]);
}

function renderToTexture(gl, time) {
	gl.useProgram(program_init);
	
	var timeLocation = gl.getUniformLocation(program_init, 'time');
	gl.uniform1f(timeLocation, time);

	gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

	gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);

	gl.drawArrays(gl.TRIANGLES, 0, 6);
    
	gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};

function renderToScreen(gl) {
	gl.useProgram(program_pers);
	gl.drawArrays(gl.TRIANGLES, 0, 6);
};	

init();
requestAnimationFrame(function(){
	renderToTexture(gl, arguments[0]);
	renderToScreen(gl);
	
	requestAnimationFrame( arguments.callee );
});
canvas { border: 1px solid black; }
body { background-color: darkslategrey }
<script src="http://greggman.github.com/webgl-fundamentals/webgl/resources/webgl-utils.js"></script>

<script id="vshader-init" type="vs/shader">
attribute vec4 pos;
varying vec2 uv;

void main() {
	gl_Position = pos;
	uv = pos.xy * .5 + .5;
}    
</script>
<script id="fshader-init" type="fs/shader">
precision mediump float;
varying vec2 uv;

uniform float time;

void main() {
	float t = floor(time / 1000.);
	vec3 color;
	color.x = sin(t*uv.x);
	color.y = tan(t*uv.y);
	color.z = cos(t);
	
    gl_FragColor = vec4(color, 1.);
}
</script>

<script id="vshader-pers" type="vs/shader">
attribute vec4 a_position;
varying vec2 v_texcoord;

void main() {
	gl_Position = a_position;
	v_texcoord = a_position.xy * .5 + .5;
}    
</script>
<script id="fshader-pers" type="fs/sahder">
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_sampler;
void main() {
	gl_FragColor = texture2D(u_sampler, v_texcoord);
}
</script>

<body>
	<canvas id="c" width="400" height="400"></canvas>
</body>

如果我注释 javascript 代码中的第 38,39 行(frameBuffer 的绑定(bind))和第 54 行(渲染到屏幕的代码,运行不同的程序)我们可以看到它正确地呈现并且名称“pos "被赋予正确的值。

var canvas = document.getElementById("c");
var gl = getWebGLContext(canvas);	

var program_init, program_pers, tex, fb;

function init() {
	var verts = [
		  1,  1,
		 -1,  1,
		 -1, -1,
		  1,  1,
		 -1, -1,
		  1, -1,
	];
    
    var vertBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
	gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
	gl.enableVertexAttribArray(0);
    
    tex = gl.createTexture();
    fb = gl.createFramebuffer();

    program_init = createProgramFromScripts(gl, ["vshader-init", "fshader-init"], ["pos"]);
    program_pers = createProgramFromScripts(gl, ["vshader-pers", "fshader-pers"], ["a_position"]);
}

function renderToTexture(gl, time) {
	gl.useProgram(program_init);
	
	var timeLocation = gl.getUniformLocation(program_init, 'time');
	gl.uniform1f(timeLocation, time);

	gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

	//gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
	//gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);

	gl.drawArrays(gl.TRIANGLES, 0, 6);
    
	gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};

function renderToScreen(gl) {
	gl.useProgram(program_pers);
	gl.drawArrays(gl.TRIANGLES, 0, 6);
};	

init();
requestAnimationFrame(function(){
	renderToTexture(gl, arguments[0]);
	//renderToScreen(gl);
	
	requestAnimationFrame( arguments.callee );
});
canvas { border: 1px solid black; }
body { background-color: darkslategrey }
<script src="http://greggman.github.com/webgl-fundamentals/webgl/resources/webgl-utils.js"></script>

<script id="vshader-init" type="vs/shader">
attribute vec4 pos;
varying vec2 uv;

void main() {
	gl_Position = pos;
	uv = pos.xy * .5 + .5;
}    
</script>
<script id="fshader-init" type="fs/shader">
precision mediump float;
varying vec2 uv;

uniform float time;

void main() {
	float t = floor(time / 1000.);
	vec3 color;
	color.x = sin(t*uv.x);
	color.y = tan(t*uv.y);
	color.z = cos(t);
	
    gl_FragColor = vec4(color, 1.);
}
</script>

<script id="vshader-pers" type="vs/shader">
attribute vec4 a_position;
varying vec2 v_texcoord;

void main() {
	gl_Position = a_position;
	v_texcoord = a_position.xy * .5 + .5;
}    
</script>
<script id="fshader-pers" type="fs/shader">
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_sampler;
void main() {
	gl_FragColor = texture2D(u_sampler, v_texcoord);
}
</script>

<body>
	<canvas id="c" width="400" height="400"></canvas>
</body>

我不太了解它应该如何工作,而且我有点不知所措。我确信我遗漏了一些重要的东西,但我找不到任何东西。任何帮助将不胜感激。

最佳答案

您的帧缓冲区纹理大小为 1x1 像素。你希望看到什么?您正在渲染单个像素。

另请注意,除非您的帧缓冲区与 Canvas 大小相同,否则您需要调用 gl.viewport 并将其设置为每次调用 后呈现的内容的大小gl.bindFramebuffer

您可能还不想在每一帧都创建纹理。这是更改了这些内容后的代码。

var canvas = document.getElementById("c");
var gl = canvas.getContext("webgl");	

var program_init, program_pers, tex, fb;
var fbWidth = 400;
var fbHeight = 300;

function init() {
	var verts = [
		  1,  1,
		 -1,  1,
		 -1, -1,
		  1,  1,
		 -1, -1,
		  1, -1,
	];
    
    var vertBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
	gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
	gl.enableVertexAttribArray(0);
    
    tex = gl.createTexture();
    fb = gl.createFramebuffer();

    program_init = webglUtils.createProgramFromScripts(gl, ["vshader-init", "fshader-init"], ["pos"]);
    program_pers = webglUtils.createProgramFromScripts(gl, ["vshader-pers", "fshader-pers"], ["a_position"]);
  
  	gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, fbWidth, fbHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    // make non power-of-2 texture renderable
    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.LINEAR);

	gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
}

function renderToTexture(gl, time) {
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.viewport(0, 0, fbWidth, fbHeight);
  
    gl.useProgram(program_init);
	
	var timeLocation = gl.getUniformLocation(program_init, 'time');
	gl.uniform1f(timeLocation, time);

	gl.drawArrays(gl.TRIANGLES, 0, 6);
};

function renderToScreen(gl) {    
	gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
	gl.useProgram(program_pers);
	gl.drawArrays(gl.TRIANGLES, 0, 6);
};	

init();
requestAnimationFrame(function(){
	renderToTexture(gl, arguments[0]);
	renderToScreen(gl);
	
	requestAnimationFrame( arguments.callee );
});
canvas { border: 1px solid black; }
body { background-color: darkslategrey }
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>

<script id="vshader-init" type="vs/shader">
attribute vec4 pos;
varying vec2 uv;

void main() {
	gl_Position = pos;
	uv = pos.xy * .5 + .5;
}    
</script>
<script id="fshader-init" type="fs/shader">
precision mediump float;
varying vec2 uv;

uniform float time;

void main() {
	float t = floor(time / 1000.);
	vec3 color;
	color.x = sin(t*uv.x);
	color.y = tan(t*uv.y);
	color.z = cos(t);
	
    gl_FragColor = vec4(color, 1.);
}
</script>

<script id="vshader-pers" type="vs/shader">
attribute vec4 a_position;
varying vec2 v_texcoord;

void main() {
	gl_Position = a_position;
	v_texcoord = a_position.xy * .5 + .5;
}    
</script>
<script id="fshader-pers" type="fs/sahder">
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_sampler;
void main() {
	gl_FragColor = texture2D(u_sampler, v_texcoord);
}
</script>

<body>
	<canvas id="c" width="400" height="400"></canvas>
</body>

关于javascript - 渲染到纹理和属性位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33692034/

相关文章:

javascript - 如何使用 Matrix4.setLookAt 在场景中移动相机

opengl-es - 如何增加台面驱动程序的 GL_MAX_TEXTURE_SIZE?

javascript - 模块模式中 get/set 和 Object.defineProperty 的区别

javascript - 如何在不使用 ID 的情况下在 ul 中定位 li?

opengl-es - WebGL2 是否自动内置了抗锯齿功能?

c++ - glVertexAttribPointer() 的索引应该是连续的吗?

metal - 如何在 Metal 顶点着色器 MTL 顶点属性描述符中描述 packed_float3?

blender - Blender 如何计算顶点法线?

javascript - 如何立即开始 setInterval 循环?

javascript - 当您单击一个页面的链接时,更改另一个页面中同一菜单的链接的颜色