public void UpdateTF() { Task.Factory.StartNew(() => { //First, discard multiple call to this function (only two calls are available) lock (m_isTFUpdateLock) { if (m_waitToUpdateTF) { Debug.Log("Already waiting for TF"); return; } else { m_waitToUpdateTF = true; } } //The wait to update the TF lock (m_updateTFLock) { //Another one can wait to update the TF if it wants (max: two parallel call, one pending, one executing) lock (m_isTFUpdateLock) m_waitToUpdateTF = false; TransferFunction tf = null; lock (m_sd) { if (m_sd.Visibility == SubDatasetVisibility.GONE) { return; } if (m_sd.TransferFunction == null) { return; } tf = (TransferFunction)m_sd.TransferFunction.Clone(); } Debug.Log("Updating TF..."); byte[] colors = ComputeTFColor(tf); lock (this) { m_colors = colors; } } }); }
public override bool Equals(object obj) { if (obj == null) { return(false); } if (obj is TransferFunction) { TransferFunction tf = obj as TransferFunction; return(tf.ColorMode == ColorMode && tf.Timestep == Timestep && tf.MinClipping == MinClipping && tf.MaxClipping == MaxClipping); } return(false); }
private void UpdateTF_Thread() { //First, discard multiple call to this function (only two calls are available) lock (m_isTFUpdateLock) { if (m_waitToUpdateTF) { Debug.Log("Already waiting for TF"); return; } else { m_waitToUpdateTF = true; } } //The wait to update the TF lock (m_updateTFLock) { //Another one can wait to update the TF if it wants (max: two parallel call, one pending, one executing) lock (m_isTFUpdateLock) m_waitToUpdateTF = false; TransferFunction tf = null; lock (m_subDataset) { if (m_subDataset.Visibility == SubDatasetVisibility.GONE) { return; } if (m_subDataset.TransferFunction == null) { return; } tf = (TransferFunction)m_subDataset.TransferFunction.Clone(); } short[] color = ComputeTFColor(tf); m_subDataset.TFComputation = color; } }
public virtual void OnTransferFunctionChange(SubDataset dataset, TransferFunction tf) { }
public override void OnTransferFunctionChange(SubDataset dataset, TransferFunction tf) { base.OnTransferFunctionChange(dataset, tf); UpdateTF(); }
private byte[] ComputeTFColor(TransferFunction tf) { int hasGradient = (tf.HasGradient() ? 1 : 0); if (m_dataset.IsLoaded == false || tf == null || tf.GetDimension() - hasGradient > m_dataset.PointFieldDescs.Count || (m_sd.OwnerID != -1 && m_sd.OwnerID != m_dataProvider.GetHeadsetID())) //Not a public subdataset { return(null); } else { unsafe { int[] indices = new int[m_dataset.PointFieldDescs.Count]; for (int i = 0; i < indices.Length; i++) { indices[i] = i; } Datasets.Gradient gradient = m_dataset.GetGradient(indices); byte[] colors = new byte[4 * m_dataset.NbPoints]; //RGBA colors; List <PointFieldDescriptor> ptDescs = m_dataset.PointFieldDescs; Parallel.For(0, m_dataset.NbPoints, i => { fixed(byte *pcolors = colors) { float[] partialRes = new float[indices.Length + hasGradient]; if (m_sd.EnableVolumetricMask && !m_sd.GetVolumetricMaskAt((int)i)) { pcolors[4 * i + 3] = 0; return; } //Determine transfer function coordinates for (int l = 0; l < ptDescs.Count; l++) { int ids = indices[l]; if (ptDescs[ids].NbValuesPerTuple == 1) { partialRes[ids] = (ptDescs[ids].Value[0].ReadAsFloat((ulong)i) - ptDescs[ids].MinVal) / (ptDescs[ids].MaxVal - ptDescs[ids].MinVal); } else { partialRes[ids] = (ptDescs[ids].ReadMagnitude((ulong)i, 0) - ptDescs[ids].MinVal) / (ptDescs[ids].MaxVal - ptDescs[ids].MinVal); } } if (tf.HasGradient()) { if (gradient != null) { partialRes[partialRes.Length - 1] = gradient.Values[0][(ulong)i]; //In case we need the gradient } else { partialRes[partialRes.Length - 1] = 0.0f; } } Color c = tf.ComputeColor(partialRes); pcolors[4 * i + 0] = (byte)(c.r * 255); pcolors[4 * i + 1] = (byte)(c.g * 255); pcolors[4 * i + 2] = (byte)(c.b * 255); pcolors[4 * i + 3] = (byte)(255); } }); return(colors); } } }
public MergeTF(TransferFunction tf1, TransferFunction tf2, float t = 0.0f) : base(tf1.ColorMode) { m_tf1 = tf1.Clone(); m_tf2 = tf2.Clone(); m_t = t; }
/// <summary> /// Constructor. The texture is created but not initialized. Use ComputeTexture to do so /// </summary> /// <param name="tf">The Transfer Function to use</param> /// <param name="textureDim">The texture dimension wanted</param> /// <param name="mode">The ColorMode to apply</param> public TFTexture(TransferFunction tf, Vector2Int textureDim) { m_tf = tf; m_dimensions = textureDim; }
public void OnTransferFunctionChange(SubDataset dataset, TransferFunction tf) { UpdateTF(); }
private short[] ComputeTFColor(TransferFunction tf) { VTKDataset vtk = (VTKDataset)m_subDataset.Parent; int hasGradient = (tf.HasGradient() ? 1 : 0); if (vtk.IsLoaded == false || tf == null || tf.GetDimension() - hasGradient > vtk.PointFieldDescs.Count || (m_subDataset.OwnerID != -1 && m_subDataset.OwnerID != m_dataProvider.GetHeadsetID())) //Not a public subdataset { return(null); } int t1 = (int)Math.Floor(tf.Timestep); int t2 = (int)Math.Ceiling(tf.Timestep); int[] times = new int[] { t1, t2 }; unsafe { int[] indices = new int[vtk.PointFieldDescs.Count]; for (int i = 0; i < indices.Length; i++) { indices[i] = i; } Datasets.Gradient gradient = vtk.GetGradient(indices); short[] colors = new short[m_dimensions.x * m_dimensions.y * m_dimensions.z]; //short because RGBA4444 == 2 bytes -> short float frac = tf.Timestep - (float)Math.Truncate(tf.Timestep); List <PointFieldDescriptor> ptDescs = m_subDataset.Parent.PointFieldDescs; Parallel.For(0, m_dimensions.z, new ParallelOptions { MaxDegreeOfParallelism = 8 }, (k, state) => { float[] partialResT1 = new float[indices.Length + hasGradient]; float[] partialResT2 = new float[indices.Length + hasGradient]; fixed(short *pcolors = colors) { //int maxOldK = Math.Max(10 * (curK + 1), m_dimensions.z); //for(int k = 10*curK; k < maxOldK; k++) { UInt64 ind = (UInt64)(k * m_dimensions.x * m_dimensions.y); UInt64 readIntK = (UInt64)(m_descPts.Size[0] * m_descPts.Size[1] * (k * m_descPts.Size[2] / m_dimensions.z)); for (int j = 0; j < m_dimensions.y; j++) { //Pre compute the indice up to J--K coordinate UInt64 readIntJK = (UInt64)(m_descPts.Size[0] * (j * m_descPts.Size[1] / m_dimensions.y)) + readIntK; for (int i = 0; i < m_dimensions.x; i++) { UInt64 readInd = (UInt64)(i * m_descPts.Size[0] / m_dimensions.x) + readIntJK; if (vtk.MaskValue != null && ((byte *)(vtk.MaskValue.Value))[readInd] == 0 || (m_subDataset.EnableVolumetricMask && m_subDataset.GetVolumetricMaskAt((int)readInd) == false)) { pcolors[ind] = 0; } else { float[][] partialRes = new float[][] { partialResT1, partialResT2 }; for (int p = 0; p < 2; p++) { //Determine transfer function coordinates for (int l = 0; l < indices.Length; l++) { int ids = indices[l]; if (ptDescs[ids].NbValuesPerTuple == 1) { partialRes[p][ids] = (ptDescs[ids].Value[times[p]].ReadAsFloat(readInd) - ptDescs[ids].MinVal) / (ptDescs[ids].MaxVal - ptDescs[ids].MinVal); } else { partialRes[p][ids] = (ptDescs[ids].ReadMagnitude(readInd, times[p]) - ptDescs[ids].MinVal) / (ptDescs[ids].MaxVal - ptDescs[ids].MinVal); } } if (tf.HasGradient()) { if (gradient != null) { partialRes[p][partialRes[p].Length - 1] = gradient.Values[times[p]][readInd]; //In case we need the gradient } else { partialRes[p][partialRes[p].Length - 1] = 0.0f; } } } //Linear interpolation Color c = (1.0f - frac) * tf.ComputeColor(partialResT1) + frac * tf.ComputeColor(partialResT2); float a = (1.0f - frac) * tf.ComputeAlpha(partialResT1) + frac * tf.ComputeAlpha(partialResT2); byte r = (byte)(16 * c.r); if (r > 15) { r = 15; } byte g = (byte)(16 * c.g); if (g > 15) { g = 15; } byte b = (byte)(16 * c.b); if (b > 15) { b = 15; } byte _a = (byte)(16 * a); if (_a > 15) { _a = 15; } pcolors[ind] = (short)((r << 12) + (g << 8) + //RGBA4444 color format (b << 4) + _a); } ind += 1; } } } } }); return(colors); } }