[Solved] TextureArrays and MultiSampling


#1

holas jMonkeys,

as the title suggests, I’m having trouble getting TextureArrays to work with MultiSampling.
First off a question to make sure i actually understand what jme provides out of the box in terms of multisampling:

The “Samples” setting in the default settings dialogue as well as the specific set- and get-methods for samples in the AppSettings-class are only relevant for FilterPostProcessors.
Other materials like Unshaded and Lighting as well as anything else does not make use of the samples setting?
Sure also filterPostProcessors dont make use of this settings “out of the box”, you have to explicitly set this value, but you get what i mean

Assuming this is true, is there no point in multisampling when drawing objects or is it just not build in?

I can see some pixels not drawn correctly on my voxel terrain when i set samples greater than 1 since i only use FXAA when samples is 1.
The WaterFilter seems to make use of multisampling, so does my FogShader and both seem to work also for samples greater than 1.

However, when i tried to add multisampling capability to the voxelshader i only ended up with fully black drawn chunks.
Here is my attempt:

I start my fragment shader with this (basically adopted from the MultiSampling.glsllib)

#extension GL_ARB_texture_multisample : enable

#if defined(GL_ARB_texture_multisample) && defined(RESOLVE_MS)
    #define COLORTEXTURE sampler2DMSArray
    vec4 fetchTextureSample(in sampler2DMSArray tex,in vec3 texC,in int sampleId){
        ivec3 iTexC = ivec3(texC.xy * vec2(textureSize(tex)), texC.z);
        return texelFetch(tex, iTexC, sampleId);
    }
#else
    #define COLORTEXTURE sampler2DArray

    vec4 fetchTextureSample(in sampler2DArray tex,in vec3 texC,in int sampleId){
        return texture(tex,texC);
    }
#endif

uniform COLORTEXTURE m_TextureArray;

later in the shader i read the color like so:

vec4 texColor = fetchTextureSample(m_TextureArray, finalTexCoord, sampleNum);

when i change the vec4 fetchTextureSample(in sampler2DMSArray tex,in vec3 texC,in int sampleId) to:

    #define COLORTEXTURE sampler2DArray
    vec4 fetchTextureSample(in sampler2DArray tex,in vec3 texC,in int sampleId){
        return texture(tex,texC);
    }

and basically disable the multisampling, the colors reappear and everything look as expected except for the few aliased pixels that i try to eliminate
from what i get, texelFetch expects the coords in texelSpace or what its called, meaning not 0-1 but 0-SIZE, thus the ivec3 with the transformation

i already played around with the texcoord values that i provide the fetchTextureSample() method with. Since the chunks are perfectly black i thought it might be the 3rd component (the texture layer) thats wrong but i dont see how they should differ

Also i read that for multisampling, the texture array should not have mipmaps, but either the mipmaps are generated silently behind the scenes or turning it off actually doesnt change anything, since i still get black chunks. in case the code for setting up the textureArrays is relevant i can post it too

As always, thanks a lot for any idea and many greetings from the shire,
samwise


#2

The code you are talking about is not doing multisampling, it is resolving it, ms is done before during the rendering.

The question is: what does your TextureArray contain? Does it contain ms data?

Also, your code doesn’t look right, if sampleNum is the the number of samples, you are fetching only one sample outside the texture memory, this would cause crash or garbage data (that’s probably what you are seeing).
For colors, a simple resolver that averages the samples, looks like this

vec4 resolve(in sampler2DMS tex,in vec2 texC){
    vec4 outColor=vec4(0);
    ivec2 iTexC = ivec2(texC * vec2(textureSize(tex)));
    for (int i = 0; i < NUM_SAMPLES; i++)outColor += texelFetch(tex, iTexC, i);    
    outColor /= float(NUM_SAMPLES);
    return outColor;
}

#3

thanks a lot for your quick reply.

im sorry for the inconsistency in the naming, it was actually meant to be “sampleId”, it is meant to be for one sample lookup only, the method itsself is eventually called in a loop
That has sideeffects and i should adopt your approach to make sure i only sample the texture several times, not the normalmap etc but it was for quick testing only and with the replacement function i mentioned it still works perfectly fine…

