mlavik1/UnityVolumeRendering

WebGL Output error

Karthikarc115 opened this issue ยท 27 comments

Hai ,
Firstly I need to say a big thanks to you as you had helped me a lot by creating this plugin as I was all blank on from where should I start this project as I had no idea how to produce volume rendering and googled so much to find a solution and finally got this amazing plugin here ,Really appreciate you for this amazing project, keep going and do more amazing jobs like this.

I tried to use your plugin for my volume rendering project and done changes in slice rendering, cross section also Realtime rotation and zooming of object with mouse button, all works fine in Windows out and unity editor, but when run same output in webGL expect slice rendering ,File browsing and Isosurfuce button every thing works fine

When i click on the file browser I can't upload in webgl output,
and when click on isosurface and slice rendering button an error message is show that the array buffer exceeds view range

Also i had faced issues regarding the Nifti file upload as i can't able to upload in any window

Any help will be helpful as I am new to volume rendering and got stuck in this situation

1
2
3
4
5
6
7
8
9
Error in webgl

Hi!
Thank you very much for the kind words :)

File browsing:
I think the runtime file browser will probably not work in WebGL builds, since you won't have access to the file system (because it's running in a browser). I think you would need to use something like UnityWebRequest to download the file from a server, though I don't really have any experience with that myself.
By the way, how did you load the model in your screenshot? Did you import it before making the build, maybe?

NIFTI / NRRD files
NIFTI and NRRD import depends on a native plugin called SimpleITK. The SimpleITK plugin currently supports Windows, Android and (probably) MacOS, but not WebGL.
I do however have an open task for adding support for NIFTI files without SimpleITK here: #48
I'll see if I can take a look at that soon.

** texSubImage2D **
I think WebGL has some memory limitations, so you might be running out of memory.. I'm not sure what the best solution is (maybe some setting?), but could you try downscaling the dataset on import?
Either:

  • If you import it in the editor: Go to "Volume Rendering" -> "Settings" -> check "Show downscale prompt", and then click "Yes" on the message box that appears when you inport a dataset.
  • Else: Add dataset.DownScaleData(); to the beginning of the CreateObject function in VolumeObjectFactory.cs

I'll have a look and see if I can detect these issues and downscale automatically if needed.

Yes i had pre imported the volume for testing as i cant upload file from computer hdd as flie browsing is not working in webgl output

I'll try with the downscale option you have mentioned thanks for the reply

Ok, great! Hope that works for you :)

Ok, great! Hope that works for you :)

will try with this

Ok, great! Hope that works for you :)

will try with this

Great!
Also, if you pull latest version from master you should probably be able to import Nifti in WebGL as well (once you've found a way to download the dataset). I added a new importer for Nifti, that does not require any native libraries.

Ok, great! Hope that works for you :)

will try with this

Great! Also, if you pull latest version from master you should probably be able to import Nifti in WebGL as well (once you've found a way to download the dataset). I added a new importer for Nifti, that does not require any native libraries.

i had tried to import the nifti file from editor window and it works fine ,now iam tring to implement it through runtime window importing option

Ok, great! Hope that works for you :)

will try with this

