Birim işleme

Birim işlemede yeniyseniz genel bakış bilgilerimizi okumanızı öneririz.

3B Dokuları Temsil Etme

CPU üzerinde:

public struct Int3 { public int X, Y, Z; /* ... */ }
 public class VolumeHeader  {
   public readonly Int3 Size;
   public VolumeHeader(Int3 size) { this.Size = size;  }
   public int CubicToLinearIndex(Int3 index) {
     return index.X + (index.Y * (Size.X)) + (index.Z * (Size.X * Size.Y));
   }
   public Int3 LinearToCubicIndex(int linearIndex)
   {
     return new Int3((linearIndex / 1) % Size.X,
       (linearIndex / Size.X) % Size.Y,
       (linearIndex / (Size.X * Size.Y)) % Size.Z);
   }
   /* ... */
 }
 public class VolumeBuffer<T> {
   public readonly VolumeHeader Header;
   public readonly T[] DataArray;
   public T GetVoxel(Int3 pos)        {
     return this.DataArray[this.Header.CubicToLinearIndex(pos)];
   }
   public void SetVoxel(Int3 pos, T val)        {
     this.DataArray[this.Header.CubicToLinearIndex(pos)] = val;
   }
   public T this[Int3 pos] {
     get { return this.GetVoxel(pos); }
     set { this.SetVoxel(pos, value); }
   }
   /* ... */
 }

GPU'da:

float3 _VolBufferSize;
 int3 UnitVolumeToIntVolume(float3 coord) {
   return (int3)( coord * _VolBufferSize.xyz );
 }
 int IntVolumeToLinearIndex(int3 coord, int3 size) {
   return coord.x + ( coord.y * size.x ) + ( coord.z * ( size.x * size.y ) );
 }
 uniform StructuredBuffer<float> _VolBuffer;
 float SampleVol(float3 coord3 ) {
   int3 intIndex3 = UnitVolumeToIntVolume( coord3 );
   int index1D = IntVolumeToLinearIndex( intIndex3, _VolBufferSize.xyz);
   return __VolBuffer[index1D];
 }

Gölgelendirme ve Gradyanlar

Yararlı görselleştirme için MRI gibi bir birimi gölgelendirme. Birincil yöntem, içinde yoğunlukları görmek istediğiniz bir 'yoğunluk penceresine' (en az ve en yüksek) sahip olmak ve siyah beyaz yoğunluğunu görmek için bu alana ölçeklendirmektir. Daha sonra bu aralıktaki değerlere bir 'renk rampası' uygulanabilir ve bir doku olarak depolanabilir, böylece yoğunluk spektrumunun farklı bölümleri farklı renkleri gölgelendirebilir:

float4 ShadeVol( float intensity ) {
   float unitIntensity = saturate( intensity - IntensityMin / ( IntensityMax - IntensityMin ) );
   // Simple two point black and white intensity:
   color.rgba = unitIntensity;
   // Color ramp method:
   color.rgba = tex2d( ColorRampTexture, float2( unitIntensity, 0 ) );

Uygulamalarımızın birçoğunda, hacmimizde hem ham yoğunluk değeri hem de 'segmentasyon dizini' depolarız (cilt ve kemik gibi farklı parçaları segmentlere ayırmak için; bu segmentler özel araçlarda uzmanlar tarafından oluşturulur). Bu, her segment dizini için farklı bir renk veya hatta farklı bir renk rampası koymak için yukarıdaki yaklaşımla birleştirilebilir:

// Change color to match segment index (fade each segment towards black):
 color.rgb = SegmentColors[ segment_index ] * color.a; // brighter alpha gives brighter color

Gölgelendiricide Birim Dilimleme

İlk adımlardan biri, birim içinde hareket eden, 'dilimleyen' ve her noktada tarama değerlerinin nasıl hareket ettirebileceğine ilişkin bir "dilimleme düzlemi" oluşturmaktır. Bu, birimin dünya uzayında nerede olduğunu temsil eden ve noktaları yerleştirmek için başvuru olarak kullanılabilecek bir 'VolumeSpace' küpü olduğunu varsayar:

// In the vertex shader:
 float4 worldPos = mul(_Object2World, float4(input.vertex.xyz, 1));
 float4 volSpace = mul(_WorldToVolume, float4(worldPos, 1));
// In the pixel shader:
 float4 color = ShadeVol( SampleVol( volSpace ) );

Gölgelendiricilerde Birim İzleme

Altvolüm izlemesi yapmak için GPU nasıl kullanılır (birkaç voxel'de derinlerde ve ardından veriler üzerinde arkadan öne doğru katmanlarda ilerler):

float4 AlphaBlend(float4 dst, float4 src) {
   float4 res = (src * src.a) + (dst - dst * src.a);
   res.a = src.a + (dst.a - dst.a*src.a);
   return res;
 }
 float4 volTraceSubVolume(float3 objPosStart, float3 cameraPosVolSpace) {
   float maxDepth = 0.15; // depth in volume space, customize!!!
   float numLoops = 10; // can be 400 on nice PC
   float4 curColor = float4(0, 0, 0, 0);
   // Figure out front and back volume coords to walk through:
   float3 frontCoord = objPosStart;
   float3 backCoord = frontPos + (normalize(cameraPosVolSpace - objPosStart) * maxDepth);
   float3 stepCoord = (frontCoord - backCoord) / numLoops;
   float3 curCoord = backCoord;
   // Add per-pixel random offset, avoids layer aliasing:
   curCoord += stepCoord * RandomFromPositionFast(objPosStart);
   // Walk from back to front (to make front appear in-front of back):
   for (float i = 0; i < numLoops; i++) {
     float intensity = SampleVol(curCoord);
     float4 shaded = ShadeVol(intensity);
     curColor = AlphaBlend(curColor, shaded);
     curCoord += stepCoord;
   }
   return curColor;
 }
// In the vertex shader:
 float4 worldPos = mul(_Object2World, float4(input.vertex.xyz, 1));
 float4 volSpace = mul(_WorldToVolume, float4(worldPos.xyz, 1));
 float4 cameraInVolSpace = mul(_WorldToVolume, float4(_WorldSpaceCameraPos.xyz, 1));
// In the pixel shader:
 float4 color = volTraceSubVolume( volSpace, cameraInVolSpace );

Tüm Birim İşleme

Yukarıdaki altvolum kodunu değiştirerek şunları elde ederiz:

float4 volTraceSubVolume(float3 objPosStart, float3 cameraPosVolSpace) {
   float maxDepth = 1.73; // sqrt(3), max distance from point on cube to any other point on cube
   int maxSamples = 400; // just in case, keep this value within bounds
   // not shown: trim front and back positions to both be within the cube
   int distanceInVoxels = length(UnitVolumeToIntVolume(frontPos - backPos)); // measure distance in voxels
   int numLoops = min( distanceInVoxels, maxSamples ); // put a min on the voxels to sample

Karma ÇözünürlükTe Sahne İşleme

Sahnenin bir bölümünü düşük çözünürlükte işleme ve yerine yerleştirme:

  1. Her kareyi güncelleştiren her gözü takip etmek için biri olmak üzere iki ekran dışı kamera ayarlayın
  2. Kameraların işlemekte olduğu iki düşük çözünürlüklü işleme hedefi (her biri 200x200) ayarlayın
  3. Kullanıcının önüne taşınan dörtlü ayarlama

Her Çerçeve:

  1. Her göz için işleme hedeflerini düşük çözünürlükte (birim verileri, pahalı gölgelendiriciler vb.) çizin
  2. Sahneyi normal şekilde tam çözünürlük (kısa çizgiler, kullanıcı arabirimi vb.) olarak çizin
  3. Kullanıcının önünde, sahnenin üzerine bir dörtlü çizin ve düşük res'in bu görünüme işlendiğini yansıtın
  4. Sonuç: Düşük çözünürlüklü ancak yüksek yoğunluklu hacim verileriyle tam çözünürlüklü öğelerin görsel birleşimi