im not sure i understand the question about what my texture array contains.
i set it up by loading some textures using the assetManager, those textures come from 256x256 png files 8bpc RGBA, create a list to which i append the images of these textures and create a texturearray using this list for the constructor.

Am i supposed to do it differently?

And since i got vec3 for texturecoords would that function you posted translate to:

vec4 resolve(in sampler2DMSArray tex, in vec3 texC){
    vec4 outColor=vec4(0);
    ivec3 iTexC = ivec3(texC.xy * vec2(textureSize(tex)), texC.z);
    for (int i = 0; i < NUM_SAMPLES; i++)outColor += texelFetch(tex, iTexC, i);    
    outColor /= float(NUM_SAMPLES);
    return outColor;
}

no special treatment for the 3rd component?


#4

No, it should be

    ivec3 iTexC = ivec3(texC.xyz * vec3(textureSize(tex)));

But i think you are confusing ms with texture filtering, ms is used to smooth the pixels at the edges between polygons, you can’t use it like that, you need to render your scene first and then resolve it.


#5

well unfortunately that sounds like it would make sence :smiley:
the thing is, since i use greedy meshing, i sometimes got faces like so:

___________
|         |
|____V____|
|    |    |
|____|____|

and at the bottom of the “V” where 3 faces meet i sometimes get 1 pixels that is not considered to be part of the chunk and instead draws something behind it.
EDIT: when i look closer it seems like those pixels sometimes appear all along the shared edge of faces that do not have the same start- and endpoint for this line, which makes more sence, i guess for those shared edges that have the same start- and endpoint the rasterizer produces the same output and thus there is no pixel left somewhere (not talking about shared vertices just meaning the exact same position in space)

from what i get FXAA “solves” the problem by doing some sort of blurring
and since i read FXAA can be used when actual multisampling is turned off i was searching for a way to do actual multisampling with my chunks
but from what you tell me FXAA just solves my problem as a sideeffect and multisampling the way i had planned it would not fix my problem

so the only solution is to draw the scene onto a texture that is bigger than the screen and then i can do some sort of multisampling when scaling down?


#6

I’m not sure if i understand the issue. Do you have an image that shows it?


#7

aliased_zoomed
you might need to rightclick -> show or view or whatever its called in your locale version and then zoom a little
since its not at the border of the drawn chunk i thought this multisampling approach would make sence but technically it actually is at the border of the drawn chunk due to how my chunks are meshed so im not sure how to solve it


#8

Yes, this looks like an aliasing issue, in that case you can use MSAA, but as i said, not in the way you have been using it.

Let’s say you want 4xMSAA

  • If you want to enable msaa on the default framebuffer (usually you want this if you don’t use post processing)
    settings.setSamples(4);

  • If you have a FilterPostProcessor, and you want to enable msaa for the render pass before the postprocessing
    fpp.setNumSamples(4);
    This will also tell the filters how many samples they need to resolve

– Note: if you have custom filters that deal with unresolved texture (eg depth and color you get out from your rendering pass), you need to implement the code needed to resolve them like in the filters shipped with jme (and this is basically the code you posted here)


#9

thanks, that clarifies a lot
i am always using a filterpostprocessor.
so if samples is greater than 1 i should setNumSamples(samples) on the fpp and if samples is 1 i can add a FXAAFilter?
if then all the filters are aware of that and use the resolving function instead of the usual texture(…) function when samples is greater than 1, this should “automatically” get rid of the aliasing?
“Automatically” in terms of i dont have to change a single line with the voxel-shader (well i would have to change it back to not do any texture resolving thing), i only have to check the filters in the filterpostprocessor?


#10

Exactly, also note that there is nothing wrong in using fxaa together with msaa, since fxaa will deal with any type of edges that it can detect, being them part of geometries, textures or the result of post processing.


#11

i have checked all the filters and made sure i did everything as it is supposed to be done (hopefully) but still there sometimes are those pixels appearing. however fxaa basically eliminates it completly and when you tell me there is no harm in using both eventually, ill stick with that.

thanks a lot for your help again