Add optional Front-to-Back DVR + early ray termination

This commit is contained in:
Vahid 2022-04-06 00:05:12 +10:00
Родитель 20b6a47f1a
Коммит c5b94a0c01
3 изменённых файлов: 112 добавлений и 16 удалений

Просмотреть файл

@ -6,6 +6,7 @@ namespace UnityVolumeRendering
[CustomEditor(typeof(VolumeRenderedObject))]
public class VolumeRenderedObjectCustomInspector : Editor
{
bool otherSettings = false;
public override void OnInspectorGUI()
{
VolumeRenderedObject volrendObj = (VolumeRenderedObject)target;
@ -36,11 +37,29 @@ namespace UnityVolumeRendering
// Show TF button
if (GUILayout.Button("Edit transfer function"))
{
if(tfMode == TFRenderMode.TF1D)
if (tfMode == TFRenderMode.TF1D)
TransferFunctionEditorWindow.ShowWindow();
else
TransferFunction2DEditorWindow.ShowWindow();
}
// Other settings for direct volume rendering
if (volrendObj.GetRenderMode() == RenderMode.DirectVolumeRendering)
{
GUILayout.Space(10);
otherSettings = EditorGUILayout.Foldout(otherSettings, "Other Settings");
if (otherSettings)
{
// Temporary back-to-front rendering option
volrendObj.SetDVRBackwardEnabled(GUILayout.Toggle(volrendObj.GetDVRBackwardEnabled(), "Enable Back-to-Front Direct Volume Rendering"));
// Early ray termination for Front-to-back DVR
if (!volrendObj.GetDVRBackwardEnabled())
{
volrendObj.SetRayTerminationEnabled(GUILayout.Toggle(volrendObj.GetRayTerminationEnabled(), "Enable early ray termination"));
}
}
}
}
}
}

Просмотреть файл

@ -23,6 +23,9 @@ namespace UnityVolumeRendering
private Vector2 visibilityWindow = new Vector2(0.0f, 1.0f);
private bool rayTerminationEnabled = true;
private bool dvrBackward = true;
public SlicingPlane CreateSlicingPlane()
{
GameObject sliceRenderingPlane = GameObject.Instantiate(Resources.Load<GameObject>("SlicingPlane"));
@ -43,12 +46,12 @@ namespace UnityVolumeRendering
public void SetRenderMode(RenderMode mode)
{
if(renderMode != mode)
if (renderMode != mode)
{
renderMode = mode;
SetVisibilityWindow(0.0f, 1.0f); // reset visibility window
}
UpdateMaaterialProperties();
UpdateMaterialProperties();
}
public void SetTransferFunctionMode(TFRenderMode mode)
@ -56,9 +59,9 @@ namespace UnityVolumeRendering
tfRenderMode = mode;
if (tfRenderMode == TFRenderMode.TF1D && transferFunction != null)
transferFunction.GenerateTexture();
else if(transferFunction2D != null)
else if (transferFunction2D != null)
transferFunction2D.GenerateTexture();
UpdateMaaterialProperties();
UpdateMaterialProperties();
}
public TFRenderMode GetTransferFunctionMode()
@ -81,7 +84,7 @@ namespace UnityVolumeRendering
if (enable != lightingEnabled)
{
lightingEnabled = enable;
UpdateMaaterialProperties();
UpdateMaterialProperties();
}
}
@ -95,7 +98,7 @@ namespace UnityVolumeRendering
if (window != visibilityWindow)
{
visibilityWindow = window;
UpdateMaaterialProperties();
UpdateMaterialProperties();
}
}
@ -104,12 +107,40 @@ namespace UnityVolumeRendering
return visibilityWindow;
}
private void UpdateMaaterialProperties()
public bool GetRayTerminationEnabled()
{
return rayTerminationEnabled;
}
public void SetRayTerminationEnabled(bool enable)
{
if (enable != rayTerminationEnabled)
{
rayTerminationEnabled = enable;
UpdateMaterialProperties();
}
}
public bool GetDVRBackwardEnabled()
{
return dvrBackward;
}
public void SetDVRBackwardEnabled(bool enable)
{
if (enable != dvrBackward)
{
dvrBackward = enable;
UpdateMaterialProperties();
}
}
private void UpdateMaterialProperties()
{
bool useGradientTexture = tfRenderMode == TFRenderMode.TF2D || renderMode == RenderMode.IsosurfaceRendering || lightingEnabled;
meshRenderer.sharedMaterial.SetTexture("_GradientTex", useGradientTexture ? dataset.GetGradientTexture() : null);
if(tfRenderMode == TFRenderMode.TF2D)
if (tfRenderMode == TFRenderMode.TF2D)
{
meshRenderer.sharedMaterial.SetTexture("_TFTex", transferFunction2D.GetTexture());
meshRenderer.sharedMaterial.EnableKeyword("TF2D_ON");
@ -120,7 +151,7 @@ namespace UnityVolumeRendering
meshRenderer.sharedMaterial.DisableKeyword("TF2D_ON");
}
if(lightingEnabled)
if (lightingEnabled)
meshRenderer.sharedMaterial.EnableKeyword("LIGHTING_ON");
else
meshRenderer.sharedMaterial.DisableKeyword("LIGHTING_ON");
@ -152,11 +183,29 @@ namespace UnityVolumeRendering
meshRenderer.sharedMaterial.SetFloat("_MinVal", visibilityWindow.x);
meshRenderer.sharedMaterial.SetFloat("_MaxVal", visibilityWindow.y);
if (rayTerminationEnabled)
{
meshRenderer.sharedMaterial.EnableKeyword("RAY_TERMINATE_ON");
}
else
{
meshRenderer.sharedMaterial.DisableKeyword("RAY_TERMINATE_ON");
}
if (dvrBackward)
{
meshRenderer.sharedMaterial.EnableKeyword("DVR_BACKWARD_ON");
}
else
{
meshRenderer.sharedMaterial.DisableKeyword("DVR_BACKWARD_ON");
}
}
private void Start()
{
UpdateMaaterialProperties();
UpdateMaterialProperties();
}
}
}