Great! Also, if you pull latest version from master you should probably be able to import Nifti in WebGL as well (once you've found a way to download the dataset). I added a new importer for Nifti, that does not require any native libraries.

also i have a tried this one dataset.DownScaleData(); but still Iam getting the same error ,i will try to sort it

Hmm.. Are you able to share your dataset with me?
If so, I can try to investigate it here.

Hmm.. Are you able to share your dataset with me?
If so, I can try to investigate it here.

I can share my dicom datas but there are 241 slices

Hmm.. Are you able to share your dataset with me?
If so, I can try to investigate it here.

Could you please share me your email id so that i can share my dicom files

Need a help in this nifti file uploading script,here is my updated part,I need the nifiti file uploading file in runtime gui when we hit playbutton and need to upload nifti file like Dicom files ,i tried to do all my best but could'nt get a solution

New

private void OnOpenNIFTIDatasetResult(RuntimeFileBrowser.DialogResult result)
{
string filePath = result.path;
DatasetType datasetType = DatasetImporterUtility.GetDatasetType(filePath);
if (!result.cancelled)
{
// We'll only allow one dataset at a time in the runtime GUI (for simplicity)
DespawnAllDatasets();

            bool recursive = true;
            // Read all files
            IEnumerable<string> fileCandidates = Directory.EnumerateFiles(result.path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                .Where(p => p.EndsWith(".nii", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".NIFTI", StringComparison.InvariantCultureIgnoreCase));

            ImageFileFormat imgFileFormat;

            if (datasetType == DatasetType.NIFTI)
            {
                imgFileFormat = ImageFileFormat.NIFTI;

                IImageFileImporter importer = ImporterFactory.CreateImageFileImporter(imgFileFormat);
                VolumeDataset dataset = importer.Import(filePath);

                if (dataset != null)
                {
                    VolumeObjectFactory.CreateObject(dataset);

                }
                else
                {
                    Debug.LogError("Failed to import datset");
                }
            }
        }
    }

Hi again! Sorry for the delay.
Maybe you can send it to mlavik-unity@mailbox.org ? (that's the e-mail I use for the Unity Asset Store version).

And that code looks right, I think? Where does it fail?

Hi again! Sorry for the delay. Maybe you can send it to mlavik-unity@mailbox.org ? (that's the e-mail I use for the Unity Asset Store version).

And that code looks right, I think? Where does it fail?

Hai sorry for the delay i'll send the mail soon,

i tried to import the nifti file by flie browser,but i cant upload the nifti file directly from desktop through the file browser option but i can upload same file through editor nifti file uploading option

Hi again @Karthikarc115

So I tried importing the first DICOM dataset, and I got an error message (in the dev console) about a failed memory allocation.
Apparently Unity has a build setting that can fix this. Can you try creating a file called WebGLFix.cs and put it in "Assets/Scripts", with the following code?

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

class MyCustomBuildProcessor : IPreprocessBuildWithReport
{
    public int callbackOrder { get { return 0; } }
    public void OnPreprocessBuild(BuildReport report)
    {
        PlayerSettings.SetPropertyString("emscriptenArgs", "-s ALLOW_MEMORY_GROWTH=1", BuildTargetGroup.WebGL);
        Debug.Log("OK!");
    }
}
#endif

And then make a new build. That fixed the issue for me:
image

If you pull latest version from master, you will also be able to move the camera around in the build (using WASD keys to move, and hold right mouse button and move mouse to rotate).

And regarding your question about loading Nifti from desktop.
You can't load a file directly form desktop in WebGL. You have three options, I think:

  1. Load the dataset before build (like you already did).
  2. Upload the dataset to a website (Dropbox, Google Drive) and download it when your WebGL application is running.
  3. Implement HTML Drag and Drop API

I'm not really much of a web developer, so I don't know much about alternative (2). I found this project that apparently implemented it: https://github.com/xelfia/XELF.FileReceiver.WebGL
But it's old so it might not work anymore..
Would (2) be an alternative for you?

Thankyou so much i 'll try

And regarding your question about loading Nifti from desktop. You can't load a file directly form desktop in WebGL. You have three options, I think:

  1. Load the dataset before build (like you already did).
  2. Upload the dataset to a website (Dropbox, Google Drive) and download it when your WebGL application is running.
  3. Implement HTML Drag and Drop API

I'm not really much of a web developer, so I don't know much about alternative (2). I found this project that apparently implemented it: https://github.com/xelfia/XELF.FileReceiver.WebGL But it's old so it mig

Hai Matias I have a doubt regarding the length calculation of the rendered object when we cut it using the cross section plane if we want to calculate a particular distance inside the object how can we do it, i tried it but didn't get any output and not getting the logic behind it that's the main problem

any help would be appreciated ,hoping for the best.

Hi again @Karthikarc115 !
So if I understand you correctly, you want to pick two points relative to the volume object, and get the real distance between them?
There was a similar questions a while ago: #124
As you might have noticed, the volume gets scaled down. I'm thinking of changing this, or at least adding a setting for it.
But for now, you can remove the three / maxScale normalizations in

volObj.transform.localScale = new Vector3(dataset.scaleX / maxScale, dataset.scaleY / maxScale, dataset.scaleZ / maxScale);

Then you should be able to measure distances by just picking two points and measuring the length/magnitude between them.

Hi again @Karthikarc115 ! So if I understand you correctly, you want to pick two points relative to the volume object, and get the real distance between them? There was a similar questions a while ago: #124 As you might have noticed, the volume gets scaled down. I'm thinking of changing this, or at least adding a setting for it. But for now, you can remove the three / maxScale normalizations in

volObj.transform.localScale = new Vector3(dataset.scaleX / maxScale, dataset.scaleY / maxScale, dataset.scaleZ / maxScale);

Then you should be able to measure distances by just picking two points and measuring the length/magnitude between them.

Thank you i'll try to make changes as you mentioned

Hai Matias I have a doubt regarding the length calculation of the rendered object , i had tried to implement line rend for length calculations and iam getting values but a bit confused about the calculated values when i try to do cross section and measured length, its showing values inside the rendered object ,although iam using camera position to calculate length, but when i try to use the volume rendered object as a reference to calculate length iam not getting any results, could you please help me to sort the issue, it would be grateful for me

here iam attaching the code and screenshot too.

`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace UnityVolumeRendering
{
public class LineDrawer : MonoBehaviour
{
private VolumeRenderedObject volrend;
private LineRenderer lineRend;
private Vector2 mousePos;
private Vector2 StartMousePos;

    [SerializeField]
    private Text DistanceText;
    private float distance;
    // Start is called before the first frame update
    void Start()
    {
        lineRend = GetComponent<LineRenderer>();
        lineRend.positionCount = 2;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //Debug.Log("kitti");
            StartMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        }

        if (Input.GetMouseButton(0))
        {
            //Debug.Log("veendum");
            mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            lineRend.SetPosition(0, new Vector3(StartMousePos.x, StartMousePos.y, 0f));
            lineRend.SetPosition(1, new Vector3(mousePos.x, mousePos.y, 0f));
            distance = (mousePos - StartMousePos).magnitude;
            DistanceText.text = distance.ToString("F1") + "meters";
        }
    }

}

}
`

1
2
3
4

So in your code you are measuring the camera-space distance between two point (both on the camera), in world space.
What you instead need to do is to pick two points on the dataset and measure their distance.
For example, you could add two spheres through this menu:
image
Then place them where you want to measure, inside the dataset (might want to scale them down first).
And then measure their distance, as Vector3.Distance(sphere1.transform.position, sphere2.transform.position)

But I suppose you want to do this by clicking on the screen? That makes it a little bit more difficult, since you will need to raycast the dataset to find out where you clicked.
I'll take a look at it tomorrow or later this week to see if I can come up with something.

So in your code you are measuring the camera-space distance between two point (both on the camera), in world space.
What you instead need to do is to pick two points on the dataset and measure their distance.
For example, you could add two spheres through this menu:
image
Then place them where you want to measure, inside the dataset (might want to scale them down first).
And then measure their distance, as Vector3.Distance(sphere1.transform.position, sphere2.transform.position)

But I suppose you want to do this by clicking on the screen? That makes it a little bit more difficult, since you will need to raycast the dataset to find out where you clicked.
I'll take a look at it tomorrow or later this week to see if I can come up with something.

Thankyou i will also try to do the way you have explained

I created a separate issue fr this request: #140
Let me know if this works for you ๐Ÿ˜

I created a separate issue fr this request: #140
Let me know if this works for you ๐Ÿ˜

Thankyou i will test it

I'll close this issue since the original problem (WebGL memory issue) has been answered.
Feel free to open a new issue if there are any other issues.