Skip to content

Commit

Permalink
WIP: Use Hounsfield scale for transfer functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mlavik1 committed Oct 16, 2023
1 parent 094b669 commit 26ad04b
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 168 deletions.
7 changes: 4 additions & 3 deletions Assets/Editor/TransferFunctionEditorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace UnityVolumeRendering
{
public class TransferFunctionEditorWindow : EditorWindow
{
private TransferFunction tf = null;
private TransferFunctionInstance tfInstance = null;

private VolumeRenderedObject volRendObject = null;

Expand Down Expand Up @@ -49,7 +49,8 @@ private void OnGUI()
if (volRendObject == null)
return;

tf = volRendObject.transferFunction;
tfInstance = volRendObject.transferFunctionInstance;
TransferFunction tf = tfInstance.transferFunction;

Event currentEvent = new Event(Event.current);

Expand All @@ -62,7 +63,7 @@ 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.SetVolumeObject(volRendObject);
tfEditor.SetTransferFunctionInstnace(tfInstance);
tfEditor.DrawOnGUI(tfEditorRect);

// Save TF
Expand Down
26 changes: 0 additions & 26 deletions Assets/Scripts/GUI/Components/DistanceMeasureTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,31 +94,5 @@ private void UpdateWindow(int windowID)

GUILayout.EndVertical();
}

private void OnLoadTransferFunction(RuntimeFileBrowser.DialogResult result)
{
if(!result.cancelled)
{
string extension = Path.GetExtension(result.path);
if(extension == ".tf")
{
TransferFunction tf = TransferFunctionDatabase.LoadTransferFunction(result.path);
if (tf != null)
{
targetObject.transferFunction = tf;
targetObject.SetTransferFunctionMode(TFRenderMode.TF1D);
}
}
if (extension == ".tf2d")
{
TransferFunction2D tf = TransferFunctionDatabase.LoadTransferFunction2D(result.path);
if (tf != null)
{
targetObject.transferFunction2D = tf;
targetObject.SetTransferFunctionMode(TFRenderMode.TF2D);
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion Assets/Scripts/GUI/Components/EditVolumeGUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private void OnLoadTransferFunction(RuntimeFileBrowser.DialogResult result)
TransferFunction tf = TransferFunctionDatabase.LoadTransferFunction(result.path);
if (tf != null)
{
targetObject.transferFunction = tf;
targetObject.SetTransferFunction(tf);
targetObject.SetTransferFunctionMode(TFRenderMode.TF1D);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace UnityVolumeRendering
public class RuntimeTransferFunctionEditor : MonoBehaviour
{
private static RuntimeTransferFunctionEditor instance = null;
private TransferFunction tf = null;
private TransferFunctionInstance tfInstance = null;
private VolumeRenderedObject volRendObject = null;

private int windowID;
Expand Down Expand Up @@ -60,15 +60,16 @@ private void UpdateWindow(int windowID)
if (volRendObject == null)
return;

tf = volRendObject.transferFunction;
tfInstance = volRendObject.transferFunctionInstance;
TransferFunction tf = tfInstance.transferFunction;

float contentWidth = Mathf.Min(WINDOW_WIDTH, (WINDOW_HEIGHT - 100.0f) * 2.0f);
float contentHeight = contentWidth * 0.5f;

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.SetVolumeObject(volRendObject);
tfEditor.SetTransferFunctionInstnace(tfInstance);
tfEditor.DrawOnGUI(tfEditorRect);

// Save TF
Expand Down Expand Up @@ -136,6 +137,7 @@ private void UpdateWindow(int windowID)
/// <param name="maxDistance">Threshold for maximum distance. Points further away than this won't get picked.</param>
private int PickColourControlPoint(float position, float maxDistance = 0.03f)
{
TransferFunction tf = tfInstance.transferFunction;
int nearestPointIndex = -1;
float nearestDist = 1000.0f;
for (int i = 0; i < tf.colourControlPoints.Count; i++)
Expand All @@ -157,6 +159,7 @@ private int PickColourControlPoint(float position, float maxDistance = 0.03f)
/// <param name="maxDistance">Threshold for maximum distance. Points further away than this won't get picked.</param>
private int PickAlphaControlPoint(Vector2 position, float maxDistance = 0.05f)
{
TransferFunction tf = tfInstance.transferFunction;
int nearestPointIndex = -1;
float nearestDist = 1000.0f;
for (int i = 0; i < tf.alphaControlPoints.Count; i++)
Expand Down
36 changes: 18 additions & 18 deletions Assets/Scripts/GUI/IMGUI/TransferFunctionEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class TransferFunctionEditor
private int movingAlphaPointIndex = -1;
private int selectedColPointIndex = -1;

private VolumeRenderedObject volRendObject = null;
private TransferFunctionInstance transferFunctionInstance = null;
private Texture2D histTex = null;

private Material tfGUIMat = null;
Expand All @@ -25,19 +25,19 @@ public void Initialise()
tfPaletteGUIMat = Resources.Load<Material>("TransferFunctionPaletteGUIMat");
}

public void SetVolumeObject(VolumeRenderedObject volRendObject)
public void SetTransferFunctionInstnace(TransferFunctionInstance tfInstance)
{
this.volRendObject = volRendObject;
this.transferFunctionInstance = tfInstance;
}

public void DrawOnGUI(Rect rect)
{
GUI.skin.button.alignment = TextAnchor.MiddleCenter;

if (volRendObject == null)
if (transferFunctionInstance == null)
return;

TransferFunction tf = volRendObject.transferFunction;
TransferFunction tf = transferFunctionInstance.transferFunction;

Event currentEvent = Event.current;

Expand All @@ -55,25 +55,25 @@ public void DrawOnGUI(Rect rect)
Rect paletteInteractionRect = new Rect(paletteRect.x - 10.0f, paletteRect.y, paletteRect.width + 30.0f, paletteRect.height);

// TODO: Don't do this every frame
tf.GenerateTexture();
transferFunctionInstance.GenerateTexture();

// Create histogram texture
if(histTex == null)
{
if(SystemInfo.supportsComputeShaders)
histTex = HistogramTextureGenerator.GenerateHistogramTextureOnGPU(volRendObject.dataset);
histTex = HistogramTextureGenerator.GenerateHistogramTextureOnGPU(transferFunctionInstance.dataset);
else
histTex = HistogramTextureGenerator.GenerateHistogramTexture(volRendObject.dataset);
histTex = HistogramTextureGenerator.GenerateHistogramTexture(transferFunctionInstance.dataset);
}

// Draw histogram
tfGUIMat.SetTexture("_TFTex", tf.GetTexture());
tfGUIMat.SetTexture("_TFTex", transferFunctionInstance.GetTexture());
tfGUIMat.SetTexture("_HistTex", histTex);
Graphics.DrawTexture(histRect, tf.GetTexture(), tfGUIMat);
Graphics.DrawTexture(histRect, transferFunctionInstance.GetTexture(), tfGUIMat);

// Draw colour palette
Texture2D tfTexture = tf.GetTexture();
tfPaletteGUIMat.SetTexture("_TFTex", tf.GetTexture());
Texture2D tfTexture = transferFunctionInstance.GetTexture();
tfPaletteGUIMat.SetTexture("_TFTex", transferFunctionInstance.GetTexture());
Graphics.DrawTexture(new Rect(paletteRect.x, paletteRect.y, paletteRect.width, paletteRect.height), tfTexture, tfPaletteGUIMat);

// Release selected colour/alpha points if mouse leaves window
Expand Down Expand Up @@ -211,7 +211,7 @@ public void ClearSelection()
public Color? GetSelectedColour()
{
if (selectedColPointIndex != -1)
return volRendObject.transferFunction.colourControlPoints[selectedColPointIndex].colourValue;
return transferFunctionInstance.transferFunction.colourControlPoints[selectedColPointIndex].colourValue;
else
return null;
}
Expand All @@ -220,17 +220,17 @@ public void SetSelectedColour(Color colour)
{
if (selectedColPointIndex != -1)
{
TFColourControlPoint colPoint = volRendObject.transferFunction.colourControlPoints[selectedColPointIndex];
TFColourControlPoint colPoint = transferFunctionInstance.transferFunction.colourControlPoints[selectedColPointIndex];
colPoint.colourValue = colour;
volRendObject.transferFunction.colourControlPoints[selectedColPointIndex] = colPoint;
transferFunctionInstance.transferFunction.colourControlPoints[selectedColPointIndex] = colPoint;
}
}

public void RemoveSelectedColour()
{
if (selectedColPointIndex != -1)
{
volRendObject.transferFunction.colourControlPoints.RemoveAt(selectedColPointIndex);
transferFunctionInstance.transferFunction.colourControlPoints.RemoveAt(selectedColPointIndex);
selectedColPointIndex = -1;
}
}
Expand All @@ -241,7 +241,7 @@ public void RemoveSelectedColour()
/// <param name="maxDistance">Threshold for maximum distance. Points further away than this won't get picked.</param>
private int PickColourControlPoint(float position, float maxDistance = 0.03f)
{
TransferFunction tf = volRendObject.transferFunction;
TransferFunction tf = transferFunctionInstance.transferFunction;
int nearestPointIndex = -1;
float nearestDist = 1000.0f;
for (int i = 0; i < tf.colourControlPoints.Count; i++)
Expand All @@ -263,7 +263,7 @@ private int PickColourControlPoint(float position, float maxDistance = 0.03f)
/// <param name="maxDistance">Threshold for maximum distance. Points further away than this won't get picked.</param>
private int PickAlphaControlPoint(Vector2 position, float maxDistance = 0.05f)
{
TransferFunction tf = volRendObject.transferFunction;
TransferFunction tf = transferFunctionInstance.transferFunction;
int nearestPointIndex = -1;
float nearestDist = 1000.0f;
for (int i = 0; i < tf.alphaControlPoints.Count; i++)
Expand Down
89 changes: 1 addition & 88 deletions Assets/Scripts/TransferFunction/TransferFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ public class TransferFunction : ScriptableObject
[SerializeField]
public List<TFAlphaControlPoint> alphaControlPoints = new List<TFAlphaControlPoint>();

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

private const int TEXTURE_WIDTH = 512;
private const int TEXTURE_HEIGHT = 2;
public bool relativeScale = false;

public void AddControlPoint(TFColourControlPoint ctrlPoint)
{
Expand All @@ -27,88 +23,5 @@ public void AddControlPoint(TFAlphaControlPoint ctrlPoint)
{
alphaControlPoints.Add(ctrlPoint);
}

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

return texture;
}

public void GenerateTexture()
{
if (texture == null)
CreateTexture();

List<TFColourControlPoint> cols = new List<TFColourControlPoint>(colourControlPoints);
List<TFAlphaControlPoint> alphas = new List<TFAlphaControlPoint>(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);

for (int iY = 0; iY < TEXTURE_HEIGHT; iY++)
{
tfCols[iX + iY * TEXTURE_WIDTH] = QualitySettings.activeColorSpace == ColorSpace.Linear ? pixCol.linear : pixCol;
}
}

texture.wrapMode = TextureWrapMode.Clamp;
texture.SetPixels(tfCols);
texture.Apply();
}

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

private void CreateTexture()
{
TextureFormat texformat = SystemInfo.SupportsTextureFormat(TextureFormat.RGBAHalf) ? TextureFormat.RGBAHalf : TextureFormat.RGBAFloat;
texture = new Texture2D(TEXTURE_WIDTH, TEXTURE_HEIGHT, texformat, false);
tfCols = new Color[TEXTURE_WIDTH * TEXTURE_HEIGHT];
}
}
}
9 changes: 4 additions & 5 deletions Assets/Scripts/TransferFunction/TransferFunctionDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ private struct TF1DSerialisationData
public int version;
public List<TFColourControlPoint> colourPoints;
public List<TFAlphaControlPoint> alphaPoints;
public bool relativeScale;

public const int VERSION_ID = 1;
public const int VERSION_ID = 2;
}

[System.Serializable]
Expand All @@ -39,7 +40,6 @@ public static TransferFunction CreateTransferFunction()
tf.AddControlPoint(new TFAlphaControlPoint(0.4f, 0.546f));
tf.AddControlPoint(new TFAlphaControlPoint(0.547f, 0.5266f));

tf.GenerateTexture();
return tf;
}

Expand All @@ -59,12 +59,10 @@ public static TransferFunction LoadTransferFunction(string filepath)
}
string jsonstring = File.ReadAllText(filepath);
TF1DSerialisationData data = JsonUtility.FromJson<TF1DSerialisationData>(jsonstring);
Debug.Log(jsonstring);
Debug.Log(data.colourPoints.ToString());
Debug.Log(data.alphaPoints.ToString());
TransferFunction tf = ScriptableObject.CreateInstance<TransferFunction>();
tf.colourControlPoints = data.colourPoints;
tf.alphaControlPoints = data.alphaPoints;
tf.relativeScale = data.version < 2 ? true : data.relativeScale;
return tf;
}

Expand All @@ -88,6 +86,7 @@ public static void SaveTransferFunction(TransferFunction tf, string filepath)
data.version = TF1DSerialisationData.VERSION_ID;
data.colourPoints = new List<TFColourControlPoint>(tf.colourControlPoints);
data.alphaPoints = new List<TFAlphaControlPoint>(tf.alphaControlPoints);
data.relativeScale = tf.relativeScale;
string jsonstring = JsonUtility.ToJson(data);
File.WriteAllText(filepath, jsonstring);
}
Expand Down
Loading

0 comments on commit 26ad04b

Please sign in to comment.