Просмотреть файл

@ -26,6 +26,8 @@
#pragma multi_compile __ CUTOUT_PLANE CUTOUT_BOX_INCL CUTOUT_BOX_EXCL
#pragma multi_compile __ LIGHTING_ON
#pragma multi_compile DEPTHWRITE_ON DEPTHWRITE_OFF
#pragma multi_compile __ DVR_BACKWARD_ON
#pragma multi_compile __ RAY_TERMINATE_ON
#pragma vertex vert
#pragma fragment frag
@ -233,8 +235,13 @@
frag_out frag_dvr(frag_in i)
{
#define MAX_NUM_STEPS 512
#define OPACITY_THRESHOLD (1.0 - 1.0 / 255.0)
#ifdef DVR_BACKWARD_ON
RayInfo ray = getRayBack2Front(i.vertexLocal);
#else
RayInfo ray = getRayFront2Back(i.vertexLocal);
#endif
RaymarchInfo raymarchInfo = initRaymarch(ray, MAX_NUM_STEPS);
float3 lightDir = normalize(ObjSpaceViewDir(float4(float3(0.0f, 0.0f, 0.0f), 0.0f)));
@ -243,7 +250,11 @@
ray.startPos += (2.0f * ray.direction * raymarchInfo.stepSize) * tex2D(_NoiseTex, float2(i.uv.x, i.uv.y)).r;
float4 col = float4(0.0f, 0.0f, 0.0f, 0.0f);
float tDepth = 0.0;
#ifdef DVR_BACKWARD_ON
float tDepth = 0.0f;
#else
float tDepth = raymarchInfo.numStepsRecip * (raymarchInfo.numSteps - 1);
#endif
for (int iStep = 0; iStep < raymarchInfo.numSteps; iStep++)
{
const float t = iStep * raymarchInfo.numStepsRecip;
@ -275,16 +286,33 @@
#endif
// Apply lighting
#ifdef LIGHTING_ON
#if defined(LIGHTING_ON) && defined(DVR_BACKWARD_ON)
src.rgb = calculateLighting(src.rgb, normalize(gradient), lightDir, ray.direction, 0.3f);
#elif defined(LIGHTING_ON)
src.rgb = calculateLighting(src.rgb, normalize(gradient), lightDir, -ray.direction, 0.3f);
#endif
col.rgb = src.a * src.rgb + (1.0f - src.a)*col.rgb;
col.a = src.a + (1.0f - src.a)*col.a;
#ifdef DVR_BACKWARD_ON
col.rgb = src.a * src.rgb + (1.0f - src.a) * col.rgb;
col.a = src.a + (1.0f - src.a) * col.a;
// Optimisation: A branchless version of: if (src.a > 0.15f) tDepth = t;
tDepth = max(tDepth, t * step(0.15, src.a));
#else
src.rgb *= src.a;
col = (1.0f - col.a) * src + col;
if (src.a > 0.15 && t < tDepth) {
tDepth = t;
}
#endif
// Early ray termination
#if !defined(DVR_BACKWARD_ON) && defined(RAY_TERMINATE_ON)
if (col.a > OPACITY_THRESHOLD) {
break;
}
#endif
}
// Write fragment output