Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mlavik1 committed Sep 7, 2024
1 parent 4c4efa1 commit b27c3ed
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 31 deletions.
53 changes: 46 additions & 7 deletions Assets/Editor/TransferFunctionEditorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@ namespace UnityVolumeRendering
{
public class TransferFunctionEditorWindow : EditorWindow
{
private enum TFEditorTarget
{
Volume,
VolumeAndTF,
TFOnly
}

private TransferFunction tf = null;

private VolumeRenderedObject volRendObject = null;

private TransferFunctionEditor tfEditor = new TransferFunctionEditor();

private bool keepTf = false;
private TFEditorTarget targetType = TFEditorTarget.Volume;

public static void ShowWindow(VolumeRenderedObject volRendObj)
{
Expand All @@ -23,6 +30,7 @@ public static void ShowWindow(VolumeRenderedObject volRendObj)
TransferFunctionEditorWindow wnd = (TransferFunctionEditorWindow)EditorWindow.GetWindow(typeof(TransferFunctionEditorWindow));
if (volRendObj)
wnd.volRendObject = volRendObj;
wnd.targetType = TFEditorTarget.Volume;
wnd.Show();
wnd.SetInitialPosition();
}
Expand All @@ -37,9 +45,31 @@ public static void ShowWindow(VolumeRenderedObject volRendObj, TransferFunction
TransferFunctionEditorWindow wnd = (TransferFunctionEditorWindow)EditorWindow.GetWindow(typeof(TransferFunctionEditorWindow));
wnd.volRendObject = volRendObj;
wnd.tf = transferFunction;
wnd.keepTf = true;
wnd.targetType = TFEditorTarget.VolumeAndTF;
wnd.Show();
wnd.SetInitialPosition();
}

public static TransferFunctionEditorWindow ShowWindow(TransferFunction transferFunction)
{
// Close all (if any) 2D TF editor windows
TransferFunction2DEditorWindow[] tf2dWnds = Resources.FindObjectsOfTypeAll<TransferFunction2DEditorWindow>();
foreach (TransferFunction2DEditorWindow tf2dWnd in tf2dWnds)
tf2dWnd.Close();

TransferFunctionEditorWindow wnd = (TransferFunctionEditorWindow)EditorWindow.GetWindow(typeof(TransferFunctionEditorWindow));
wnd.volRendObject = null;
wnd.tf = transferFunction;
wnd.targetType = TFEditorTarget.TFOnly;
wnd.Show();
wnd.SetInitialPosition();
return wnd;
}

public void SetHorizontalZoom(float min, float max)
{
tfEditor.zoomRect.x = min;
tfEditor.zoomRect.width = max - min;
}

private void SetInitialPosition()
Expand All @@ -60,13 +90,16 @@ private void OnGUI()
wantsMouseEnterLeaveWindow = true;

// Update selected object
if (volRendObject == null)
if (targetType == TFEditorTarget.Volume && volRendObject == null)
{
volRendObject = SelectionHelper.GetSelectedVolumeObject();
tf = volRendObject.transferFunction;
}

if (volRendObject == null)
if (volRendObject == null && tf == null)
return;

if (!keepTf)
if (targetType == TFEditorTarget.Volume)
tf = volRendObject.transferFunction;

Event currentEvent = new Event(Event.current);
Expand All @@ -80,7 +113,13 @@ private void OnGUI()
Rect outerRect = new Rect(0.0f, 0.0f, contentWidth, contentHeight);
Rect tfEditorRect = new Rect(outerRect.x + 20.0f, outerRect.y + 20.0f, outerRect.width - 40.0f, outerRect.height - 50.0f);

tfEditor.SetTarget(volRendObject.dataset, tf);
if (targetType == TFEditorTarget.Volume)
tfEditor.SetTarget(volRendObject);
else if(targetType == TFEditorTarget.VolumeAndTF)
tfEditor.SetTarget(volRendObject.dataset, tf);
else
tfEditor.SetTarget(tf);

tfEditor.DrawOnGUI(tfEditorRect);

// Draw horizontal zoom slider
Expand Down Expand Up @@ -152,7 +191,7 @@ private void OnGUI()
GUI.Label(new Rect(tfEditorRect.x, tfEditorRect.y + tfEditorRect.height + 55.0f, 720.0f, 50.0f), "Left click to select and move a control point.\nRight click to add a control point, and ctrl + right click to delete.");

float tDataPos = (currentEvent.mousePosition.x - tfEditorRect.x) / tfEditorRect.width;
if (tDataPos >= 0.0f && tDataPos <= 1.0f)
if (volRendObject != null && tDataPos >= 0.0f && tDataPos <= 1.0f)
{
float dataValue = Mathf.Lerp(volRendObject.dataset.GetMinDataValue(), volRendObject.dataset.GetMaxDataValue(), tDataPos);
GUI.Label(new Rect(tfEditorRect.x, tfEditorRect.y + tfEditorRect.height + 100.0f, 150.0f, 50.0f), $"Data value: {dataValue}");
Expand Down
27 changes: 20 additions & 7 deletions Assets/Editor/VolumeRenderedObjectCustomInspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,28 @@ public override void OnInspectorGUI()
for (int i = 0; i < segmentationLabels.Count; i++)
{
EditorGUILayout.BeginHorizontal();
SegmentationLabel segmentationlabel = segmentationLabels[i];
EditorGUI.BeginChangeCheck();
segmentationlabel.name = EditorGUILayout.TextField(segmentationlabel.name);
segmentationlabel.colour = EditorGUILayout.ColorField(segmentationlabel.colour);
bool changed = EditorGUI.EndChangeCheck();
segmentationLabels[i] = segmentationlabel;
SegmentationLabel segmentationLabel = segmentationLabels[i];
segmentationLabel.name = EditorGUILayout.TextField(segmentationLabel.name);
segmentationLabel.colour = EditorGUILayout.ColorField(segmentationLabel.colour);
if (GUILayout.Button("TF"))
{
if (segmentationLabel.transferFunction == null)
segmentationLabel.transferFunction = ScriptableObject.CreateInstance<TransferFunction>();
segmentationLabel.transferFunction.onUpdate = volrendObj.UpdateSegmentationLabels;
float zoomMin = Mathf.InverseLerp(volrendObj.dataset.GetMinDataValue(), volrendObj.dataset.GetMaxDataValue(), segmentationLabel.minDataValue);
float zoomMax = Mathf.InverseLerp(volrendObj.dataset.GetMinDataValue(), volrendObj.dataset.GetMaxDataValue(), segmentationLabel.maxDataValue);
TransferFunctionEditorWindow wnd = TransferFunctionEditorWindow.ShowWindow(segmentationLabel.transferFunction);
wnd.SetHorizontalZoom(zoomMin, zoomMax);
}
if (segmentationLabel.colour != segmentationLabels[i].colour)
segmentationLabel.transferFunction = null;
bool changed = segmentationLabel.colour != segmentationLabels[i].colour
|| segmentationLabel.name != segmentationLabels[i].name
|| segmentationLabel.transferFunction != segmentationLabels[i].transferFunction;
segmentationLabels[i] = segmentationLabel;
if (GUILayout.Button("delete"))
{
volrendObj.RemoveSegmentation(segmentationlabel.id);
volrendObj.RemoveSegmentation(segmentationLabel.id);
}
EditorGUILayout.EndHorizontal();
if (changed)
Expand Down
11 changes: 9 additions & 2 deletions Assets/Scripts/GUI/IMGUI/TransferFunctionEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ public void SetTarget(VolumeDataset dataset, TransferFunction transferFunction)
this.transferFunction = transferFunction;
}

public void SetTarget(TransferFunction transferFunction)
{
this.targetObject = null;
this.dataset = null;
this.transferFunction = transferFunction;
}

public void DrawOnGUI(Rect rect)
{
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
Expand All @@ -61,7 +68,7 @@ public void DrawOnGUI(Rect rect)
transferFunction = targetObject.transferFunction;
}

if (dataset == null || transferFunction == null)
if (transferFunction == null)
{
return;
}
Expand Down Expand Up @@ -90,7 +97,7 @@ public void DrawOnGUI(Rect rect)
tf.GenerateTexture();

// Create histogram texture
if(histTex == null)
if(histTex == null && dataset != null)
{
if(SystemInfo.supportsComputeShaders)
histTex = HistogramTextureGenerator.GenerateHistogramTextureOnGPU(dataset);
Expand Down
3 changes: 3 additions & 0 deletions Assets/Scripts/Segmentation/SegmentationLabel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ public struct SegmentationLabel
public int id;
public string name;
public Color colour;
public TransferFunction transferFunction;
public float minDataValue;
public float maxDataValue;
}
}
124 changes: 124 additions & 0 deletions Assets/Scripts/Segmentation/SegmentationTransferFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Runtime.InteropServices.WindowsRuntime;

namespace UnityVolumeRendering
{
[Serializable]
public class SegmentationTransferFunction : TransferFunction
{
private Texture2D texture = null;
private Color[] textureColours;
List<SegmentationLabel> segmentationLabels = new List<SegmentationLabel>();

private const int TEXTURE_WIDTH = 1024;

public void SetSegmentationLabels(List<SegmentationLabel> labels)
{
this.segmentationLabels = labels;
GenerateTexture();
}

public override void AddControlPoint(TFColourControlPoint ctrlPoint)
{
}

public override void AddControlPoint(TFAlphaControlPoint ctrlPoint)
{
}

public override Texture2D GetTexture()
{
if (texture == null)
GenerateTexture();

return texture;
}

public override void GenerateTexture()
{

textureColours = new Color[TEXTURE_WIDTH * segmentationLabels.Count];

for (int iSegmentation = 0; iSegmentation < segmentationLabels.Count; iSegmentation++)
{
SegmentationLabel segmentationLabel = segmentationLabels[iSegmentation];

if (segmentationLabel.transferFunction == null)
{
for (int i = 0; i < TEXTURE_WIDTH; i++)
{
textureColours[i + iSegmentation * TEXTURE_WIDTH] = segmentationLabel.colour;
}
}
else
{
TransferFunction tf = segmentationLabel.transferFunction;
List<TFColourControlPoint> cols = new List<TFColourControlPoint>(tf.colourControlPoints);
List<TFAlphaControlPoint> alphas = new List<TFAlphaControlPoint>(tf.alphaControlPoints);

// Sort lists of control points
cols.Sort((a, b) => (a.dataValue.CompareTo(b.dataValue)));
alphas.Sort((a, b) => (a.dataValue.CompareTo(b.dataValue)));

// Add colour points at beginning and end
if (cols.Count == 0 || cols[cols.Count - 1].dataValue < 1.0f)
cols.Add(new TFColourControlPoint(1.0f, Color.white));
if (cols[0].dataValue > 0.0f)
cols.Insert(0, new TFColourControlPoint(0.0f, Color.white));

// Add alpha points at beginning and end
if (alphas.Count == 0 || alphas[alphas.Count - 1].dataValue < 1.0f)
alphas.Add(new TFAlphaControlPoint(1.0f, 1.0f));
if (alphas[0].dataValue > 0.0f)
alphas.Insert(0, new TFAlphaControlPoint(0.0f, 0.0f));

int numColours = cols.Count;
int numAlphas = alphas.Count;
int iCurrColour = 0;
int iCurrAlpha = 0;

for (int iX = 0; iX < TEXTURE_WIDTH; iX++)
{
float t = iX / (float)(TEXTURE_WIDTH - 1);
while (iCurrColour < numColours - 2 && cols[iCurrColour + 1].dataValue < t)
iCurrColour++;
while (iCurrAlpha < numAlphas - 2 && alphas[iCurrAlpha + 1].dataValue < t)
iCurrAlpha++;

TFColourControlPoint leftCol = cols[iCurrColour];
TFColourControlPoint rightCol = cols[iCurrColour + 1];
TFAlphaControlPoint leftAlpha = alphas[iCurrAlpha];
TFAlphaControlPoint rightAlpha = alphas[iCurrAlpha + 1];

float tCol = (Mathf.Clamp(t, leftCol.dataValue, rightCol.dataValue) - leftCol.dataValue) / (rightCol.dataValue - leftCol.dataValue);
float tAlpha = (Mathf.Clamp(t, leftAlpha.dataValue, rightAlpha.dataValue) - leftAlpha.dataValue) / (rightAlpha.dataValue - leftAlpha.dataValue);

tCol = Mathf.SmoothStep(0.0f, 1.0f, tCol);
tAlpha = Mathf.SmoothStep(0.0f, 1.0f, tAlpha);

Color pixCol = rightCol.colourValue * tCol + leftCol.colourValue * (1.0f - tCol);
pixCol.a = rightAlpha.alphaValue * tAlpha + leftAlpha.alphaValue * (1.0f - tAlpha);

textureColours[iX + iSegmentation * TEXTURE_WIDTH] = QualitySettings.activeColorSpace == ColorSpace.Linear ? pixCol.linear : pixCol;
}
}
}
if (texture == null || texture.height != segmentationLabels.Count)
{
TextureFormat texformat = SystemInfo.SupportsTextureFormat(TextureFormat.RGBAHalf) ? TextureFormat.RGBAHalf : TextureFormat.RGBAFloat;
texture = new Texture2D(TEXTURE_WIDTH, segmentationLabels.Count, texformat, false);
texture.wrapMode = TextureWrapMode.Clamp;
texture.filterMode = FilterMode.Point;
}
texture.SetPixels(textureColours);
texture.Apply();
}

public override Color GetColour(float x)
{
return Color.black;
}
}
}
15 changes: 10 additions & 5 deletions Assets/Scripts/TransferFunction/TransferFunction.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using UnityEngine;
using System.Collections.Generic;
using System;
using UnityEngine.Events;

namespace UnityVolumeRendering
{
Expand All @@ -12,31 +13,33 @@ public class TransferFunction : ScriptableObject
[SerializeField]
public List<TFAlphaControlPoint> alphaControlPoints = new List<TFAlphaControlPoint>();

public UnityAction onUpdate;

private Texture2D texture = null;
private Color[] tfCols;

private const int TEXTURE_WIDTH = 1024;
private const int TEXTURE_HEIGHT = 2;

public void AddControlPoint(TFColourControlPoint ctrlPoint)
public virtual void AddControlPoint(TFColourControlPoint ctrlPoint)
{
colourControlPoints.Add(ctrlPoint);
}

public void AddControlPoint(TFAlphaControlPoint ctrlPoint)
public virtual void AddControlPoint(TFAlphaControlPoint ctrlPoint)
{
alphaControlPoints.Add(ctrlPoint);
}

public Texture2D GetTexture()
public virtual Texture2D GetTexture()
{
if (texture == null)
GenerateTexture();

return texture;
}

public void GenerateTexture()
public virtual void GenerateTexture()
{
if (texture == null)
CreateTexture();
Expand Down Expand Up @@ -96,9 +99,11 @@ public void GenerateTexture()
texture.wrapMode = TextureWrapMode.Clamp;
texture.SetPixels(tfCols);
texture.Apply();

onUpdate?.Invoke();
}

public Color GetColour(float x)
public virtual Color GetColour(float x)
{
int index = Mathf.RoundToInt(x * TEXTURE_WIDTH);
return tfCols[index];
Expand Down
Loading

0 comments on commit b27c3ed

Please sign in to comment.