Approach to show low res texture on objects far away and high res when close?

Started by Windmiller, November 05, 2021, 09:41:31 PM

Previous topic - Next topic

Windmiller

Hi!

I was thinking about different approaches to load low res textures to apply on a 3D object that is far away and load and apply high res when getting closer, but how to know what size of texture the device can handle before getting out of memory or something like that?
Someone who has an idea, and would like to think me in the right direction.
Should I use and count on the different resolution "res" folders in Android or is there a better solution?

Regards..

AeroShark333

Hey!

I believe the distance-based texture quality thing you're talking about could be done with mipmapping with distance-based level of detail (LOD) texture fetching.

I believe jPCT has support for mipmapping but I've found it a little buggy for myself... (Or I'm just not sure how to make use of it properly)
I'm not sure if default shaders use this...

I believe for this technique, you should take into account that twice the memory consumption of the base texture is necessary. (With a peak of 4 times the memory consumption of a single base texture with default jPCT texture loading (I'm not entirely sure about this, however)).








LODResolution
Level 0 (base)8x * 4x
Level 14x * 2x
Level 22x * 1x
Level 31x * 0.5x
Level 4etc...
with x being some resolution scaling factor...

I believe if your texture loading 'algorithm' is efficiënt you could probably get away with loading textures at at a maximum peak memory consumption of just twice the base texture memory consumption.

The memory consumption of a single texture can be calculated approximately as follows:(https://www.jpct.net/wiki/index.php/Reducing_memory_usage)
Remember: 8 bits = 1 byte

Higher color quality:
For 32-bit: width * height * 4 bytes
For 24-bit: width * height * 3 bytes (no alpha)

Lower color quality:
For 16-bit: width * height * 2 bytes
For 12-bit: width * height * 1.5 bytes (no alpha)

So for example:
Let's say you have a 32-bit texture of 8192 by 4096 pixels.
The memory consumption can be calculated with the above formula.
This would result in approximately 130 MB.
When doing mipmapping, the memory consumption will be nearly doubled, so that'd be 260MB.
I believe that with jPCT's default texture loading algorithm, it'd be doubled in peak memory consumption for both scenarios.
260 MB without mipmapping, 520 MB with mipmapping.

Maybe something else that could be useful:
https://www.jpct.net/forum2/index.php/topic,5135.0.html
I guess it could be extended to allow for more efficient texture loading and also mipmapping... Mind that Android makes a distinction between loading textures to (J)VM memory and native memory, where the first is usually more limited...

Hope this was useful in some way! :)

EgonOlsen

Quote from: AeroShark333 on November 06, 2021, 08:47:20 AM
I believe jPCT has support for mipmapping but I've found it a little buggy for myself... (Or I'm just not sure how to make use of it properly)
It's actually a hardware thing. If it doesn't work, it's a driver thing o, on very old devices, an issue with the graphics chip. But other than that, it should work just fine.... ???

AeroShark333

Quote from: EgonOlsen on November 06, 2021, 06:37:58 PM
Quote from: AeroShark333 on November 06, 2021, 08:47:20 AM
I believe jPCT has support for mipmapping but I've found it a little buggy for myself... (Or I'm just not sure how to make use of it properly)
It's actually a hardware thing. If it doesn't work, it's a driver thing o, on very old devices, an issue with the graphics chip. But other than that, it should work just fine.... ???
If I remember correctly, I got black textures on some devices when using either non-square (but still POT) or NPOT textures. I believe the only way I could force to make it work was to first convert it/stretch it to a POT square texture... But yeah, memory... So I believe I didn't try to bother to go into it that much anymore

Windmiller

Thanks for all the information, it will definitely be useful, a great useful read. Mipmap was a long time ago so I will need to read a more about that to bring the memories back. Thanks again :)

EgonOlsen

Quote from: AeroShark333 on November 07, 2021, 01:25:52 AM
If I remember correctly, I got black textures on some devices when using either non-square (but still POT) or NPOT textures. I believe the only way I could force to make it work was to first convert it/stretch it to a POT square texture... But yeah, memory... So I believe I didn't try to bother to go into it that much anymore
Yes, that's an issue indeed. It's a driver/hardware limitation, not jPCT-AE's fault. It shouldn't be a problem on any modern hardware though.

Windmiller

But what about tiling textures, repeating a small one instead of stretching them out? I found a function that seems to belong to this and that's the Texture.setClamping()??
Or do I have to map it myself in like Blender, isn't it possible to do without special UV coords made in Blender? I mean I can´t test this with the Primitives objects?

Regards

AeroShark333

