UNPKG

ami.js

Version:

<p align="center"> <img src="https://cloud.githubusercontent.com/assets/214063/23213764/78ade038-f90c-11e6-8208-4fcade5f3832.png" width="60%"> </p>

371 lines (311 loc) 11.6 kB
/* globals Stats, dat*/ import ControlsTrackball from '../../src/controls/controls.trackball'; import HelpersLut from '../../src/helpers/helpers.lut'; import LoadersVolume from '../../src/loaders/loaders.volume'; import ShadersRaycasting from '../../src/shaders/shaders.raycasting'; let glslify = require('glslify'); // standard global letiables let controls, threeD, renderer, stats, camera, sceneRTT, sceneScreen, uniformsSecondPass; let rtTexture; let lut; let ready = false; let myStack = { lut: 'walking_dead', opacity: 'linear', steps: 256, alphaCorrection: 0.5, frequence: 0, amplitude: 0 }; function onMouseDown() { if (uniformsSecondPass) { uniformsSecondPass.uSteps.value = Math.floor(myStack.steps / 2); } } function onMouseUp() { if (uniformsSecondPass) { uniformsSecondPass.uSteps.value = myStack.steps; } } function onWindowResize() { // update the camera camera.aspect = threeD.offsetWidth / threeD.offsetHeight; camera.updateProjectionMatrix(); // notify the renderer of the size change renderer.setSize(threeD.offsetWidth, threeD.offsetHeight); } function buildGUI() { let gui = new dat.GUI({ autoPlace: false }); let customContainer = document.getElementById('my-gui-container'); customContainer.appendChild(gui.domElement); let stackFolder = gui.addFolder('Settings'); let lutUpdate = stackFolder.add(myStack, 'lut', lut.lutsAvailable()); lutUpdate.onChange(function(value) { lut.lut = value; uniformsSecondPass.uTextureLUT.value.dispose(); uniformsSecondPass.uTextureLUT.value = lut.texture; }); // init LUT lut.lut = myStack.lut; uniformsSecondPass.uTextureLUT.value.dispose(); uniformsSecondPass.uTextureLUT.value = lut.texture; let opacityUpdate = stackFolder.add(myStack, 'opacity', lut.lutsAvailable('opacity')); opacityUpdate.onChange(function(value) { lut.lutO = value; uniformsSecondPass.uTextureLUT.value.dispose(); uniformsSecondPass.uTextureLUT.value = lut.texture; }); let stepsUpdate = stackFolder.add(myStack, 'steps', 0, 512).step(1); stepsUpdate.onChange(function(value) { if (uniformsSecondPass) { uniformsSecondPass.uSteps.value = value; } }); let alphaCorrrectionUpdate = stackFolder.add(myStack, 'alphaCorrection', 0, 1).step(0.01); alphaCorrrectionUpdate.onChange(function(value) { if (uniformsSecondPass) { uniformsSecondPass.uAlphaCorrection.value = value; } }); let frequenceUpdate = stackFolder.add(myStack, 'frequence', 0, 1).step(0.01); frequenceUpdate.onChange(function(value) { if (uniformsSecondPass) { uniformsSecondPass.uFrequence.value = value; } }); let amplitudeUpdate = stackFolder.add(myStack, 'amplitude', 0, 0.5).step(0.01); amplitudeUpdate.onChange(function(value) { if (uniformsSecondPass) { uniformsSecondPass.uAmplitude.value = value; } }); stackFolder.open(); } function init() { // this function is executed on each animation frame function animate() { // render controls.update(); if (ready) { renderer.render(sceneRTT, camera, rtTexture, true); renderer.render(sceneScreen, camera); } stats.update(); // request new frame requestAnimationFrame(function() { animate(); }); } // renderer threeD = document.getElementById('r3d'); renderer = new THREE.WebGLRenderer({ alpha: true }); renderer.setSize(threeD.offsetWidth, threeD.offsetHeight); threeD.appendChild(renderer.domElement); // stats stats = new Stats(); threeD.appendChild(stats.domElement); // camera camera = new THREE.PerspectiveCamera(45, threeD.offsetWidth / threeD.offsetHeight, 0.1, 100000); camera.position.x = 166; camera.position.y = -471; camera.position.z = 153; camera.up.set(-0.42, 0.86, 0.26); // controls controls = new ControlsTrackball(camera, threeD); controls.rotateSpeed = 5.5; controls.zoomSpeed = 1.2; controls.panSpeed = 0.8; controls.staticMoving = true; controls.dynamicDampingFactor = 0.3; threeD.addEventListener('mousedown', onMouseDown, false); threeD.addEventListener('mouseup', onMouseUp, false); window.addEventListener('resize', onWindowResize, false); // start rendering loop animate(); } window.onload = function() { // init threeJS init(); let t2 = [ '36444280', '36444294', '36444308', '36444322', '36444336', '36444350', '36444364', '36444378', '36444392', '36444406', '36444420', '36444434', '36444448', '36444462', '36444476', '36444490', '36444504', '36444518', '36444532', '36746856', '36746870', '36746884', '36746898', '36746912', '36746926', '36746940', '36746954', '36746968', '36746982', '36746996', '36747010', '36747024', '36748200', '36748214', '36748228', '36748270', '36748284', '36748298', '36748312', '36748326', '36748340', '36748354', '36748368', '36748382', '36748396', '36748410', '36748424', '36748438', '36748452', '36748466', '36748480', '36748494', '36748508', '36748522', '36748242', '36748256' ]; let files = t2.map(function(v) { return 'https://cdn.rawgit.com/FNNDSC/data/master/dicom/adi_brain/' + v; }); // let data = [ // 'scan-00109_rec-01a.nii_.gz' // // '7002_t1_average_BRAINSABC.nii.gz' // ]; // let files = data.map(function(v) { // return '../../data/nii/' + v; // }); // load sequence for each file // instantiate the loader // it loads and parses the dicom image // hookup a progress bar.... let loader = new LoadersVolume(threeD); let seriesContainer = []; let loadSequence = []; files.forEach((url) => { loadSequence.push( Promise.resolve() // fetch the file .then(() => loader.fetch(url)) .then((data) => loader.parse(data)) .then((series) => { seriesContainer.push(series); }) .catch(function(error) { window.console.log('oops... something went wrong...'); window.console.log(error); }) ); }); // load sequence for all files Promise .all(loadSequence) .then(() => { loader.free(); loader = null; let series = seriesContainer[0].mergeSeries(seriesContainer)[0]; // get first stack from series let stack = series.stack[0]; // prepare and pack it stack.prepare(); stack.pack(); // box is centered on 0,0,0 // we want first voxel of the box to be centered on 0,0,0 // in IJK space let boxGeometry = new THREE.BoxGeometry( stack.dimensionsIJK.x - 1, stack.dimensionsIJK.y - 1, stack.dimensionsIJK.z - 1 ); // box is centered on 0,0,0 // we want first voxel of the box to be centered on 0,0,0 // in IJK space let offset = new THREE.Vector3(-0.5, -0.5, -0.5); boxGeometry.applyMatrix(new THREE.Matrix4().makeTranslation( stack.halfDimensionsIJK.x + offset.x, stack.halfDimensionsIJK.y + offset.y, stack.halfDimensionsIJK.z + offset.z) ); // slice material let textures = []; for (let m = 0; m < stack._rawData.length; m++) { let tex = new THREE.DataTexture( stack.rawData[m], stack.textureSize, stack.textureSize, stack.textureType, THREE.UnsignedByteType, THREE.UVMapping, THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.NearestFilter); tex.needsUpdate = true; tex.flipY = true; textures.push(tex); } // Create first pass mesh, scene, and textyre to be rendered to // // material let uniformsFirstPass = ShadersRaycasting.firstPassUniforms(); uniformsFirstPass.uWorldBBox.value = stack.worldBoundingBox(); let materialFirstPass = new THREE.ShaderMaterial({ uniforms: uniformsFirstPass, vertexShader: glslify('../../src/shaders/shaders.data.vert'), fragmentShader: glslify('../../src/shaders/shaders.raycasting.firstPass.frag'), side: THREE.BackSide }); // mesh let boxMeshFirstPass = new THREE.Mesh(boxGeometry, materialFirstPass); // go the LPS space boxMeshFirstPass.applyMatrix(stack._ijk2LPS); // scene sceneRTT = new THREE.Scene(); sceneRTT.add(boxMeshFirstPass); // target texture rtTexture = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, {minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBFormat }); // Create second pass mesh and scene // // material uniformsSecondPass = ShadersRaycasting.secondPassUniforms(); uniformsSecondPass.uTextureSize.value = stack.textureSize; uniformsSecondPass.uTextureContainer.value = textures; uniformsSecondPass.uWorldToData.value = stack.lps2IJK; uniformsSecondPass.uNumberOfChannels.value = stack.numberOfChannels; uniformsSecondPass.uBitsAllocated.value = stack.bitsAllocated; uniformsSecondPass.uPackedPerPixel.value = stack.packedPerPixel; uniformsSecondPass.uWindowCenterWidth.value = [stack.windowCenter, stack.windowWidth * 0.8]; uniformsSecondPass.uRescaleSlopeIntercept.value = [stack.rescaleSlope, stack.rescaleIntercept]; uniformsSecondPass.uTextureBack.value = rtTexture; uniformsSecondPass.uWorldBBox.value = stack.worldBoundingBox(); uniformsSecondPass.uDataDimensions.value = [stack.dimensionsIJK.x, stack.dimensionsIJK.y, stack.dimensionsIJK.z]; uniformsSecondPass.uSteps.value = myStack.steps; // CREATE LUT lut = new HelpersLut('my-lut-canvases'); lut.luts = HelpersLut.presetLuts(); lut.lutsO = HelpersLut.presetLutsO(); uniformsSecondPass.uTextureLUT.value = lut.texture; uniformsSecondPass.uLut.value = 1; uniformsSecondPass.uAlphaCorrection.value = myStack.alphaCorrection; let materialSecondPass = new THREE.ShaderMaterial({ uniforms: uniformsSecondPass, vertexShader: glslify('../../src/shaders/shaders.raycasting.secondPass.vert'), fragmentShader: glslify('../../src/shaders/shaders.raycasting.secondPass.frag'), side: THREE.FrontSide, transparent: true }); // mesh let boxMeshSecondPass = new THREE.Mesh(boxGeometry, materialSecondPass); // go the LPS space boxMeshSecondPass.applyMatrix(stack._ijk2LPS); // scene sceneScreen = new THREE.Scene(); sceneScreen.add(boxMeshSecondPass); // update camrea's and interactor's target let centerLPS = stack.worldCenter(); camera.lookAt(centerLPS.x, centerLPS.y, centerLPS.z); camera.updateProjectionMatrix(); controls.target.set(centerLPS.x, centerLPS.y, centerLPS.z); buildGUI(); let screenshotElt = document.getElementById('screenshot'); screenshotElt.addEventListener('click', function() { controls.update(); if (ready) { renderer.render(sceneRTT, camera, rtTexture, true); renderer.render(sceneScreen, camera); } let screenshot = renderer.domElement.toDataURL(); screenshotElt.download = 'VJS-' + Date.now() + '.png'; screenshotElt.href = screenshot; }); // good to go ready = true; }) .catch((error) => window.console.log(error)); };