【问题标题】:Three.js: 3D texture MIP depth face clipping when using a perspective cameraThree.js:使用透视相机时的 3D 纹理 MIP 深度人脸裁剪
【发布时间】:2021-06-27 19:55:36
【问题描述】:

我正在为我的一个灯光模拟器使用three.js 开发一个Web GUI。 GUI 需要渲染一个 3D 体积(整数或浮点数),所以我修改了3D texture demo 脚本并制作了一个测试页面。

经过一些调整,我能够以 MIP 样式渲染 3D 纹理,但显示在正确渲染深度方面似乎存在一些问题 - 某些边界框面可能会在某些摄像机角度消失,并导致渲染不准确。

下面的屏幕截图显示了问题。纹理是具有两个 z 层的 40x20x30 体积:0

从上面的屏幕截图中可以看出,MIP 渲染在左视角还可以,但在大多数其他角度开始显示锯齿状边界(或缺少 bbx 面),如右侧所示。

您可以点击以下链接自行查看

http://mcx.space/test/0235423747321423142346464758/

要输入这个体积,请点击“JSON”选项卡,删除现有文本,然后复制/粘贴下面的 JSON 数据(如您所见,“Shapes”对象使用JData ND array format 定义了一个 3D 体积, 并被解码为numjs NdArray 对象)。替换 JSON 文本后,您可以单击“预览”选项卡查看渲染。

{
  "Session": {
    "ID": "mcx",
    "Photons": 100000,
    "DoMismatch": true,
    "DoAutoThread": true,
    "DoSaveVolume": true,
    "DoPartialPath": true,
    "DoNormalize": true,
    "DoSaveRef": false,
    "DoSaveExit": false,
    "DoSaveSeed": false,
    "DoDCS": false,
    "DoSpecular": true,
    "DebugFlag": "",
    "SaveDataMask": "DP",
    "OutputFormat": "nii",
    "OutputType": "x",
    "RNGSeed": 1648335518
  },
  "Forward": {
    "T0": 0,
    "T1": 5e-9,
    "Dt": 5e-9
  },
  "Optode": {
    "Source": {
      "Type": "pencil",
      "Pos": [30,30,0],
      "Dir": [0,0,1],
      "Param1": [0,0,0,0],
      "Param2": [0,0,0,0]
    },
    "Detector": []
  },
  "Shapes":{
    "_ArrayType_":"uint8",
    "_ArraySize_":[40,20,30],
    "_ArrayZipType_":"zlib",
    "_ArrayZipSize_":24000,
    "_ArrayZipData_":"eJztybENAAAIA6DU/492dOgHBlaSMqfTWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprv+4CkyqAIQ=="
  },
  "Domain": {
    "OriginType": true,
    "Dim": [60,60,60],
    "VolumeFile": "",
    "Media": [
      {
        "mua": 0,
        "mus": 0,
        "g": 1,
        "n": 1
      },
      {
        "mua": 0,
        "mus": 0,
        "g": 1,
        "n": 1
      }
    ]
  }
}

我的脚本主要改编自 3d 纹理演示。我尝试在材质设置中添加transparent: true, opacity: 0.6, alphaTest: 0.5, depthWrite: false,但没有任何区别。

因为我的数据和演示脚本是同一个 float32 数组,但是演示脚本在 MIP 模式下运行得非常好。我想知道我是否忽略了什么。

非常感谢您的评论和指点!谢谢


function render(){
  renderer.render( scene, camera );
}
        
function drawvolume(volume){
  const dtype={
    uint8:THREE.UnsignedByteType,
    uint16:THREE.UnsignedShortType,
    uint32:THREE.UnsignedIntType,
    int8:THREE.ByteType,
    int16:THREE.ShortType,
    int32:THREE.IntType,
    float32:THREE.FloatType
  };
  const dim=volume.shape;
  const buf=nj.array(volume.flatten().selection.data, 'float32');//had to cast to float32, otherwise, uint8 won't render

  const texture = new THREE.DataTexture3D( buf.selection.data, dim[2], dim[1], dim[0]);
  texture.format = THREE.RedFormat;
  texture.type = THREE.FloatType;
  texture.minFilter = texture.magFilter = THREE.LinearFilter;
  texture.unpackAlignment = 1;

  // Colormap textures
  const cmtextures = {
      viridis: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/cm_viridis.png', render ),
      gray: new THREE.TextureLoader().load( 'https://threejs.org/examples/textures/cm_gray.png', render )
  };

  // Material
  const shader = VolumeRenderShader1;

  const uniforms = THREE.UniformsUtils.clone( shader.uniforms );

  uniforms[ "u_data" ].value = texture;
  uniforms[ "u_size" ].value.set( dim[2], dim[1], dim[0] );
  uniforms[ "u_clim" ].value.set( volume.min(), volume.max() );
  uniforms[ "u_renderstyle" ].value = 0;
  uniforms[ "u_renderthreshold" ].value =  0.2;
  uniforms[ "u_cmdata" ].value = cmtextures[ "viridis" ];

  const material = new THREE.ShaderMaterial( {
      uniforms: uniforms,
      vertexShader: shader.vertexShader,
      fragmentShader: shader.fragmentShader,
      side: THREE.BackSide // The volume shader uses the backface as its "reference point"
  } );

  // THREE.Mesh
  const geometry = new THREE.BoxGeometry(  dim[2], dim[1], dim[0] );
  geometry.translate(dim[2]*0.5 - 0.5, dim[1]*0.5 - 0.5, dim[0]*0.5 - 0.5 );

  const mesh = new THREE.Mesh( geometry, material );
  return mesh;
}

...

     if(isWebGL2Available()){
       let jd=new jdata(cfg.Shapes,{});
       let vol=jd.decode().data;
       boundingbox.add( drawvolume(vol.transpose()) );
     }

另一个问题:我在渲染 3D 整数数组而不是浮点数组时也遇到了麻烦。我尝试将纹理设置更新为以下内容,但它显示了一个统一的块。我怀疑我还需要编写一个新的着色器?

  const texture = new THREE.DataTexture3D( volume.selection.data, dim[2], dim[1], dim[0]);
  texture.format = THREE.RedIntegerFormat;
  texture.type = dtype[volume.dtype];
  texture.minFilter = texture.magFilter = THREE.LinearFilter;
  texture.unpackAlignment = 1;

【问题讨论】:

  • 经过几天的调试,我发现如果我将相机切换到OrthographicCamera,一切正常。但是,我想使用PerspectiveCamera 使其工作,插入camera.updateProjectionMatrix(); 没有帮助。

标签: javascript three.js textures


【解决方案1】:

我不确定我是否正确解决了您的问题。对我来说,这看起来像是材料应用的一面的问题。也许你应该在ShaderMaterial 中尝试THREE.DoubleSideTHREE.FrontSide

【讨论】:

猜你喜欢
  • 2014-05-11
  • 2013-01-12
  • 1970-01-01
  • 2013-02-09
  • 2016-12-06
  • 2015-06-17
  • 1970-01-01
  • 2016-07-03
  • 2013-01-13
相关资源
最近更新 更多