IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
VolumeCube.cs
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4 
5 public class VolumeCube : MonoBehaviour {
6 
7  public MeshFilter stackOfSlices;
8 
9 
10  void OnEnable()
11  {
12  // Register event callbacks for all DICOM events:
13  PatientEventSystem.startListening( PatientEventSystem.Event.DICOM_NewLoadedVolume, eventDisplayCurrentDicom );
14  PatientEventSystem.startListening( PatientEventSystem.Event.PATIENT_Closed, eventClear );
15  PatientEventSystem.startListening( PatientEventSystem.Event.DICOM_CloseVolume, eventClear );
16  eventClear ();
17  //eventDisplayCurrentDicom ();
18  buildMesh();
19  }
20 
21  void OnDisable()
22  {
23  // Unregister myself - no longer receive events (until the next OnEnable() call):
24  PatientEventSystem.stopListening( PatientEventSystem.Event.DICOM_NewLoadedVolume, eventDisplayCurrentDicom );
25  PatientEventSystem.stopListening( PatientEventSystem.Event.PATIENT_Closed, eventClear );
26  PatientEventSystem.stopListening( PatientEventSystem.Event.DICOM_CloseVolume, eventClear );
27  }
28 
29  // Use this for initialization
30  void Start () {
31  }
32 
33  void buildMesh() {
34 
35  List<Vector3> verts = new List<Vector3> ();
36  List<int> tris = new List<int>();
37  List<Vector2> uvs = new List<Vector2>();
38  List<Vector3> normals = new List<Vector3> ();
39  Vector3 normal;
40  int vertsAlreadyAdded = 0;
41 
42  // TODO: Current volume starts at 0.5*sliceDelta, not at 0 as it should!
43  int numSlices = 512;//512;
44  float sliceDelta = 1f / (float)numSlices;
45  normal = new Vector3 (0, 0, 1);
46  vertsAlreadyAdded = verts.Count;
47  for (int slice = 0; slice < numSlices; slice ++) {
48  Vector3 vert1 = new Vector3 (-1, -1, -1 + 2f*(float)(slice+0.5f)*sliceDelta);
49  Vector3 vert2 = new Vector3 (-1, 1, -1 + 2f*(float)(slice+0.5f)*sliceDelta);
50  Vector3 vert3 = new Vector3 (1, -1, -1 + 2f*(float)(slice+0.5f)*sliceDelta);
51  Vector3 vert4 = new Vector3 (1, 1, -1 + 2f*(float)(slice+0.5f)*sliceDelta);
52 
53  // Front faces:
54  verts.Add (vert1);
55  verts.Add (vert2);
56  verts.Add (vert3);
57  verts.Add (vert4);
58  normals.Add (normal);
59  normals.Add (normal);
60  normals.Add (normal);
61  normals.Add (normal);
62  // 1
63  tris.Add (vertsAlreadyAdded + slice*4 + 2);
64  tris.Add (vertsAlreadyAdded + slice*4 + 1);
65  tris.Add (vertsAlreadyAdded + slice*4 + 0);
66  // 2
67  tris.Add (vertsAlreadyAdded + slice*4 + 2);
68  tris.Add (vertsAlreadyAdded + slice*4 + 3);
69  tris.Add (vertsAlreadyAdded + slice*4 + 1);
70  }
71  vertsAlreadyAdded = verts.Count;
72  for (int slice = 0; slice < numSlices; slice ++) {
73  Vector3 vert1 = new Vector3 (-1, -1, 1 - 2f*(float)(slice+0.5f)*sliceDelta);
74  Vector3 vert2 = new Vector3 (-1, 1, 1 - 2f*(float)(slice+0.5f)*sliceDelta);
75  Vector3 vert3 = new Vector3 (1, -1, 1 - 2f*(float)(slice+0.5f)*sliceDelta);
76  Vector3 vert4 = new Vector3 (1, 1, 1 - 2f*(float)(slice+0.5f)*sliceDelta);
77 
78  // Front faces:
79  verts.Add (vert1);
80  verts.Add (vert2);
81  verts.Add (vert3);
82  verts.Add (vert4);
83  normals.Add (-normal);
84  normals.Add (-normal);
85  normals.Add (-normal);
86  normals.Add (-normal);
87  // 1
88  tris.Add (vertsAlreadyAdded + slice*4 + 0);
89  tris.Add (vertsAlreadyAdded + slice*4 + 1);
90  tris.Add (vertsAlreadyAdded + slice*4 + 2);
91  // 2
92  tris.Add (vertsAlreadyAdded + slice*4 + 1);
93  tris.Add (vertsAlreadyAdded + slice*4 + 3);
94  tris.Add (vertsAlreadyAdded + slice*4 + 2);
95  }
96 
97  normal = new Vector3 (0, 1, 0);
98  vertsAlreadyAdded = verts.Count;
99  for (int slice = 0; slice < numSlices; slice ++) {
100  Vector3 vert1 = new Vector3 (-1, -1 + 2f*(float)(slice+0.5f)*sliceDelta, -1);
101  Vector3 vert2 = new Vector3 (-1, -1 + 2f*(float)(slice+0.5f)*sliceDelta, 1);
102  Vector3 vert3 = new Vector3 (1, -1 + 2f*(float)(slice+0.5f)*sliceDelta, -1);
103  Vector3 vert4 = new Vector3 (1, -1 + 2f*(float)(slice+0.5f)*sliceDelta, 1);
104 
105  // Front faces:
106  verts.Add (vert1);
107  verts.Add (vert2);
108  verts.Add (vert3);
109  verts.Add (vert4);
110  normals.Add (normal);
111  normals.Add (normal);
112  normals.Add (normal);
113  normals.Add (normal);
114 
115  // 1
116  tris.Add (vertsAlreadyAdded + slice*4 + 0);
117  tris.Add (vertsAlreadyAdded + slice*4 + 1);
118  tris.Add (vertsAlreadyAdded + slice*4 + 2);
119  // 2
120  tris.Add (vertsAlreadyAdded + slice*4 + 1);
121  tris.Add (vertsAlreadyAdded + slice*4 + 3);
122  tris.Add (vertsAlreadyAdded + slice*4 + 2);
123 
124  }
125  vertsAlreadyAdded = verts.Count;
126  for (int slice = 0; slice < numSlices; slice ++) {
127  Vector3 vert1 = new Vector3 (-1, 1 - 2f*(float)(slice+0.5f)*sliceDelta, -1);
128  Vector3 vert2 = new Vector3 (-1, 1 - 2f*(float)(slice+0.5f)*sliceDelta, 1);
129  Vector3 vert3 = new Vector3 (1, 1 - 2f*(float)(slice+0.5f)*sliceDelta, -1);
130  Vector3 vert4 = new Vector3 (1, 1 - 2f*(float)(slice+0.5f)*sliceDelta, 1);
131 
132  // Front faces:
133  verts.Add (vert1);
134  verts.Add (vert2);
135  verts.Add (vert3);
136  verts.Add (vert4);
137  normals.Add (-normal);
138  normals.Add (-normal);
139  normals.Add (-normal);
140  normals.Add (-normal);
141  // 1
142  tris.Add (vertsAlreadyAdded + slice*4 + 2);
143  tris.Add (vertsAlreadyAdded + slice*4 + 1);
144  tris.Add (vertsAlreadyAdded + slice*4 + 0);
145  // 2
146  tris.Add (vertsAlreadyAdded + slice*4 + 2);
147  tris.Add (vertsAlreadyAdded + slice*4 + 3);
148  tris.Add (vertsAlreadyAdded + slice*4 + 1);
149  }
150 
151  normal = new Vector3 (1, 0, 0);
152  vertsAlreadyAdded = verts.Count;
153  for (int slice = 0; slice < numSlices; slice ++) {
154  Vector3 vert1 = new Vector3 (-1 + 2f*(float)(slice+0.5f)*sliceDelta, -1, -1);
155  Vector3 vert2 = new Vector3 (-1 + 2f*(float)(slice+0.5f)*sliceDelta, -1, 1);
156  Vector3 vert3 = new Vector3 (-1 + 2f*(float)(slice+0.5f)*sliceDelta, 1, -1);
157  Vector3 vert4 = new Vector3 (-1 + 2f*(float)(slice+0.5f)*sliceDelta, 1, 1);
158 
159  // Front faces:
160  verts.Add (vert1);
161  verts.Add (vert2);
162  verts.Add (vert3);
163  verts.Add (vert4);
164  normals.Add (normal);
165  normals.Add (normal);
166  normals.Add (normal);
167  normals.Add (normal);
168  // 1
169  tris.Add (vertsAlreadyAdded + slice*4 + 2);
170  tris.Add (vertsAlreadyAdded + slice*4 + 1);
171  tris.Add (vertsAlreadyAdded + slice*4 + 0);
172  // 2
173  tris.Add (vertsAlreadyAdded + slice*4 + 2);
174  tris.Add (vertsAlreadyAdded + slice*4 + 3);
175  tris.Add (vertsAlreadyAdded + slice*4 + 1);
176  }
177  vertsAlreadyAdded = verts.Count;
178  for (int slice = 0; slice < numSlices; slice ++) {
179  Vector3 vert1 = new Vector3 (1 - 2f*(float)(slice+0.5f)*sliceDelta, -1, -1);
180  Vector3 vert2 = new Vector3 (1 - 2f*(float)(slice+0.5f)*sliceDelta, -1, 1);
181  Vector3 vert3 = new Vector3 (1 - 2f*(float)(slice+0.5f)*sliceDelta, 1, -1);
182  Vector3 vert4 = new Vector3 (1 - 2f*(float)(slice+0.5f)*sliceDelta, 1, 1);
183 
184  // Front faces:
185  verts.Add (vert1);
186  verts.Add (vert2);
187  verts.Add (vert3);
188  verts.Add (vert4);
189  normals.Add (-normal);
190  normals.Add (-normal);
191  normals.Add (-normal);
192  normals.Add (-normal);
193  // 1
194  tris.Add (vertsAlreadyAdded + slice*4 + 0);
195  tris.Add (vertsAlreadyAdded + slice*4 + 1);
196  tris.Add (vertsAlreadyAdded + slice*4 + 2);
197  // 2
198  tris.Add (vertsAlreadyAdded + slice*4 + 1);
199  tris.Add (vertsAlreadyAdded + slice*4 + 3);
200  tris.Add (vertsAlreadyAdded + slice*4 + 2);
201  }
202 
203  // Generate the mesh object.
204  Mesh ret = new Mesh();
205  ret.vertices = verts.ToArray();
206  ret.triangles = tris.ToArray();
207  ret.normals = normals.ToArray();
208  ret.uv = uvs.ToArray();
209 
210  // Assign the mesh object and update it.
211  ret.RecalculateBounds();
212  //ret.RecalculateNormals();
213  stackOfSlices.mesh = ret;
214  }
215 
217  public void SetDicom( DICOM3D dicom )
218  {
219  Material mat = GetComponent<MeshRenderer> ().sharedMaterial;
220  Debug.Log ("Min, max: "+ (float)dicom.seriesInfo.minPixelValue + " " + (float)dicom.seriesInfo.maxPixelValue);
221  mat.SetFloat ("globalMinimum", (float)dicom.seriesInfo.minPixelValue);
222  mat.SetFloat ("globalMaximum", (float)dicom.seriesInfo.maxPixelValue);
223  mat.mainTexture = dicom.getTexture3D();
224  mat.SetVector ("textureSize", new Vector3 (dicom.texWidth, dicom.texHeight, dicom.texDepth));
225 
226  // ------------------------------------------------
227  // Move the VolumeCube to the position where the 3D DICOM should be rendered:
228  // (The VolumeCube's localPosition and localScale is in the DICOM's "patient coordinate system", so
229  // adjusting its localPosition and localScale to fit with the DICOM's center and size will set it to
230  // the correct position.)
231 
232  // Size which the volume should have at the end (in patient coordinates):
233  Vector3 goalSize = dicom.boundingBox.size;
234  // Position where the center of the rendered volume should be (in patient coordinates):
235  Vector3 goalCenter = dicom.boundingBox.center;
236  // Current (original) position and sizes of the mesh, because of the way it was generated:
237  Vector3 minMesh = new Vector3 (-1, -1, -1);
238  Vector3 maxMesh = new Vector3 (1, 1, 1);
239  Vector3 meshSize = maxMesh - minMesh;
240  // The padding factor takes into account that the DICOM volume may be smaller than the texture, since
241  // Unity requires power-of-two textures, so the texture may be larger than the DICOM volume.
242  Vector3 paddingFactor = new Vector3 (
243  (float)dicom.origTexWidth / (float)dicom.texWidth,
244  (float)dicom.origTexHeight / (float)dicom.texHeight,
245  (float)dicom.origTexDepth / (float)dicom.texDepth);
246 
247  // Part of the mesh which actually holds the DICOM volume:
248  Vector3 paddedMeshSize = Vector3.Scale (paddingFactor, meshSize);
249 
250  // Center of the part of the mesh which is filled with the DICOM volume:
251  Vector3 meshCenter = minMesh + paddedMeshSize*0.5f;
252  // Offset from the mesh original center (which is, because of the way the mesh was generated above, zero):
253  Vector3 meshCenterOffset = Vector3.zero - meshCenter;
254 
255  // Inverse of paddedMeshSize:
256  Vector3 invPaddedMeshSize = new Vector3 (1f / paddedMeshSize.x, 1f / paddedMeshSize.y, 1f / paddedMeshSize.z);
257  // The final scale is the goalSize/paddedMeshSize:
258  Vector3 scale = Vector3.Scale (goalSize, invPaddedMeshSize);
259  transform.localScale = scale;
260  // Move the mesh center to its final position:
261  transform.localPosition = goalCenter + Vector3.Scale (meshCenterOffset, scale);
262 
263  // ------------------------------------------------
264  }
265 
266 
267  void eventDisplayCurrentDicom( object obj = null )
268  {
269  DICOM3D dicom = DICOMLoader.instance.currentDICOMVolume;
270  if (dicom != null) {
271  SetDicom (dicom);
272  GetComponent<MeshRenderer> ().enabled = true;
273  }
274  }
275 
276  void eventClear( object obj = null )
277  {
278  GetComponent<MeshRenderer> ().enabled = false;
279  }
280 }
int origTexDepth
Definition: DICOM.cs:28
UInt32 minPixelValue
Definition: DICOMSeries.cs:53
UInt32 maxPixelValue
Definition: DICOMSeries.cs:58
int origTexWidth
Definition: DICOM.cs:24
void SetDicom(DICOM3D dicom)
Definition: VolumeCube.cs:217
int origTexHeight
Definition: DICOM.cs:26
DICOMSeries seriesInfo
Definition: DICOM.cs:13