Fake texture mipmapping with Geometry Nodes and/or python?

Hi everyone, as the title says, could it be possible to have something like texture mip mapping (switch texture resolution) in Blender based on the camera distance?
Something similar to LODs but not for geometry but texture resolution?

If not with GN, can it be done with python? I’m not good at all with coding so any help/pointers will be greatly appreciated, thank you!

Hi @julperado,

Is this with respect to an animation that you will be rendering out or for realtime viewing in Blender?

I am not sure if it is possible to implement mipmaps the way they are done in other tools, but one way I can think of that doesn’t involve writing code is to do this using Shader Nodes. You could use the View Distance (or View Z Depth) attribute of the Camera Data node, define distance thresholds using a Math node (or Color Ramp) and use it mix textures of different resolutions. Refer to this StackExchange question for more information.

Of course, like you see in the screenshots on that question, there would be certain distances at which you would see textures of two different resolutions, but I think with some Vector Math exploration, you can workaround this. I think a similar solution might be possible with the Set Material node in Geometry Nodes, but I haven’t extensively used it.

The other possible solution I can think of involves writing some code. You could write a handler that get’s triggered every time the camera moves, use it to dynamically calculate the distance of each object (or a terrain tile) from the camera and accordingly assign a higher or lower resolution texture to the material.

If this is an animation that will be rendered out, you could use a frame change handler so that it gets triggered every time the frame changes. Or if this is for realtime viewing you could use a depsgraph update handler so that even if you move the camera manually (without a frame change) it would still trigger an update.

Thanks for your answer Salai!
Yes, I didn’t explain very well but it is for rendering. The project we’re working on right now is getting increasily complex when it comes to renders, because there’s a lot of characters/props/sets and the RAM consumption to load all the textures is higher on each episode.
I’ll check the links you provided and come back if I have any questions (I probably will hehe).

For now I have one more question, is there a tool that can automate the creation of the different resolutions for each texture? Right now I’m thinking of using actions in Photoshop, but if there’s a way to do it directly in Blender it would be best.

You could do that with a script, using the PIL (Python Image Library) module, which I believe comes packed in with Blender.

Here is a small script to demonstrate:

import bpy
from PIL import Image
import os

image = '161222.PNG'
filepath = bpy.data.images[image].filepath

LOD0 = Image.open(filepath)

resolution = LOD0.size
LODs = ['LOD1', 'LOD2', 'LOD3', 'LOD4']

for i, LOD in enumerate(LODs):
    i = i + 2
    width = int(resolution[0] / i)
    height = int(resolution[1] / i)

    newsize = width, height
    LOD = LOD0.resize(newsize)  
    name = f'161222_LOD{i - 1}.PNG'

    directory = os.path.dirname(filepath)
    path = os.path.join(directory, name)
    LOD.save(path, 'PNG')
    bpy.ops.image.open('EXEC_DEFAULT', filepath=path)

It takes an original image, and creates new images at half, third and quarter resolutions, then opens them up in the Image Editor to be viewed.

PIL has quite a few features in terms of scaling and interpolation, so if the results are not what you hoped for, there are some settings you can play around with.

Also, my script uses the resize method which lowers the size of the image, as well as its resolution, there is also a thumbnail method which will downsample the image but maintain the size.

2 Likes

…it is for rendering. The project we’re working on right now is getting increasily complex when it comes to renders, because there’s a lot of characters/props/sets and the RAM consumption to load all the textures is higher on each episode.

If it’s for rendering, then the Shader Nodes won’t cut it. Because, I think, invariably all resolution variants of the texture will be loaded onto the memory when the render begins, since all of them are present in the node tree.

I think you might have to take the latter route of writing a custom script that swaps and assigns the right resolution texture dynamically, since in that case only that specific resolution will be loaded onto the memory.

This wouldn’t be much of a problem for realtime viewing though, because in that case you would want to optimize viewport drawing rather than just memory consumption.

I’ll check the links you provided and come back if I have any questions (I probably will hehe).

Sure, let me know. Happy to help.

…is there a tool that can automate the creation of the different resolutions for each texture?

I think @SpectralVectors’s solution should work like a charm for this.

3 Likes

Thanks for your help guys! I really appreciate it!
I’m at absolute zero when it comes to python so I’ll probably have to do a lot of trial and error before get it to work properly but your pointers are already VERY useful :clap:

1 Like