using System.
Threading;
using [Link];
using UnityEditor;
using UnityEngine;
namespace UnityVolumeRendering
{
[ExecuteInEditMode]
public class VolumeRenderedObject : MonoBehaviour
{
[SerializeField, HideInInspector]
public TransferFunction transferFunction;
[SerializeField, HideInInspector]
public TransferFunction2D transferFunction2D;
[SerializeField, HideInInspector]
public VolumeDataset dataset;
[SerializeField, HideInInspector]
public MeshRenderer meshRenderer;
[SerializeField, HideInInspector]
public GameObject volumeContainerObject;
[SerializeField, HideInInspector]
private RenderMode renderMode;
[SerializeField, HideInInspector]
private TFRenderMode tfRenderMode;
[SerializeField, HideInInspector]
private bool lightingEnabled;
[SerializeField, HideInInspector]
private LightSource lightSource;
[SerializeField, HideInInspector]
private Vector2 visibilityWindow = new Vector2(0.0f, 1.0f);
[SerializeField, HideInInspector]
private bool rayTerminationEnabled = true;
[SerializeField, HideInInspector]
private bool cubicInterpolationEnabled = false;
private CrossSectionManager crossSectionManager;
private SemaphoreSlim updateMatLock = new SemaphoreSlim(1, 1);
public SlicingPlane CreateSlicingPlane()
{
GameObject sliceRenderingPlane =
[Link]([Link]<GameObject>("SlicingPlane"));
[Link] =
[Link];
[Link] = [Link];
[Link] = [Link];
[Link] = [Link] * 0.1f; // TODO:
Change the plane mesh instead and use [Link]
MeshRenderer sliceMeshRend =
[Link]<MeshRenderer>();
[Link] = new Material([Link]);
Material sliceMat =
[Link]<MeshRenderer>().sharedMaterial;
[Link]("_DataTex", [Link]());
[Link]("_TFTex", [Link]());
[Link]("_parentInverseMat", [Link]);
[Link]("_planeMat",
[Link]([Link],
[Link], [Link])); // TODO: allow
changing scale
SlicingPlane slicingPlaneComp =
[Link]<SlicingPlane>();
[Link] = this;
return slicingPlaneComp;
}
public void SetRenderMode(RenderMode mode)
{
Task task = SetRenderModeAsync(mode);
}
public async Task SetRenderModeAsync(RenderMode mode, IProgressHandler
progressHandler = null)
{
if (renderMode != mode)
{
renderMode = mode;
SetVisibilityWindow(0.0f, 1.0f); // reset visibility window
}
await UpdateMaterialPropertiesAsync(progressHandler);
}
public void SetTransferFunctionMode(TFRenderMode mode)
{
Task task = SetTransferFunctionModeAsync(mode);
}
public async Task SetTransferFunctionModeAsync(TFRenderMode mode,
IProgressHandler progressHandler = null)
{
if (progressHandler == null)
progressHandler = [Link];
[Link](0.3f, "Generating transfer function
texture");
tfRenderMode = mode;
if (tfRenderMode == TFRenderMode.TF1D && transferFunction != null)
[Link]();
else if (transferFunction2D != null)
[Link]();
[Link]();
[Link](0.7f, "Updating material properties");
await UpdateMaterialPropertiesAsync(progressHandler);
[Link]();
}
public TFRenderMode GetTransferFunctionMode()
{
return tfRenderMode;
}
public RenderMode GetRenderMode()
{
return renderMode;
}
public bool GetLightingEnabled()
{
return lightingEnabled;
}
public LightSource GetLightSource()
{
return lightSource;
}
public CrossSectionManager GetCrossSectionManager()
{
if (crossSectionManager == null)
crossSectionManager = GetComponent<CrossSectionManager>();
if (crossSectionManager == null)
crossSectionManager =
[Link]<CrossSectionManager>();
return crossSectionManager;
}
public void SetLightingEnabled(bool enable)
{
if (enable != lightingEnabled)
{
lightingEnabled = enable;
UpdateMaterialProperties();
}
}
public async Task SetLightingEnabledAsync(bool enable, IProgressHandler
progressHandler = null)
{
if (enable != lightingEnabled)
{
lightingEnabled = enable;
await UpdateMaterialPropertiesAsync(progressHandler);
}
}
public void SetLightSource(LightSource source)
{
lightSource = source;
UpdateMaterialProperties();
}
public void SetVisibilityWindow(float min, float max)
{
SetVisibilityWindow(new Vector2(min, max));
}
public void SetVisibilityWindow(Vector2 window)
{
if (window != visibilityWindow)
{
visibilityWindow = window;
UpdateMaterialProperties();
}
}
public Vector2 GetVisibilityWindow()
{
return visibilityWindow;
}
public bool GetRayTerminationEnabled()
{
return rayTerminationEnabled;
}
public void SetRayTerminationEnabled(bool enable)
{
if (enable != rayTerminationEnabled)
{
rayTerminationEnabled = enable;
UpdateMaterialProperties();
}
}
[[Link]("Back-to-front rendering no longer supported")]
public bool GetDVRBackwardEnabled()
{
return false;
}
[[Link]("Back-to-front rendering no longer supported")]
public void SetDVRBackwardEnabled(bool enable)
{
[Link]("Back-to-front rendering no longer supported");
}
public bool GetCubicInterpolationEnabled()
{
return cubicInterpolationEnabled;
}
public void SetCubicInterpolationEnabled(bool enable)
{
if (enable != cubicInterpolationEnabled)
{
cubicInterpolationEnabled = enable;
UpdateMaterialProperties();
}
}
public void SetTransferFunction(TransferFunction tf)
{
[Link] = tf;
UpdateMaterialProperties();
}
public async Task SetTransferFunctionAsync(TransferFunction tf,
IProgressHandler progressHandler = null)
{
if ([Link] == null)
{
[Link] = new
Material([Link]("VolumeRendering/DirectVolumeRenderingShader"));
[Link]("_DataTex",
[Link]());
}
if (transferFunction == null)
{
transferFunction =
[Link]();
}
[Link] = tf;
await UpdateMaterialPropertiesAsync(progressHandler);
}
private void UpdateMaterialProperties(IProgressHandler progressHandler =
null)
{
Task task = UpdateMaterialPropertiesAsync(progressHandler);
}
private async Task UpdateMaterialPropertiesAsync(IProgressHandler
progressHandler = null)
{
await [Link]();
try
{
bool useGradientTexture = tfRenderMode == TFRenderMode.TF2D ||
renderMode == [Link] || lightingEnabled;
Texture3D texture = useGradientTexture ? await
[Link](progressHandler) : null;
[Link]("_GradientTex", texture);
UpdateMatInternal();
}
finally
{
[Link]();
}
}
private void UpdateMatInternal()
{
if (tfRenderMode == TFRenderMode.TF2D)
{
[Link]("_TFTex",
[Link]());
[Link]("TF2D_ON");
}
else
{
[Link]("_TFTex",
[Link]());
[Link]("TF2D_ON");
}
if (lightingEnabled)
[Link]("LIGHTING_ON");
else
[Link]("LIGHTING_ON");
if (lightSource == [Link])
[Link]("USE_MAIN_LIGHT");
else
[Link]("USE_MAIN_LIGHT");
switch (renderMode)
{
case [Link]:
{
[Link]("MODE_DVR");
[Link]("MODE_MIP");
[Link]("MODE_SURF");
break;
}
case [Link]:
{
[Link]("MODE_DVR");
[Link]("MODE_MIP");
[Link]("MODE_SURF");
break;
}
case [Link]:
{
[Link]("MODE_DVR");
[Link]("MODE_MIP");
[Link]("MODE_SURF");
break;
}
}
[Link]("_MinVal", visibilityWindow.x);
[Link]("_MaxVal", visibilityWindow.y);
[Link]("_TextureSize", new
Vector3([Link], [Link], [Link]));
if (rayTerminationEnabled)
[Link]("RAY_TERMINATE_ON");
else
[Link]("RAY_TERMINATE_ON");
if (cubicInterpolationEnabled)
[Link]("CUBIC_INTERPOLATION_ON");
else
[Link]("CUBIC_INTERPOLATION_ON");
}
private void Awake()
{
// TODO: Remove this after some time. This is to avoid breaking old
serialised objects from before volumeContainerObject was added.
EnsureVolumeContainerRef();
}
private void Start()
{
UpdateMaterialProperties();
}
public void OnValidate()
{
// TODO: Remove this after some time. This is to avoid breaking old
serialised objects from before volumeContainerObject was added.
EnsureVolumeContainerRef();
}
private void EnsureVolumeContainerRef()
{
if (volumeContainerObject == null)
{
[Link]("VolumeContainer missing. This is expected if the
object was saved with an old version of the plugin. Please re-save it.");
Transform trans = [Link]("VolumeContainer");
if (trans == null)
trans =
[Link]<MeshRenderer>(true)?.transform;
if (trans)
volumeContainerObject = [Link];
}
}
}
}