0

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

该程序由两个程序组成:

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

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

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

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

gl_FragColor=纹理2D(shadowMap,fTexCoord);

“shadowMap”是我在步骤2中渲染到的纹理。期待看到一个漂浮的茶壶,下面画着一个长方形。这确实有效。现在,我还希望有一个“地面”来容纳茶壶。毕竟,我们渲染了我们正在查看的场景,而没有将地面渲染到帧缓冲区/纹理。

代码

var UNSIGNED_SHORT_SIZE=2;//setup()填充的变量var glCanvas;var gl,茶壶程序,地面程序;var vBuffer、iBuffer和fBuffer;var顶点、索引、纹理;var茶壶=空;var模型;var视图;var光;var投影;var BASE_URL=“https://hmbastiaan.nl/martijn/webgl/W08P02_SO/";var宽度=150,高度=150;函数makeTeapot(){var drawingInfo=茶壶.getDrawingInfoObjects();var指数=drawingInfo.indices;for(var i=0;i<指数.length;i++){指数[i]+=4;//为“地面”添加偏移}返回{索引:drawingInfo.indices,顶点:drawingInfo.vertices}}函数makeRectangle(x1,x2,y1,y2,z1,z2){var x1=-2,x2=2,y1=-1,y2=-1,z1=-1,z2=-5;var顶点=[vec4(x1,y2,z1,1),vec4(x2,y1,z1,1),vec4(x2,y1,z2,1),vec4(x1,y2,z2,1)];var纹理=[vec2(-1.0,-1.0),vec2(1.0,-1.0),vec2(1.0,1.0),vec2(-1.0,1.0)];var指数=[0, 1, 2,0, 2, 3];返回{索引:索引,顶点:顶点,纹理:纹理}}函数resetBuffers(){顶点=[];指数=[];纹理=[];//添加矩形var矩形=makeRectangle();Array.prototype.push.apply(顶点、矩形顶点);数组.原型.推送.应用(索引,矩形.索引);数组.原型.推送.应用(纹理,矩形.纹理);//添加茶壶var茶壶=制作茶壶();数组.原型.推送.应用(顶点,茶壶.顶点);数组.原型.推送.应用(索引,茶壶.索引);console.log(顶点);console.log(索引);console.log(纹理);//发送到GPUgl.bindBuffer(gl.ARRAY_BUFFER,vBuffer);gl.bufferData(gl.ARRAY_BUFFER,展平(顶点),gl.STATIC_DRAW);gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,iBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,新Uint16Array(索引),gl.STATIC_DRAW);}函数设置(){$.get(BASE_URL+“teapot.obj”,函数(teapot_obj_data){teapot=新OBJDoc(BASE_URL+“teapot.obj”);if(!teapot.parse(teapotobj_data,1)){alert(“分析teapot.obj失败。”);回报;}设置2();}).fail(函数(){alert(“获取teapot.obj失败。”);});}函数设置2(){glCanvas=文档.getElementById(“gl-canvas”);gl=WebGLUtils.setupWebGL(glCanvas,{stencil:true,alpha:false});gl.视口(0,0,宽度,高度);teapotProgram=initShaders(gl,BASE_URL+“vshader-teapot.glsl”,BASE_FRL+“fshader-tapot.glsl”);groundProgram=initShaders(gl,BASE_URL+“vshader-ground.glsl”,BASE_FRL+“fshader-geround.gsl”);灯光=vec3(0.0、2.0、-2.0);视图=lookAt(vec3(0,0,3),vec3;投影=透视(45,1.0,1100.0);//拿茶壶制服gl.useProgram(teapotProgram);teapotProgram.modelLoc=gl.getUniformLocation(茶壶程序,“模型”);teapotProgram.viewLoc=gl.getUniformLocation(茶壶程序,“视图”);teapotProgram.projectionLoc=gl.getUniformLocation(茶壶程序,“投影”);//上传制服gl.uniformMatrix4fv(teapotProgram.projectionLoc,false,扁平(投影));gl.uniformMatrix4fv(teapotProgram.viewLoc,false,扁平(view));gl.uniformMatrix4fv(teapotProgram.modelLoc,false,扁平(缩放(0.25,0.25,0.25));//获取茶壶属性teapotProgram.vPosition=gl.getAttribLocation(teapot程序,“vPosition”);//获取地面制服gl.useProgram(地面程序);groundProgram.modelLoc=gl.getUniformLocation(groundProgram,“模型”);groundProgram.viewLoc=gl.getUniformLocation(地面程序,“视图”);groundProgram.projectionLoc=gl.getUniformLocation(地面程序,“投影”);groundProgram.shadowMap=gl.getUniformLocation(groundProgram,“shadowMap”);//获取地面属性地面程序.vTexCoord=gl.getAttribLocation(地面程序,“vTexCourd”);groundProgram.vPosition=gl.getAttribLocation(groundProgram,“vPosition”);//分配和填充顶点缓冲区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);//分配索引缓冲区iBuffer=gl.createBuffer();//设置固定基地运营商fBuffer=gl.createFramebuffer();gl.bindFramebuffer(gl.FRAMEBUFFER,fBuffer);fBuffer.renderbuffer=gl.createRenderbuffer();gl.bindRenderbuffer(gl.RENDERBUFFER,fBuffer.RENDERBUFFER);gl.渲染缓冲存储(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,512512,0,gl.RGBA,gl.UNSIGNED_BYTE,空);gl.生成位图(gl.TEXTURE_2D);gl.tex参数(gl.TEXTURE_2D,gl.TESTURE_MIN_FILTER,gl.NEAREST_MIMPAP_LINEAR);gl.tex参数(gl.TEXTURE_2D,gl.TESTURE_MAG_FILTER,gl.NEAREST);gl.帧缓冲区纹理2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,fBuffer.TEXTURE,0);gl.帧缓冲渲染缓冲区(gl.FRAMEBUFFER、gl.DEPTH_ATTACHMENT、gl.RENDERBUFFER和fBuffer.RENDERBUFFER);//健全性检查:帧缓冲区现在似乎抛出错误if(!gl.is帧缓冲区(fBuffer)){throw(“无效帧缓冲区”);}var status=gl.checkFramebufferStatus(gl.FRAMEBUFFER);开关(状态){案例gl.FRAMEBUFFER_COMPLETE:断裂;案例gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:throw(“不完整的帧缓冲区:framebuffer_Incomplete_ATTACHMENT”);断裂;案例gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:throw(“不完整的帧缓冲区:framebuffer_Incomplete_MISSING_ATTACHMENT”);断裂;案例gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:throw(“不完整的帧缓冲区:framebuffer_Incomplete_DIMENSIONS”);断裂;案例gl.FRAMEBUFFER_UNSUPPORTED:throw(“不完整的帧缓冲区:framebuffer_UNSUPPORTED”);断裂;违约:throw(“帧缓冲区不完整:”+状态);}//设置地面纹理gl.uniform1i(groundProgram.shadowMap,0);//上传制服gl.uniformMatrix4fv(groundProgram.projectionLoc,false,扁平(投影));gl.uniformMatrix4fv(groundProgram.viewLoc,false,扁平(view));gl.uniformMatrix4fv(groundProgram.modelLoc,false,扁平(mat4()));//恢复默认缓冲区gl.bindTexture(gl.TEXTURE_2D,null);gl.bindRenderbuffer(gl.RENDERBUFFER,null);gl.bindFramebuffer(gl.FRAMEBUFFER,null);//设置背景颜色gl.透明色(0.3921,0.5843,0.9294,1.0);全局启用(全局深度测试);全局启用(全局CULL_FACE);resetBuffers();window.requestAnimationFrame(渲染);}函数render(){var茶壶=制作茶壶();gl.useProgram(teapotProgram);gl.清除(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFFER_BIT| gl.STENCIL_BUFFER _BIT);//切换到帧缓冲区gl.bindFramebuffer(gl.FRAMEBUFFER,fBuffer);//绘制茶壶茶壶=制作茶壶();gl.drawElements(gl.TRIANGLES,teapot.indices.length,gl.UNSIGNED_SHORT,6*UNSIGNED_SHORT_SIZE);//将帧缓冲区设置为消除缓冲区(浏览器内输出)gl.bindFramebuffer(gl.FRAMEBUFFER,null);//绘制地面gl.useProgram(地面程序);gl.drawElements(gl.TRIANGLES,6,gl.UNSIGNED_SHORT,0);//渲染茶壶gl.useProgram(teapotProgram);gl.drawElements(gl.TRIANGLES,teapot.indices.length,gl.UNSIGNED_SHORT,6*UNSIGNED_SHORT_SIZE);}设置();
<div><br/>抱歉:|</cavas></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://hmbastian.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():渲染场景。

