webgl扩展系列之三--------WEBGL_depth_texture(深度纹理)

一.介绍

WEBGL_depth_texture是一个webgl1的扩展插件,允许为FBO创建深度纹理,将深度写入纹理中,便于使用,通常 可以用来获取点击点的世界坐标,法线等。

这个扩展扩展了两个方法:

  • texImage2D(target, level, internalformat, width, height, border, format, type, pixels)
    • formatinternalformat可以接受两个参数:gl.DEPTH_COMPONENTgl.DEPTH_STENCIL
    • type可以接受三个参数:gl.UNSIGNED_SHORT, gl.UNSIGNED_INT, 和 ext.UNSIGNED_INT_24_8_WEBGL.
    • pixels 可以接受[Uint16Array] or a [Uint32Array]
  • framebufferTexture2D(target, attachment, textarget, texture, level)
    • attachment可以接受gl.DEPTH_STENCIL_ATTACHMENT

二 使用深度反算世界坐标

2.1 获取扩展

js 复制代码
this._depthTextureExt = this._gl.getExtension("WEBGL_depth_texture");

2.2 创建深度(模板)纹理

js 复制代码
Texture2D.createDepthStencilTexture=function({width,height,type,context}){
  const gl=context._gl
  return new Texture2D({
    context,
    width,
    height,
    type,
    format:gl.DEPTH_STENCIL,
    internalformat:gl.DEPTH_STENCIL
  })
}

2.3 FBO创建深度(模板)关联对象

js 复制代码
//将颜色附件绑定到FBO上
gl.framebufferTexture2D(
   gl.FRAMEBUFFER,
   gl.DEPTH_STENCIL_ATTACHMENT,
   gl.TEXTURE_2D,
   texture2D.texture,
   0
);

2.4 创建屏幕四边形,将深度纹理展示

js 复制代码
const uniformMap2 = {
    u_viewProjectMatrix: orthoCamera.viewProjectMatrix,
    u_modelMatrix: plane.modelMatrix,
    u_texture: depthStentilTexture,
    near:camera.nearDistance,
    far:camera.farDistance
};
drawCommandPlane.uniformMap = uniformMap2;
drawCommandPlane.execute();

shader

c 复制代码
const depthTextureFS = /*glsl*/ `
  //  #extension GL_EXT_draw_buffers : require
  precision highp float;
  uniform sampler2D u_texture;
  uniform float near;
  uniform float far;
  varying vec2 v_uv;
  float getViewZ(float depth) 
  {

      float z = depth * 2.0 - 1.0; // back to NDC 
      return (2.0 * near * far) / (far + near - z * (far - near));    
  }

  float linerDepth(float viewZ){
    return (viewZ-near)/(far-near);
  }

  void main(){
    vec4 depthStencil=texture2D(u_texture,v_uv);
    // float viewZ=getViewZ(depthStencil.r);
    // gl_FragColor=vec4(vec3(1.0-linerDepth(viewZ)),depthStencil.a);
    gl_FragColor=vec4(vec3(1.0-depthStencil.r),depthStencil.a);
  }

`;

2.5 点击获取世界坐标

js 复制代码
document.getElementById("canvas").onclick = (e) => {
  const x = e.offsetX;
  const y = e.offsetY;

  const pixels = new Uint8Array(4);
  draw()
  gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
  console.log(pixels)
  const depth = (255 - pixels[0]) / (255);
  windowToWorldPosition(x/canvas.clientWidth,(1.0-y/canvas.clientHeight),depth)
};

function windowToWorldPosition(x,y,depth) {
  //转换到ndc空间
  const xNDC=x*2-1
  const yNDC=y*2-1
  const zNDC=depth*2-1
  const worldPosition=camera.inverseProjectMatrix.multiplyVector4(new Vector4([xNDC,yNDC,zNDC,1.0]))

  const elements=worldPosition.elements
  console.log(elements[0]/elements[3],elements[1]/elements[3],elements[2]/elements[3])
}

点击获取一个结果为:-0.2748838665872577 0.8578270784183898 1.327160348557312目测是正确的

在这个过程中,其实可以在2.4中shader将深度打包为RGBA值,同时子啊点击时获取到rgba在解包为深度值,精度更高!

相关推荐
anyup_前端梦工厂5 小时前
初始 ShellJS:一个 Node.js 命令行工具集合
前端·javascript·node.js
5hand5 小时前
Element-ui的使用教程 基于HBuilder X
前端·javascript·vue.js·elementui
GDAL5 小时前
vue3入门教程:ref能否完全替代reactive?
前端·javascript·vue.js
小马哥编程7 小时前
Function.prototype和Object.prototype 的区别
javascript
王小王和他的小伙伴8 小时前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱8 小时前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿8 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08218 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
摇光938 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
胡西风_foxww9 小时前
【ES6复习笔记】Class类(15)
javascript·笔记·es6·继承··class·静态成员