Three.js: 3D-текстура MIP глубина вырезания лица при использовании перспективной камеры

#javascript #three.js #textures

Вопрос:

Я работаю над веб-графическим интерфейсом, используя three.js для одного из моих световых симуляторов. Графический интерфейс требует рендеринга 3D-объема (целых чисел или с плавающей точкой), поэтому я адаптировал демонстрационный сценарий 3D-текстуры и создал тестовую страницу.

После некоторой настройки я смог отобразить 3D — текстуру в стиле MIP, но на дисплее, похоже, возникли некоторые проблемы с правильной визуализацией глубины-некоторые грани ограничивающего прямоугольника могут исчезнуть под определенными углами камеры и сделать визуализацию неточной.

На приведенном ниже снимке экрана показана проблема. Текстура представляет собой объем 40x20x30 с двумя z-слоями: значение 1,0 для 0<z<20 и значение 2,0 для 20<z

неправильный рендеринг текстур

Как вы можете видеть на приведенном выше скриншоте, рендеринг MIP в порядке под левым углом обзора, но начинает показывать неровные границы (или отсутствующие грани bbx) под большинством других углов, показанных справа.

Вы можете увидеть это сами, перейдя по ссылке ниже

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

чтобы ввести этот том, пожалуйста, перейдите на вкладку «JSON», удалите существующий текст и скопируйте/вставьте приведенные ниже данные JSON (как вы можете видеть, объект «Фигуры» определяет объем 3D с использованием формата массива JData ND и декодируется в объект 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
      }
    ]
  }
}
 

My script was largely adapted from the 3d texture demo. I tried to add transparent: true, opacity: 0.6, alphaTest: 0.5, depthWrite: false to the material setting, but it did not make any difference.

Потому что мои данные представляют собой тот же массив 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;
 

Комментарии:

1. Потратив несколько дней на отладку этого, я обнаружил , что если я переключу камеру на an OrthographicCamera , все будет работать нормально. Однако я хотел бы, чтобы это работало с помощью a PerspectiveCamera , вставка camera.updateProjectionMatrix(); не помогает.

Ответ №1:

Я не уверен, правильно ли я понял вашу проблему. Для меня это выглядит как проблема с той стороной, на которую наносится материал. Может быть, тебе стоит попробовать THREE.DoubleSide или THREE.FrontSide в самом ShaderMaterial .

Комментарии:

1. эти ТРОЕ. Установка материала задней стороны произошла от three.js демонстрация 3d -текстуры threejs.org/examples/webgl2_materials_texture3d.html, Я также изменил его на двустороннюю/переднюю сторону, но это ничего не изменило. Опять же, проблема вызвана использованием камеры perspectivecamera.