Texture to texture array

Hi,

I need advice about sampler2DArray. On OpenGL IRC I spoke about fast loading textures throught uniforms. Guys direct me to glTexStorage3D for 2D textures.

Now I’m trouble with porting shaders from sampler2D to sampler2DArray.

Tessellation ev. shader before:

#version 400

layout(quads, fractional_even_spacing, cw) in;

in terrainVertex
{
    vec2 position;
} In[];

out worldVertex
{
    vec4 worldPosition;
    vec3 worldNormal;
    vec4 position;
    vec3 normal;
    vec2 texCoords;
} Out;

uniform sampler2D heightMap;

// The number of triangles created per height-map texel
uniform int maxTrianglesPerTexel = 10;

// Distance between each tessellation point at max tess level
uniform float horizontalScale = 10.0;

// Transformation matrices
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 worldNormalMatrix;
uniform mat3 normalMatrix;
uniform mat4 mvp;

const float maxTessLevel = 64.0;

void main()
{
    // Calculate extent of this patch in texture coords [0,1]
    vec2 patchExtent = maxTessLevel / (textureSize(heightMap, 0) * maxTrianglesPerTexel);

    // Calculate the texture coordinates
    Out.texCoords = In[0].position.xy + gl_TessCoord.xy * patchExtent;

    // Calculate the model-space position
    vec4 position;
    position.xz = Out.texCoords * horizontalScale;
    position.y  = texture(heightMap, Out.texCoords).r;
    position.w  = 1.0;

    // Transform the position to world coordinates and to eye space
    Out.worldPosition = modelMatrix * position;
    Out.position      = modelViewMatrix * position;

    // Calculate the normal
    // This could be moved to a one-time pre-process step to create a normal map.
    // This would be a good candidate for a compute shader.
    // For deformable terrain, would need re-generating when terrain is modified
    const ivec3 offset = ivec3(-1, 0, 1); // Texel offsets
    float delta  = 2.0 * horizontalScale / textureSize(heightMap, 0).x; // Horizontal displacement in world coords
    float left   = textureOffset(heightMap, Out.texCoords, offset.xy).r;
    float right  = textureOffset(heightMap, Out.texCoords, offset.zy).r;
    float top    = textureOffset(heightMap, Out.texCoords, offset.yz).r;
    float bottom = textureOffset(heightMap, Out.texCoords, offset.yx).r;

    vec3 x = normalize(vec3(delta, right - left, 0.0));
    vec3 z = normalize(vec3(0.0, top - bottom, delta));
    vec3 n = cross(z, x);

    Out.worldNormal = worldNormalMatrix * n;
    Out.normal      = normalMatrix * n;

    // Transform to clip-space
    gl_Position = mvp * position;
}

I don’t know how to use textureOffset(…) (left, right, top, bottom) in sampler2DArray, also texture(…) (position.y), textureSize(…) (patchExtent)

I read Array Texture - OpenGL Wiki so I should use “actual_layer = max(0, min(d​ - 1, floor(layer​ + 0.5)) )” ? And use for in shader? Is this correct way? I don’t think it’s correct way.

Thanks for help.

The texture functions work the same as for sampler2D, except that the coordinates contain an extra component to select the layer. For textureOffset, the offset parameter is still an ivec2 (i.e. the offset only applies to selection of texels within a layer, not the selection of a layer).

That just specifies that the layer is rounded to the nearest integer then clamped. Typically, the layer is an integer; although it may have been passed via a floating-point attribute, you wouldn’t normally interpolate it.

Ok, if its same then following code should be:

#version 400
#extension GL_EXT_texture_array : enable

layout(quads, fractional_even_spacing, cw) in;

in terrainVertex
{
    vec2 position;
} In[];

out worldVertex
{
    vec4 worldPosition;
    vec3 worldNormal;
    vec4 position;
    vec3 normal;
    vec2 texCoords;
} Out;

uniform sampler2DArray heightMap;

// The number of triangles created per height-map texel
uniform int maxTrianglesPerTexel = 10;

// Distance between each tessellation point at max tess level
uniform float horizontalScale = 10.0;

// Transformation matrices
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 worldNormalMatrix;
uniform mat3 normalMatrix;
uniform mat4 mvp;

const float maxTessLevel = 64.0;

void main()
{
    // Calculate extent of this patch in texture coords [0,1]
    vec2 patchExtent = maxTessLevel / (textureSize(heightMap, 0).xy * maxTrianglesPerTexel); // -- modified

    // Calculate the texture coordinates
    Out.texCoords = In[0].position.xy + gl_TessCoord.xy * patchExtent;

    // Calculate the model-space position
    vec4 position;
    position.xz = Out.texCoords * horizontalScale;
    position.y  = texture(heightMap, vec3(Out.texCoords, 0)).r; // -- modified
    position.w  = 1.0;

    // Transform the position to world coordinates and to eye space
    Out.worldPosition = modelMatrix * position;
    Out.position      = modelViewMatrix * position;

    // Calculate the normal
    // This could be moved to a one-time pre-process step to create a normal map.
    // This would be a good candidate for a compute shader.
    // For deformable terrain, would need re-generating when terrain is modified
    const ivec3 offset = ivec3(-1, 0, 1); // Texel offsets

    float delta  = 2.0 * horizontalScale / textureSize(heightMap, 0).x; // Horizontal displacement in world coords
    float left   = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.xy).r; // -- modified
    float right  = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.zy).r; // -- modified
    float top    = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.yz).r; // -- modified
    float bottom = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.yx).r; // -- modified

    vec3 x = normalize(vec3(delta, right - left, 0.0));
    vec3 z = normalize(vec3(0.0, top - bottom, delta));
    vec3 n = cross(z, x);

    Out.worldNormal = worldNormalMatrix * n;
    Out.normal      = normalMatrix * n;

    // Transform to clip-space
    gl_Position = mvp * position;
}

