Skip to content

Commit e5fc73a

Browse files
authored
Merge pull request mlavik1#94 from vahpy/dvr-optimisation
Front-to-Back Direct Volume Rendering + Minor Performance Optimisation
2 parents 094729f + 11d279a commit e5fc73a

4 files changed

Lines changed: 117 additions & 18 deletions

File tree

Assets/Editor/VolumeRenderedObjectCustomInspector.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace UnityVolumeRendering
66
[CustomEditor(typeof(VolumeRenderedObject))]
77
public class VolumeRenderedObjectCustomInspector : Editor
88
{
9+
bool otherSettings = false;
910
public override void OnInspectorGUI()
1011
{
1112
VolumeRenderedObject volrendObj = (VolumeRenderedObject)target;
@@ -36,11 +37,29 @@ public override void OnInspectorGUI()
3637
// Show TF button
3738
if (GUILayout.Button("Edit transfer function"))
3839
{
39-
if(tfMode == TFRenderMode.TF1D)
40+
if (tfMode == TFRenderMode.TF1D)
4041
TransferFunctionEditorWindow.ShowWindow();
4142
else
4243
TransferFunction2DEditorWindow.ShowWindow();
4344
}
45+
46+
// Other settings for direct volume rendering
47+
if (volrendObj.GetRenderMode() == RenderMode.DirectVolumeRendering)
48+
{
49+
GUILayout.Space(10);
50+
otherSettings = EditorGUILayout.Foldout(otherSettings, "Other Settings");
51+
if (otherSettings)
52+
{
53+
// Temporary back-to-front rendering option
54+
volrendObj.SetDVRBackwardEnabled(GUILayout.Toggle(volrendObj.GetDVRBackwardEnabled(), "Enable Back-to-Front Direct Volume Rendering"));
55+
56+
// Early ray termination for Front-to-back DVR
57+
if (!volrendObj.GetDVRBackwardEnabled())
58+
{
59+
volrendObj.SetRayTerminationEnabled(GUILayout.Toggle(volrendObj.GetRayTerminationEnabled(), "Enable early ray termination"));
60+
}
61+
}
62+
}
4463
}
4564
}
4665
}

Assets/Scripts/VolumeObject/VolumeRenderedObject.cs

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class VolumeRenderedObject : MonoBehaviour
2323

2424
private Vector2 visibilityWindow = new Vector2(0.0f, 1.0f);
2525

26+
private bool rayTerminationEnabled = true;
27+
private bool dvrBackward = true;
28+
2629
public SlicingPlane CreateSlicingPlane()
2730
{
2831
GameObject sliceRenderingPlane = GameObject.Instantiate(Resources.Load<GameObject>("SlicingPlane"));
@@ -43,22 +46,22 @@ public SlicingPlane CreateSlicingPlane()
4346

4447
public void SetRenderMode(RenderMode mode)
4548
{
46-
if(renderMode != mode)
49+
if (renderMode != mode)
4750
{
4851
renderMode = mode;
4952
SetVisibilityWindow(0.0f, 1.0f); // reset visibility window
5053
}
51-
UpdateMaaterialProperties();
54+
UpdateMaterialProperties();
5255
}
5356

5457
public void SetTransferFunctionMode(TFRenderMode mode)
5558
{
5659
tfRenderMode = mode;
5760
if (tfRenderMode == TFRenderMode.TF1D && transferFunction != null)
5861
transferFunction.GenerateTexture();
59-
else if(transferFunction2D != null)
62+
else if (transferFunction2D != null)
6063
transferFunction2D.GenerateTexture();
61-
UpdateMaaterialProperties();
64+
UpdateMaterialProperties();
6265
}
6366

6467
public TFRenderMode GetTransferFunctionMode()
@@ -81,7 +84,7 @@ public void SetLightingEnabled(bool enable)
8184
if (enable != lightingEnabled)
8285
{
8386
lightingEnabled = enable;
84-
UpdateMaaterialProperties();
87+
UpdateMaterialProperties();
8588
}
8689
}
8790

