2013-06-05 2 views
2

Я работаю над проектом Unity3D, который на мгновение опирается на трехмерную текстуру.Эмуляция 3D-текстуры в шейдере (связанная с субпикселом)

Проблема заключается в том, что Unity позволяет пользователям Pro использовать Texture3D. Поэтому я ищу альтернативу Texture3D, возможно, одномерную текстуру (хотя и не изначально доступную в Unity), которая интерпретируется как 3-мерная в шейдере (которая использует 3D-текстуру).

Есть ли способ сделать это, в то время как (предпочтительно) хранить информацию подпикселя?

(теги GLSL и Cg добавил, что здесь лежит суть проблемы)

Edit: Проблема решается здесь, а также: webgl glsl emulate texture3d Однако это еще не закончена и работает должным образом.

Редактировать: В настоящее время я не обращаю внимания на информацию о субпикселе. Поэтому любая помощь по преобразованию 2D-текстуры в 3D-информацию оценивается!

Edit: я отказался свой ответ, как это не является достаточным, как еще:

float2 uvFromUvw(float3 uvw) { 
     float2 uv = float2(uvw.x, uvw.y/_VolumeTextureSize.z); 
     uv.y += float(round(uvw.z * (_VolumeTextureSize.z - 1)))/_VolumeTextureSize.z; 
     return uv; 
    } 

С инициализации как Texture2D (volumeWidth, volumeHeight * volumeDepth).

Большую часть времени он работает, но иногда он показывает неправильные пиксели, возможно, из-за информации о субпикселях, которую он набирает. Как я могу это исправить? Зажим ввода не работает.

ответ

1

Я использую это для моего 3D облака, если это помогает:

float SampleNoiseTexture(float3 _UVW, float _MipLevel) 
{ 
    float2 WrappedUW = fmod(16.0 * (1000.0 + _UVW.xz), 16.0); // UW wrapped in [0,16[ 

    float IntW = floor(WrappedUW.y);    // Integer slice number 
    float dw = WrappedUW.y - IntW;     // Remainder for intepolating between slices 

    _UVW.x = (17.0 * IntW + WrappedUW.x + 0.25) * 0.00367647058823529411764705882353; // divided by 17*16 = 272 

    float4 Value = tex2D(_TexNoise3D, float4(_UVW.xy, 0.0, 0.0)); 

    return lerp(Value.x, Value.y, dw); 
} 

«3D текстура» упакован в 16 ломтиков 17 пикселей в ширину в 272x16 текстуры, с 17-го столбца каждого среза являясь копией 1-го столбца (режим адреса обертки) ... Конечно, никакое mip-mapping не допускается с помощью этой техники.

+1

Я забыл указать, что X компонент текстуры содержит значение текущего Slice в то время как компонент Y содержит следующее значение среза. Таким образом, вы можете задерживаться вдоль направления W, используя единственный кран текстуры. Это ограничивает эти «3D» текстуры только двумя компонентами, хотя это было нормально, поскольку я сохранил только одно монохроматическое значение шума ... – Patapom

+0

Это довольно гениальный, я должен сказать! Спасибо за помощь :) – RobotRock

+0

Можете ли вы подробнее рассказать о магических числах? Или у вас где-то есть документация? – RobotRock

0

Я следил за реакцией Patapoms и пришел к следующему. Однако это все равно, как и должно быть.

float getAlpha(float3 position) 
{ 
    float2 WrappedUW = fmod(_Volume.xz * (1000.0 + position.xz), _Volume.xz); // UW wrapped in [0,16[ 

    float IntW = floor(WrappedUW.y);    // Integer slice number 
    float dw = WrappedUW.y - IntW;     // Remainder for intepolating between slices 

    position.x = ((_Volume.z + 1.0) * IntW + WrappedUW.x + 0.25)/((_Volume.z + 1.0) * _Volume.x); // divided by 17*16 = 272 

    float4 Value = tex2Dlod(_VolumeTex, float4(position.xy, 0.0, 0.0)); 

    return lerp(Value.x, Value.y, dw); 
} 


public int GetPixelId(int x, int y, int z) { 
    return y * (volumeWidth + 1) * volumeDepth + z * (volumeWidth + 1) + x; 
} 

      // Code to set the pixelbuffer one pixel at a time starting from a clean slate 
      pixelBuffer[GetPixelId(x, y, z)].r = color.r; 

      if (z > 0) 
       pixelBuffer[GetPixelId(x, y, z - 1)].g = color.r; 

      if (z == volumeDepth - 1 || z == 0) 
       pixelBuffer[GetPixelId(x, y, z)].g = color.r; 

      if (x == 0) { 
       pixelBuffer[GetPixelId(volumeWidth, y, z)].r = color.r; 
       if (z > 0) 
        pixelBuffer[GetPixelId(volumeWidth, y, z - 1)].g = color.r; 

       if (z == volumeDepth - 1 || z == 0) 
        pixelBuffer[GetPixelId(volumeWidth, y, z)].g = color.r; 
      } 
1

Вот код, я использую для создания 3D-текстуры, если это то, что вас беспокоит:

static const NOISE3D_TEXTURE_POT = 4; 
static const NOISE3D_TEXTURE_SIZE = 1 << NOISE3D_TEXTURE_POT; 

// <summary> 
// Create the "3D noise" texture 
// To simulate 3D textures that are not available in Unity, I create a single long 2D slice of (17*16) x 16 
// The width is 17*16 so that all 3D slices are packed into a single line, and I use 17 as a single slice width 
// because I pad the last pixel with the first column of the same slice so bilinear interpolation is correct. 
// The texture contains 2 significant values in Red and Green : 
//  Red is the noise value in the current W slice 
//  Green is the noise value in the next W slice 
// Then, the actual 3D noise value is an interpolation of red and green based on the W remainder 
// </summary> 
protected NuajTexture2D Build3DNoise() 
{ 
    // Build first noise mip level 
    float[,,] NoiseValues = new float[NOISE3D_TEXTURE_SIZE,NOISE3D_TEXTURE_SIZE,NOISE3D_TEXTURE_SIZE]; 
    for (int W=0; W < NOISE3D_TEXTURE_SIZE; W++) 
     for (int V=0; V < NOISE3D_TEXTURE_SIZE; V++) 
      for (int U=0; U < NOISE3D_TEXTURE_SIZE; U++) 
       NoiseValues[U,V,W] = (float) SimpleRNG.GetUniform(); 

    // Build actual texture 
    int MipLevel = 0; // In my original code, I build several textures for several mips... 
    int MipSize = NOISE3D_TEXTURE_SIZE >> MipLevel; 
    int Width = MipSize*(MipSize+1); // Pad with an additional column 
    Color[] Content = new Color[MipSize*Width]; 

    // Build content 
    for (int W=0; W < MipSize; W++) 
    { 
     int Offset = W * (MipSize+1); // W Slice offset 
     for (int V=0; V < MipSize; V++) 
     { 
      for (int U=0; U <= MipSize; U++) 
      { 
       Content[Offset+Width*V+U].r = NoiseValues[U & (MipSize-1),V,W]; 
       Content[Offset+Width*V+U].g = NoiseValues[U & (MipSize-1),V,(W+1) & (MipSize-1)]; 
      } 
     } 
    } 

    // Create texture 
    NuajTexture2D Result = Help.CreateTexture("Noise3D", Width, MipSize, TextureFormat.ARGB32, false, FilterMode.Bilinear, TextureWrapMode.Repeat); 
    Result.SetPixels(Content, 0); 
    Result.Apply(false, true); 

    return Result; 
}