1D Textures as a lookup table for my shaders

I would like to feed my shaders a one dimensional texture as a lookup table. OpenGL has Sampler1D and Texture1D but what do I use on the JME3 side of things?

On the forum there was talk about Texture1D in JME over 15 years ago, but there is no such class in Javadoc.

Curious, what is the use-case for a 1D texture that is different than an array?

Mainly speed.

Array Uniforms, as I understand it, are slow and need to be updated every draw call.

I feed my instances the index of the nearest world point. In the shader I use this index to get world information about the corresponding point.

Since I misuse column 3 of the transformation matrix, I only have four floats so I don’t want to use two floats for an index. This means that with a 2D texture I would have to split the ID into x and y before sampling the texture. And that 1 milion instances x 40 vertices.

And I think it would be cleaner since in fact my data is just not organized in a grid.

But if I am mistaking, and arrays are as fast as textures and can handle over 200K of information, that would be great.

I mean that you can actually just set arrays as material parameters… like a float array:
https://javadoc.jmonkeyengine.org/v3.5.2-stable/com/jme3/shader/VarType.html#FloatArray
vec4 array:
https://javadoc.jmonkeyengine.org/v3.5.2-stable/com/jme3/shader/VarType.html#Vector4Array
…and so on.

…but I’m also not sure why you need special 1DTexture support over just sending in a 2D texture with no width. I would be very much surprised if the GPU weren’t already treating 1D textures that way.
sampler2D(myTexture, vec2(0, myIndex));

That I did try, but there is a limit for the x and y dimensions that does not allow me to have an x value over 32K (approx).

And arrays are not slowing stuff down (more than textures do)?

I don’t know why they would. To me, sampler has the opportunity to be slower because it has to turn a 0…1 float into an index, check for min/mag filtering, etc… An array is just an array.

That would not change with a 1D texture, I think. There will still be a limit.

I get C5041 errors. If I am correct 40K arrays are way too big for uniforms.

You can check the Limits.FragmentUniformVectors and Limits.VertexUniformVectors for the maximum amount of vectors you can use as uniforms

It says 1024… not going to fit. I need to feed it 200K of world data…

So back to texture1D… does anyone know where it went, does anyone have the source code for that class?

You still can use a 2d texture.
convetring 1d array lookup to 2d lookup.

the gl specs say that 1d textures have the same max width as 2d textures

I need to phone the guy who wrote those specs…

Too bad… any ideas how I can send more instanceData per instance to my shaders? That way I can waste some space on the extra coord.

How are you passing the array coordinate for the 1d array?

int x=index/textureWidth
int y=index%textureWidth

I misuse column #3 of the transformation matrix.

I took your suggestion and played with it:

float y = int(floor(mapIdx / 16))/256;
float x = int(mod(mapIdx, 16))/256;

Now my grass is flying… which is good, I just messed with the coords to get some feedback.

It is working!

This video shows a test. When nobody is walking in it, the grass is red. When a guy walks around in it, it turns green and when he goes elsewhere it turns red again. This shows that the WorldInfo-texture idea works.

Some elements I put together:

  • First of all I created a texture with an ImageRaster to draw directly on it. every pixel corresponds with one of the 40K vertices of the globe mesh. The red chanel is used to store the height, green is for guys walking around.
  • I created grass using instancing. For every grass patch there are 20 floats of information. 16 for the transformation matrix and the normal-rotation and for spots. OpenGL only supports 16 elements per attribute array. But since these elements can be of any type, using vec4’s allows you to pass 4x16=64 floats - and using mat4’s would give you even more.
  • Each grass patch needs the following extra information in order for this idea to work:
    • 2 uv coords for wind location
    • 2 uv coords of the for worldInfo-lookup
    • distance to the nearest world-point
    • direction of the nearest world-point
      I combine both uv-pairs: the wind location is in the fraction, the world-lookup is in the integers. Using the wind-UV’s is easy: they don’t need any work since they will wrap anyway. The worldlookup-UV’s need some work.
// GRASS PATCHES
uniform vec2  m_windDirection;   //Direction of the wind
uniform float m_windSpeed;       //Speed of the wind, not implemented
uniform float m_time;            //Game-time updated every cycle
uniform sampler2D m_windDistortionMap; //2 channel distortion noise to read displacement 
uniform sampler2D m_worldInfo;
vec2    uv=inInstanceData[4].xy;
float   mapIdx=inInstanceData[4].z;
float   mapAngle=inInstanceData[4].w;
//uniform float m_worldInfoMovers[40962];

varying vec4 worldTest;

void main(){
   vec4 modelSpacePos = vec4(inPosition, 1.0);
   vec3 modelSpaceNorm = inNormal;
   
   float x = floor(uv.x)/256;
   float y = floor(uv.y)/256;
   
   vec4 wInfo=texture2D( m_worldInfo , vec2(x,y) );
   

   worldTest=wInfo;

This is the relevant part of the vert-shader code. There are also some minor changes to Instancing.glsllib.

Now I need some clever shader code to make the patched bend to the ground corresponding to the ‘presure’. Pressure is a world info value between 0 and 1.

1 Like