@@ -95,7 +98,7 @@ public void SetVisibilityWindow(Vector2 window)
9598
if (window != visibilityWindow)
9699
{
97100
visibilityWindow = window;
98-
UpdateMaaterialProperties();
101+
UpdateMaterialProperties();
99102
}
100103
}
101104

@@ -104,12 +107,40 @@ public Vector2 GetVisibilityWindow()
104107
return visibilityWindow;
105108
}
106109

107-
private void UpdateMaaterialProperties()
110+
public bool GetRayTerminationEnabled()
111+
{
112+
return rayTerminationEnabled;
113+
}
114+
115+
public void SetRayTerminationEnabled(bool enable)
116+
{
117+
if (enable != rayTerminationEnabled)
118+
{
119+
rayTerminationEnabled = enable;
120+
UpdateMaterialProperties();
121+
}
122+
}
123+
124+
public bool GetDVRBackwardEnabled()
125+
{
126+
return dvrBackward;
127+
}
128+
129+
public void SetDVRBackwardEnabled(bool enable)
130+
{
131+
if (enable != dvrBackward)
132+
{
133+
dvrBackward = enable;
134+
UpdateMaterialProperties();
135+
}
136+
}
137+
138+
private void UpdateMaterialProperties()
108139
{
109140
bool useGradientTexture = tfRenderMode == TFRenderMode.TF2D || renderMode == RenderMode.IsosurfaceRendering || lightingEnabled;
110141
meshRenderer.sharedMaterial.SetTexture("_GradientTex", useGradientTexture ? dataset.GetGradientTexture() : null);
111142

112-
if(tfRenderMode == TFRenderMode.TF2D)
143+
if (tfRenderMode == TFRenderMode.TF2D)
113144
{
114145
meshRenderer.sharedMaterial.SetTexture("_TFTex", transferFunction2D.GetTexture());
115146
meshRenderer.sharedMaterial.EnableKeyword("TF2D_ON");
@@ -120,7 +151,7 @@ private void UpdateMaaterialProperties()
120151
meshRenderer.sharedMaterial.DisableKeyword("TF2D_ON");
121152
}
122153

123-
if(lightingEnabled)
154+
if (lightingEnabled)
124155
meshRenderer.sharedMaterial.EnableKeyword("LIGHTING_ON");
125156
else
126157
meshRenderer.sharedMaterial.DisableKeyword("LIGHTING_ON");
@@ -152,11 +183,29 @@ private void UpdateMaaterialProperties()
152183

153184
meshRenderer.sharedMaterial.SetFloat("_MinVal", visibilityWindow.x);
154185
meshRenderer.sharedMaterial.SetFloat("_MaxVal", visibilityWindow.y);
186+
187+
if (rayTerminationEnabled)
188+
{
189+
meshRenderer.sharedMaterial.EnableKeyword("RAY_TERMINATE_ON");
190+
}
191+
else
192+
{
193+
meshRenderer.sharedMaterial.DisableKeyword("RAY_TERMINATE_ON");
194+
}
195+
196+
if (dvrBackward)
197+
{
198+
meshRenderer.sharedMaterial.EnableKeyword("DVR_BACKWARD_ON");
199+
}
200+
else
201+
{
202+
meshRenderer.sharedMaterial.DisableKeyword("DVR_BACKWARD_ON");
203+
}
155204
}
156205

157206
private void Start()
158207
{
159-
UpdateMaaterialProperties();
208+
UpdateMaterialProperties();
160209
}
161210
}
162211
}

Assets/Shaders/DirectVolumeRenderingShader.shader

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#pragma multi_compile __ CUTOUT_PLANE CUTOUT_BOX_INCL CUTOUT_BOX_EXCL
2727
#pragma multi_compile __ LIGHTING_ON
2828
#pragma multi_compile DEPTHWRITE_ON DEPTHWRITE_OFF
29+
#pragma multi_compile __ DVR_BACKWARD_ON
30+
#pragma multi_compile __ RAY_TERMINATE_ON
2931
#pragma vertex vert
3032
#pragma fragment frag
3133

