Search code examples
unity-game-engineglslhlslcg

3D Texture emulation in shader (subpixel related)


I am working on a Unity3D project which relies on a 3D texture momentarily.

The problem is, Unity only allows Pro users to make use of Texture3D. Hence I'm looking for an alternative to Texture3D, perhaps a one dimensional texture (although not natively available in Unity) that is interpreted as 3 dimensional in the shader (which uses the 3D texture).

Is there a way to do this whilst (preferably) keeping subpixel information?

(GLSL and Cg tags added because here lies the core of the problem)

Edit: The problem is addressed here as well: webgl glsl emulate texture3d However this is not yet finished and working properly.

Edit: For the time being I disregard proper subpixel information. So any help on converting a 2D texture to contain 3D information is appreciated!

Edit: I retracted my own answer as it isn't sufficient as of yet:

    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;
    }

With initialization as Texture2D(volumeWidth, volumeHeight * volumeDepth).

Most of the time it works, but sometimes it shows wrong pixels, probably because of subpixel information it is picking up on. How can I fix this? Clamping the input doesn't work.


Solution

  • I'm using this for my 3D clouds if that helps:

    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 );
    }
    

    The "3D texture" is packed as 16 slices of 17 pixels wide in a 272x16 texture, with the 17th column of each slice being a copy of the 1st column (wrap address mode)... Of course, no mip-mapping allowed with this technique.