gpt4 book ai didi

javascript - 无法渲染到帧缓冲区(纹理)

转载 作者:行者123 更新时间:2023-12-02 15:22:21 29 4
gpt4 key购买 nike

我正在尝试使用阴影贴图实现阴影,因此我需要将场景渲染到单独的帧缓冲区(纹理)。我无法让它正常工作,因此在剥离我的代码库后,我留下了一组相对简单的指令,这些指令应该将场景渲染到纹理,然后简单地渲染纹理。

该程序由两个程序组成:

  1. 地面计划
  2. 茶壶程序

第一个应该渲染一个具有特定纹理的矩形。第二个应该渲染一个茶壶(颜色基于其位置)。 Eech 渲染步骤执行以下操作(嗯,无论如何,这就是想法):

  1. 切换到帧缓冲区
  2. 渲染茶壶
  3. 切换到普通缓冲区
  4. 渲染茶壶
  5. 渲染地面

现在,地面片段着色器看起来像:

gl_FragColor = texture2D(shadowMap, fTexCoord);

“shadowMap”是我在步骤 2 中渲染的纹理。我期望看到一个 float 的茶壶,其下方绘制了一个矩形。这确实有效。现在,我还期望有一个“地面”来容纳一个茶壶。毕竟,我们在没有地面的情况下渲染了我们正在查看的场景到帧缓冲区/纹理。

代码

var UNSIGNED_SHORT_SIZE = 2;

// Variables filled by setup()
var glCanvas;
var gl, teapotProgram, groundProgram;
var vBuffer, iBuffer, fBuffer;
var vertices, indices, textures;

var teapot = null;
var model;
var view;
var light;
var projection;

var BASE_URL = "https://hmbastiaan.nl/martijn/webgl/W08P02_SO/";

var WIDTH = 150, HEIGHT = 150;

function makeTeapot(){
var drawingInfo = teapot.getDrawingInfoObjects();
var indices = drawingInfo.indices;

for(var i=0; i < indices.length; i++){
indices[i] += 4; // Add offset for 'ground'
}

return {
indices: drawingInfo.indices,
vertices: drawingInfo.vertices
}
}

function makeRectangle(x1, x2, y1, y2, z1, z2){
var x1 = -2,
x2 = 2,
y1 = -1,
y2 = -1,
z1 = -1,
z2 = -5;

var vertices = [
vec4(x1, y2, z1, 1),
vec4(x2, y1, z1, 1),
vec4(x2, y1, z2, 1),
vec4(x1, y2, z2, 1)
];

var textures = [
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2( 1.0, 1.0),
vec2(-1.0, 1.0)
];

var indices = [
0, 1, 2,
0, 2, 3
];

return {
indices: indices,
vertices: vertices,
textures: textures
}

}

function resetBuffers(){
vertices = [];
indices = [];
textures = [];

// Add rectangle
var rectangle = makeRectangle();
Array.prototype.push.apply(vertices, rectangle.vertices);
Array.prototype.push.apply(indices, rectangle.indices);
Array.prototype.push.apply(textures, rectangle.textures);

// Add teapot
var teapot = makeTeapot();
Array.prototype.push.apply(vertices, teapot.vertices);
Array.prototype.push.apply(indices, teapot.indices);

console.log(vertices);
console.log(indices);
console.log(textures);

// Send to GPU
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
}

function setup(){
$.get(BASE_URL + "teapot.obj", function(teapot_obj_data){
teapot = new OBJDoc(BASE_URL + "teapot.obj");

if(!teapot.parse(teapot_obj_data, 1)){
alert("Parsing teapot.obj failed.");
return;
}

setup2();
}).fail(function(){
alert("Getting teapot.obj failed.");
});
}

function setup2(){
glCanvas = document.getElementById("gl-canvas");

gl = WebGLUtils.setupWebGL(glCanvas, {stencil: true, alpha: false});
gl.viewport(0, 0, WIDTH, HEIGHT);

teapotProgram = initShaders(gl, BASE_URL + "vshader-teapot.glsl", BASE_URL + "fshader-teapot.glsl");
groundProgram = initShaders(gl, BASE_URL + "vshader-ground.glsl", BASE_URL + "fshader-ground.glsl");

light = vec3(0.0, 2.0, -2.0);
view = lookAt(vec3(0, 0, 3), vec3(0,0,0), vec3(0,1,0));
projection = perspective(45, 1.0, 1, 100.0);

// Get teapot uniforms
gl.useProgram(teapotProgram);
teapotProgram.modelLoc = gl.getUniformLocation(teapotProgram, "Model");
teapotProgram.viewLoc = gl.getUniformLocation(teapotProgram, "View");
teapotProgram.projectionLoc = gl.getUniformLocation(teapotProgram, "Projection");

// Upload uniforms
gl.uniformMatrix4fv(teapotProgram.projectionLoc, false, flatten(projection));
gl.uniformMatrix4fv(teapotProgram.viewLoc, false, flatten(view));
gl.uniformMatrix4fv(teapotProgram.modelLoc, false, flatten(scalem(0.25, 0.25, 0.25)));

// Get teapot attributes
teapotProgram.vPosition = gl.getAttribLocation(teapotProgram, "vPosition");

// Get ground uniforms
gl.useProgram(groundProgram);
groundProgram.modelLoc = gl.getUniformLocation(groundProgram, "Model");
groundProgram.viewLoc = gl.getUniformLocation(groundProgram, "View");
groundProgram.projectionLoc = gl.getUniformLocation(groundProgram, "Projection");
groundProgram.shadowMap = gl.getUniformLocation(groundProgram, "shadowMap");

// Get ground attributes
groundProgram.vTexCoord = gl.getAttribLocation(groundProgram, "vTexCoord");
groundProgram.vPosition = gl.getAttribLocation(groundProgram, "vPosition");

// Allocate and fill vertices buffer
vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);