@@ -233,8 +235,13 @@
233235
frag_out frag_dvr(frag_in i)
234236
{
235237
#define MAX_NUM_STEPS 512
238+
#define OPACITY_THRESHOLD (1.0 - 1.0 / 255.0)
236239

240+
#ifdef DVR_BACKWARD_ON
237241
RayInfo ray = getRayBack2Front(i.vertexLocal);
242+
#else
243+
RayInfo ray = getRayFront2Back(i.vertexLocal);
244+
#endif
238245
RaymarchInfo raymarchInfo = initRaymarch(ray, MAX_NUM_STEPS);
239246

240247
float3 lightDir = normalize(ObjSpaceViewDir(float4(float3(0.0f, 0.0f, 0.0f), 0.0f)));
@@ -243,7 +250,11 @@
243250
ray.startPos += (2.0f * ray.direction * raymarchInfo.stepSize) * tex2D(_NoiseTex, float2(i.uv.x, i.uv.y)).r;
244251

245252
float4 col = float4(0.0f, 0.0f, 0.0f, 0.0f);
246-
float tDepth = 0.0;
253+
#ifdef DVR_BACKWARD_ON
254+
float tDepth = 0.0f;
255+
#else
256+
float tDepth = raymarchInfo.numStepsRecip * (raymarchInfo.numSteps - 1);
257+
#endif
247258
for (int iStep = 0; iStep < raymarchInfo.numSteps; iStep++)
248259
{
249260
const float t = iStep * raymarchInfo.numStepsRecip;
@@ -258,6 +269,9 @@
258269
// Get the dansity/sample value of the current position
259270
const float density = getDensity(currPos);
260271

272+
// Apply visibility window
273+
if (density < _MinVal || density > _MaxVal) continue;
274+
261275
// Calculate gradient (needed for lighting and 2D transfer functions)
262276
#if defined(TF2D_ON) || defined(LIGHTING_ON)
263277
float3 gradient = getGradient(currPos);
@@ -272,18 +286,33 @@
272286
#endif
273287

274288
// Apply lighting
275-
#ifdef LIGHTING_ON
289+
#if defined(LIGHTING_ON) && defined(DVR_BACKWARD_ON)
276290
src.rgb = calculateLighting(src.rgb, normalize(gradient), lightDir, ray.direction, 0.3f);
291+
#elif defined(LIGHTING_ON)
292+
src.rgb = calculateLighting(src.rgb, normalize(gradient), lightDir, -ray.direction, 0.3f);
277293
#endif
278294

279-
// Optimisation: A branchless version of: if (density < _MinVal || density > _MaxVal) src.a = 0.0f;
280-
src.a *= step(_MinVal, density) * step(density, _MaxVal);
281-
282-
col.rgb = src.a * src.rgb + (1.0f - src.a)*col.rgb;
283-
col.a = src.a + (1.0f - src.a)*col.a;
295+
#ifdef DVR_BACKWARD_ON
296+
col.rgb = src.a * src.rgb + (1.0f - src.a) * col.rgb;
297+
col.a = src.a + (1.0f - src.a) * col.a;
284298

285299
// Optimisation: A branchless version of: if (src.a > 0.15f) tDepth = t;
286300
tDepth = max(tDepth, t * step(0.15, src.a));
301+
#else
302+
src.rgb *= src.a;
303+
col = (1.0f - col.a) * src + col;
304+
305+
if (src.a > 0.15 && t < tDepth) {
306+
tDepth = t;
307+
}
308+
#endif
309+
310+
// Early ray termination
311+
#if !defined(DVR_BACKWARD_ON) && defined(RAY_TERMINATE_ON)
312+
if (col.a > OPACITY_THRESHOLD) {
313+
break;
314+
}
315+
#endif
287316
}
288317

289318
// Write fragment output

CREDITS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ Image sequence import. Other contributions.
1212
GUI for modifying slicing plane positiomn/orientation.
1313
- [btsai-dev](https://github.com/btsai-dev)
1414
Memory leak fix
15+
- [Vahid](https://github.com/vahpy)
16+
Texture downscaling, optimisation.
1517

1618
Feel free to add yourself to this list when contributing to this project.

0 commit comments

Comments
 (0)