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在解包为深度值,精度更高!

相关推荐
惜.己39 分钟前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
长天一色1 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2342 小时前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
读心悦2 小时前
如何在 Axios 中封装事件中心EventEmitter
javascript·http
神之王楠2 小时前
如何通过js加载css和html
javascript·css·html
余生H2 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
流烟默3 小时前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
茶卡盐佑星_3 小时前
meta标签作用/SEO优化
前端·javascript·html
与衫3 小时前
掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系
android·javascript·sql
金灰3 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5