gl.vertexAttribPointer(teapotProgram.vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(teapotProgram.vPosition);

gl.vertexAttribPointer(groundProgram.vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(groundProgram.vPosition);

// Allocate indices buffer
iBuffer = gl.createBuffer();

// Setup FBO
fBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fBuffer);

fBuffer.renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, fBuffer.renderbuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 512, 512);

fBuffer.texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, fBuffer.texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 512, 512, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fBuffer.texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fBuffer.renderbuffer);

// Sanity checking: framebuffer seems to throw now errors
if (!gl.isFramebuffer(fBuffer)) {
throw("Invalid framebuffer");
}

var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
switch (status) {
case gl.FRAMEBUFFER_COMPLETE:
break;
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
throw("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break;
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
throw("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break;
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
throw("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
break;
case gl.FRAMEBUFFER_UNSUPPORTED:
throw("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
break;
default:
throw("Incomplete framebuffer: " + status);
}

// Set ground textures
gl.uniform1i(groundProgram.shadowMap, 0);

// Upload uniforms
gl.uniformMatrix4fv(groundProgram.projectionLoc, false, flatten(projection));
gl.uniformMatrix4fv(groundProgram.viewLoc, false, flatten(view));
gl.uniformMatrix4fv(groundProgram.modelLoc, false, flatten(mat4()));

// Restore default buffers
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

// Set background colour
gl.clearColor(0.3921, 0.5843, 0.9294, 1.0);

gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);

resetBuffers();

window.requestAnimationFrame(render);
}

function render(){
var teapot = makeTeapot();

gl.useProgram(teapotProgram);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

// Switch to framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, fBuffer);

// Draw teapot
teapot = makeTeapot();
gl.drawElements(gl.TRIANGLES, teapot.indices.length, gl.UNSIGNED_SHORT, 6 * UNSIGNED_SHORT_SIZE);

// Set framebuffer to defualt buffer (in-browser output)
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

// Draw ground
gl.useProgram(groundProgram);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);

// Render teapot
gl.useProgram(teapotProgram);
gl.drawElements(gl.TRIANGLES, teapot.indices.length, gl.UNSIGNED_SHORT, 6 * UNSIGNED_SHORT_SIZE);
}

setup();
<div>
<br/>
<canvas width="150" height="150" id="gl-canvas">Sorry :|</canvas>
</div>
<script type='text/javascript' src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/webgl-utils.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/initShaders2.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/MV.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/objParser.js"></script>

感兴趣的函数:

  1. setup2():设置所有缓冲区和制服。
  2. render():渲染场景。

免责声明:这是一个作业,尽管此代码已经足够简化,看起来根本不像原始作业:)。

最佳答案

乍一看有几个问题。

  1. 纹理绑定(bind)是全局的。因为在 setup2 中您解除了 1 个纹理的绑定(bind),这意味着它从未被使用过。

    您需要在每次绘制调用之前绑定(bind)所需的任何纹理。换句话说,当您绘制地面时,您需要绑定(bind)茶壶纹理,如下所示

    gl.bindTexture(gl.TEXTURE_2D, fBuffer.texture);

    注意:这过于简化了真正需要的内容。你真的需要

    1. 选择一个纹理单元来绑定(bind)纹理

      var unit = 5;
      gl.activeTexture(gl.TEXTURE0 + unit);
    2. 将纹理绑定(bind)到该单元。

      gl.bindTexture(gl.TEXTURE_2D, fBuffer.texture);
    3. 将统一采样器设置为该纹理单元

      gl.uniform1i(groundProgram.shadowMap, unit);

    您不需要这些额外步骤的原因是因为 (a) 您只需有 1 个纹理,因此您使用的是默认纹理单元 #0,并且 (b) 因为制服默认为 0,因此 shadowMap 正在查看纹理单元 #0。

  2. 因为您已经制作了 mipmap 纹理,所以仅渲染到级别 0 不会更新 mips。

    换句话说,渲染茶壶后,您将拥有一个 mip 级别 0 的茶壶,但 mip 级别 1、2、3、4、5 等仍然没有任何内容。您需要调用

    gl.generateMipmap(gl.TEXTURE_2D)

    在将茶壶渲染到该纹理后。要么停止使用 mips

  3. 每次调用gl.bindFramebuffer时都需要设置视口(viewport)。

    gl.bindFramebuffer 后面几乎总是应该调用 gl.viewport 以使视口(viewport)与您要渲染的对象的大小相匹配

    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    // set to size of fb
    gl.viewport(0, 0, widthOfFb, heightOfFb);

    renderSomething();

    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    // set to size of canvas's drawingBuffer
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
  4. 属性设置是全局的

    您设置茶壶属性。然后根据纹理绘制茶壶。然后您绘制地面,但仍在使用茶壶属性。

    就像纹理一样,您需要在每次绘制调用之前设置属性。

我还猜测您确实不应该在渲染函数中调用 makeTeapot ,而应该在设置中调用它。

您可能会发现this article useful

您还应该考虑not putting properties on WebGL objects as it's arguably an anti-pattern .

同步 XHR 请求也不酷。您将在 JavaScript 控制台中收到此消息

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.

关于javascript - 无法渲染到帧缓冲区(纹理),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33942909/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com