Hmmm, what I would do myself is probably this:
- Texture#setClamping(false) => so it goes into texture repeating mode.
- Scale the UV coordinates with the amount of repetitions you want in each direction (instead of the usual 0.0 to 1.0, it'll go from 0.0 to N*1.0, where N is the amount of repetitions in the U or V direction).

Since I assume you don't want to do the second option... Here's what I'd suggest still:
I think you should be able to retrieve UV coordinates from an Object3D: https://www.jpct.net/jpct-ae/doc/com/threed/jpct/PolygonManager.html#getTextureUV-int-int-
I am missing a setTextureUV() method here though...
In the end, I believe https://www.jpct.net/jpct-ae/doc/com/threed/jpct/Object3D.html#setTextureMatrix-com.threed.jpct.Matrix- might be your best bet for scaling/offsetting UV coordinates
I'm not entirely sure if this will give the desired results, however...

EgonOlsen

Quote from: AeroShark333 on November 18, 2021, 12:56:35 PM
Since I assume you don't want to do the second option... Here's what I'd suggest still:
I think you should be able to retrieve UV coordinates from an Object3D: https://www.jpct.net/jpct-ae/doc/com/threed/jpct/PolygonManager.html#getTextureUV-int-int-
I am missing a setTextureUV() method here though...
There is one, just not in the way in which you expect it to be. What you have to do is to grab the information you need from the various methods in the PolygonManager, create a TextureInfo-Instance from these and assign it to the polygon by using setPolygonTexture(). This code from the wiki has an example of that in the setTexture()-method where I'm tiling a terrain texture: https://www.jpct.net/wiki/index.php?title=Texture_splatting_on_a_terrain

Quote
In the end, I believe https://www.jpct.net/jpct-ae/doc/com/threed/jpct/Object3D.html#setTextureMatrix-com.threed.jpct.Matrix- might be your best bet for scaling/offsetting UV coordinates
That should work as well, I think...

AeroShark333

Quote from: EgonOlsen on November 18, 2021, 01:31:12 PM
There is one, just not in the way in which you expect it to be. What you have to do is to grab the information you need from the various methods in the PolygonManager, create a TextureInfo-Instance from these and assign it to the polygon by using setPolygonTexture(). This code from the wiki has an example of that in the setTexture()-method where I'm tiling a terrain texture: https://www.jpct.net/wiki/index.php?title=Texture_splatting_on_a_terrain
Ah... yes, I forgot TextureInfo holds UV information... My bad

Windmiller

Hi, and thanks!

You´re great, both of you, thanks a lot really appreciate your help :)
Makes sense, I'll try this.


Windmiller

Now I'm getting somewhere.. but not quite enough :(

I'm using this code


private static void setTexture(Object3D obj) {
        TextureManager tm = TextureManager.getInstance();

        obj.calcBoundingBox();

        float[] bb = obj.getMesh().getBoundingBox();

        float minX = bb[0];
        float maxX = bb[1];
        float minZ = bb[4];
        float maxZ = bb[5];
        float dx = maxX - minX;
        float dz = maxZ - minZ;

        float dxs = dx;
        float dzs = dz;

        dx /= 10f;
        dz /= 10f;

        float dxd = dx;
        float dzd = dz;

        int tid = tm.getTextureID("entityTexturePlanet");
        //int sid = tm.getTextureID("rocks");
        //int trid = tm.getTextureID("sand");
        //int bid = tm.getTextureID("splat");

        PolygonManager pm = obj.getPolygonManager();
        for (int i = 0; i < pm.getMaxPolygonID(); i++) {
            SimpleVector v0 = pm.getTransformedVertex(i, 0);
            SimpleVector v1 = pm.getTransformedVertex(i, 1);
            SimpleVector v2 = pm.getTransformedVertex(i, 2);

            // Assign textures for the first three layers (the "normal"
            // textures)...
            TextureInfo ti = new TextureInfo(tid, v0.x / dx, v0.z / dz, v1.x / dx, v1.z / dz, v2.x / dx, v2.z / dz);
            //ti.add(sid, v0.x / dxd, v0.z / dzd, v1.x / dxd, v1.z / dzd, v2.x / dxd, v2.z / dzd, TextureInfo.MODE_ADD);
            //ti.add(trid, v0.x / dxd, v0.z / dzd, v1.x / dxd, v1.z / dzd, v2.x / dxd, v2.z / dzd, TextureInfo.MODE_ADD);

            // Assign the splatting texture...
            //ti.add(bid, -(v0.x - minX) / dxs, (v0.z - minZ) / dzs, -(v1.x - minX) / dxs, (v1.z - minZ) / dzs, -(v2.x - minX) / dxs, (v2.z - minZ) / dzs, TextureInfo.MODE_ADD);
            pm.setPolygonTexture(i, ti);
        }
    }


It's your code Egon, but it's quick and dirty and I'm only using one texture in it and changed the image to a sandy image, with the size 512x512.
It looks fine most of the sphere but there's a border going 360 around the sphere as seen in the image. (the image is pretty dark but I hope you'll see what I'm talking about here)

How can I solve this big bad border on my sphere?
What is it that I'm not understanding here, scratching my head.
I know it has something to do with that my object is a Primitives.getSphere(..); but hmm

Thanks in advance

I've learnt something from this thread https://www.jpct.net/forum2/index.php/topic,2190.msg16243.html#msg16243
And that's that the Primitives UV are kind of basic. But I still got the border :(
It seems that the code I'm using is for flat surfaces only? Doesn't make it right for a sphere.

I have a perfect Sphere with UV mapped textures in it that I've made in Blender, is there a way to apply multi textures to these UV coordinates with a function like yours Egon? So that I programmatically can add "Splatter Texture" to it?

EgonOlsen

Yes, that's because the object gets textured based on its vertices' positions in space, not on its previous texture coordinates. Assuming that the sphere itself has proper coordinates, you shold get them via https://www.jpct.net/jpct-ae/doc/com/threed/jpct/PolygonManager.html#getTextureUV-int-int- and then do something like


TextureInfo ti = new TextureInfo(tid, u0, v0, u1, v1, u2, v2);


instead of


TextureInfo ti = new TextureInfo(tid, v0.x / dx, v0.z / dz, v1.x / dx, v1.z / dz, v2.x / dx, v2.z / dz);


For splatting, just multiple these coodinates with some value and assign them to another layer.