???

Sampler2D code:

#version 400

layout(quads, fractional_even_spacing, cw) in;

in terrainVertex
{
    vec2 position;
} In[];

out worldVertex
{
    vec4 worldPosition;
    vec3 worldNormal;
    vec4 position;
    vec3 normal;
    vec2 texCoords;
} Out;

uniform sampler2D heightMap;

// The number of triangles created per height-map texel
uniform int maxTrianglesPerTexel = 10;

// Distance between each tessellation point at max tess level
uniform float horizontalScale = 10.0;

// Transformation matrices
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 worldNormalMatrix;
uniform mat3 normalMatrix;
uniform mat4 mvp;

const float maxTessLevel = 64.0;

void main()
{
    // Calculate extent of this patch in texture coords [0,1]
    vec2 patchExtent = maxTessLevel / (textureSize(heightMap, 0) * maxTrianglesPerTexel);

    // Calculate the texture coordinates
    Out.texCoords = In[0].position.xy + gl_TessCoord.xy * patchExtent;

    // Calculate the model-space position
    vec4 position;
    position.xz = Out.texCoords * horizontalScale;
    position.y  = texture(heightMap, Out.texCoords).r;
    position.w  = 1.0;

    // Transform the position to world coordinates and to eye space
    Out.worldPosition = modelMatrix * position;
    Out.position      = modelViewMatrix * position;

    // Calculate the normal
    // This could be moved to a one-time pre-process step to create a normal map.
    // This would be a good candidate for a compute shader.
    // For deformable terrain, would need re-generating when terrain is modified
    const ivec3 offset = ivec3(-1, 0, 1); // Texel offsets

    float delta  = 2.0 * horizontalScale / textureSize(heightMap, 0).x; // Horizontal displacement in world coords
    float left   = textureOffset(heightMap, Out.texCoords, offset.xy).r;
    float right  = textureOffset(heightMap, Out.texCoords, offset.zy).r;
    float top    = textureOffset(heightMap, Out.texCoords, offset.yz).r;
    float bottom = textureOffset(heightMap, Out.texCoords, offset.yx).r;

    vec3 x = normalize(vec3(delta, right - left, 0.0));
    vec3 z = normalize(vec3(0.0, top - bottom, delta));
    vec3 n = cross(z, x);

    Out.worldNormal = worldNormalMatrix * n;
    Out.normal      = normalMatrix * n;

    // Transform to clip-space
    gl_Position = mvp * position;
}

From modified code I’m getting this.
There shouldn’t be any free space, where is the bug?

Did you bind it as GL_TEXTURE_2D_ARRAY in your (presuming) C++ code?

Ofc, following code is constructor and bind

// -- TextureType in header
    enum TextureType
    {
        Texture1DArray = GL_TEXTURE_1D_ARRAY,
        Texture2DArray = GL_TEXTURE_2D_ARRAY
    };

    TextureArray(int textureWidth, int textureHeight, int layersCount, TextureType textureType = Texture2DArray);

// -- constructor
TextureArray::TextureArray(int textureWidth, int textureHeight, int layersCount, TextureType textureType)
: type(textureType)
, textureId(0)
, width(textureWidth)
, height(textureHeight)
, layers(layersCount)
, GLfuncs(0)
{
    texels = new GLfloat[width * height * sizeof(float) * layers];
}


// -- bind
void TextureArray::bind()
{
    glBindTexture(type, textureId);

    GLfuncs->glTexStorage3D(type, 1, GL_RGBA32F, width, height, layers);
}

/// -- Create constructor of texture array in constructor of map tile
terrainMapData(new TextureArray(MAP_WIDTH, MAP_HEIGHT, CHUNKS * CHUNKS))

I looked in my code and for the glTexStorage function I use level of 0 and not 1. In fact setting it to 1 causes my FBO on that texture to be not complete. I have no clue why, all the references actually says it has to be at last 1.

GLfuncs->glTexStorage3D(type, 0, GL_RGBA32F, width, height, layers);

On a side note: are you sure that sizeof(float) is right inside a new GLfloat(). Looks to me that it just randomly gives you the right value 4 that you need for the 4 color components…

[QUOTE=Osbios;1255278]I looked in my code and for the glTexStorage function I use level of 0 and not 1. In fact setting it to 1 causes my FBO on that texture to be not complete. I have no clue why, all the references actually says it has to be at last 1.

GLfuncs->glTexStorage3D(type, 0, GL_RGBA32F, width, height, layers);

On a side note: are you sure that sizeof(float) is right inside a new GLfloat(). Looks to me that it just randomly gives you the right value 4 that you need for the 4 color components…[/QUOTE]

I just changed glTexStorage3D it show me whole terrain (just from loader), after initializing nVidia driver crashed. No idea why, I will investigate that.

Sorry I mixed up glTexStorage with glTexImage. The 1 for layer is correct!

So I should revert my change?

Yes. Like I said I mixed up the glTexStorage and glTexImage functions. Your parameters for glTexStorage3D are correct.

Then I’m where I was. On the start.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.