免责声明:这是一个赋值,尽管此代码已简化到与原始赋值完全不同:)。

4
  • 请创建一个最小可再现示例并将其编辑为您的问题。这里没有人会仔细检查你的整个代码。 评论 2015年11月26日16:10
  • 好吧,我会尽量减少。谢谢! 评论 2015年11月26日16:11
  • 我已经大大减少了代码。render()函数现在尽我所能地简单明了,应该可以清楚地说明我的问题。我也会编辑我的问题。 评论 2015年11月26日17:02
  • 您不应该让我们跳过障碍来查看您的代码。将着色器放在代码或html中。不要从外部网站下载。这使得看它们非常乏味:( 评论 2015年11月27日4:17

1答案1

重置为默认值

乍一看,有几个问题。

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

    每次调用绘图之前,需要绑定所需的任何纹理。换句话说,在绘制地面时,需要绑定茶壶纹理,如

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

    注意:这是对真正需要的东西的过度简化。你真的需要

    1. 选择要将纹理绑定到的纹理单位

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

      gl.bindTexture(gl.TEXTURE_2D,fBuffer.TEXTURE);
    3. 将均匀采样器设置为该纹理单位

      gl.uniform1i(groundProgram.shadowMap,单位);

    你不需要这些额外步骤的原因是(a)你只需要有1个纹理,所以使用纹理单位#0,默认值和(b),因为制服默认为0,所以阴影贴图正在查看纹理单元#0。

  2. 因为您已经创建了mipmapped纹理,所以仅渲染到级别0不会更新mip。

    换句话说,渲染茶壶后,您将在mip级别0中拥有茶壶,但mip级别1、2、3、4、5等中仍然没有茶壶。你需要打电话

    gl.生成位图(gl.TEXTURE_2D)

    在渲染茶壶后对该纹理进行渲染。要么这样,要么停止使用mip

  3. 每次调用时都需要设置视口gl.bind帧缓冲区.

    gl.bind帧缓冲区应该总是在打电话给全局视口使视口与要渲染的对象的大小匹配

    gl.bindFramebuffer(gl.FRAMEBUFFER,fb);//设置为fb的大小gl.视口(0,0,widthOfFb,heightOfFp);renderSomething();gl.bindFramebuffer(gl.FRAMEBUFFER,null);//设置为画布的drawingBuffer的大小gl.视口(0,0,gl.drawingBufferWidth,gl.dawingBufferHeight);
  4. 属性设置是全局的

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

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

我猜你真的不应该打电话制作茶壶但应该在安装程序中调用它。

你可能会发现这篇文章很有用

你还应该考虑没有在WebGL对象上放置属性,因为这可能是一种反模式.

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

主线程上的同步XMLHttpRequest已弃用,因为其对最终用户体验的不利影响。更多信息帮助,检查http://xr.spec.whatwg.org/.

1
  • 谢谢你的耐心。我肯定应该在代码中加入着色器。同步XHR请求是我的大学提供的代码的一部分。关于其他几点:我不知道,非常感谢。我会尽快测试它。 评论 2015年11月27日7:57

您的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.