/// <summary> /// Compute the Color t parameter using (1.0-t)*m_tf1 + t*m_tf2 /// </summary> /// <param name="values">The values to compute the color. Must be between 0.0f and 1.0f. Length: at minimum the length of GetDimension()</param> /// <returns>The color</returns> public override Color ComputeColor(float[] values) { Color tf1Val; Color tf2Val; uint dim = GetDimension(); //We need to rearrange "values" because of the gradient of the lowest dimension object //Check tf1 if (m_tf1.GetDimension() < dim && m_tf1.HasGradient()) { float temp = values[m_tf1.GetDimension() - 1]; values[m_tf1.GetDimension() - 1] = values[dim - 1]; tf1Val = m_tf1.ComputeColor(values); values[m_tf1.GetDimension() - 1] = temp; } else { tf1Val = m_tf1.ComputeColor(values); } //Check tf2 if (m_tf2.GetDimension() < dim && m_tf2.HasGradient()) { float temp = values[m_tf2.GetDimension() - 1]; values[m_tf2.GetDimension() - 1] = values[dim - 1]; tf2Val = m_tf2.ComputeColor(values); values[m_tf2.GetDimension() - 1] = temp; } else { tf2Val = m_tf2.ComputeColor(values); } return((1.0f - m_t) * tf1Val + m_t * tf2Val); }
/// <summary> /// Compute the Texture pixels /// </summary> /// <param name="values">Array of values to send to the Transfer Function. Size : texelSize.x*texelSize.y</param> /// <param name="padding">The padding in the array between each values</param> /// <returns>Return true on success, false on failure</returns> public bool ComputeTexture(float[] values, uint padding) { if (values.Length / padding != m_dimensions.x * m_dimensions.y) { return(false); } float[] v = new float[padding]; m_colors = new byte[4 * values.Length / padding]; for (int i = 0; i < m_colors.Length / 4; i++) { Array.Copy(values, padding * i, v, 0, padding); Color iCol = m_tf.ComputeColor(v); m_colors[4 * i] = (byte)(iCol.r * 255); m_colors[4 * i + 1] = (byte)(iCol.g * 255); m_colors[4 * i + 2] = (byte)(iCol.b * 255); m_colors[4 * i + 3] = (byte)(m_tf.ComputeAlpha(v) * 255); } return(true); }
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); } } }
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); } }