Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transparent parts in meshes shows what's behind the node, even if there are opaque mesh parts behind, depending on view angle #15762

Closed
nics-le opened this issue Feb 5, 2025 · 12 comments

Comments

@nics-le
Copy link

nics-le commented Feb 5, 2025

Luanti version

Luanti 5.11.0-dev (Linux)
Using LuaJIT 2.1.0-beta3
Built by GCC 11.4
Running on Linux/6.8.0 x86_64
BUILD_TYPE=Release
RUN_IN_PLACE=0
USE_CURL=1
USE_GETTEXT=1
USE_SOUND=1
STATIC_SHAREDIR="/usr/share/luanti"
STATIC_LOCALEDIR="/usr/share/locale"

Operating system and version

KDE neon 6.2

CPU model

Intel® Core i7-8565U

GPU model

NVIDIA GeForce MX250

Active renderer

4.6 / opengl3 / SDL

Summary

I made a obj mesh in blender:

Image
outer parts are fully opaque, that cube inside has transparency. But if I change my position:

Image

it looks this way.

This is my code for node registration:

minetest.register_node("beer_test:mesh_barrel_10", {
    description = "Mesh Barrel 10L",
    tiles = {
		{name = "beer_test_barrel_side_2.png", backface_culling = false},
		{name = "beer_test_barrel_side.png", backface_culling = false},
		{name = "beer_test_barrel_top.png", backface_culling = false},
		{name = "default_water_source_animated.png^[opacity:180",
		animation = {
			type = "vertical_frames",
			aspect_w = 16,
			aspect_h = 16,
			length = 2.0,
		}, backface_culling = false}
	},
    paramtype2 = "none",
    groups = {cracky=2},
    sounds = default.node_sound_wood_defaults(),
    use_texture_alpha = "blend",
    drawtype = "mesh",
    paramtype = "none",
    mesh = "barrel_10.obj"
})

The faces of the "liquid cube" and the barrel part does not touch each other in this case (was just a try).
Is it a bug in Luanti or am I using the API in a wrong way?

Steps to reproduce

Create or get any mesh from any source with at least two materials, one is opaque one has transparency.
The parts of the mesh must be arranged in a way that you can look through the transparent part to the opaque part.

Depending on the angle from where you are looking you will see the opaque part or what's behind the node

@nics-le nics-le added the Unconfirmed bug Bug report that has not been confirmed to exist/be reproducible label Feb 5, 2025
@appgurueu
Copy link
Contributor

The problem ultimately is that your entire node is dealt with in the semitransparent pass. (There is no feature to let you "mark" a specific material as "blend" and another one as "opaque"; to the engine the entire node is "blend".)

This means you get all of the problems of semitransparency. Either you have transparency sorting disabled (what is your transparency_sorting_distance set to?) or transparency sorting has a bug.

@nics-le
Copy link
Author

nics-le commented Feb 6, 2025

Thanks for your fast reply :). In my case transparency_sorting_distance is set to 16. Is that an appropriate value?

@nics-le
Copy link
Author

nics-le commented Feb 6, 2025

Ahhh, I got it! transparency_sorting_group_by_buffers was enabled. Because this is the default value (due to performance reasons) I don't think it's a good idea to rely on that users will disable this option. Is there a better way to implement sth. similar? maybe as two nodes? Or should I avoid transparency?

@appgurueu
Copy link
Contributor

Ahhh, I got it! transparency_sorting_group_by_buffers was enabled. Because this is the default value (due to performance reasons) I don't think it's a good idea to rely on that users will disable this option.

It's a tradeoff unfortunately. I've seen many users disable transparency sorting entirely because it is simply too resource hungry. So far it seems that some semitransparency rendering issues are the smaller problem.

Or should I avoid transparency?

If possible: Yes.


As for a proper solution for at least your issue, I think it would suffice if use_texture_alpha could be specified on a per-tile basis (similar to backface_culling), with the node use_texture_alpha as the default. Your node would then have use_texture_alpha = "clip" (or "opaque" even); only the water surface would have use_texture_alpha = "blend" (and would thus be rendered in the semitransparent pass, after the solid surfaces have been rendered).

@Desour
Copy link
Member

Desour commented Feb 6, 2025

For an immediate fix, you could also use just one tile for the node.

For a good fix in the engine, we need texture atlasing or array textures.

@sfan5 sfan5 added Question and removed Unconfirmed bug Bug report that has not been confirmed to exist/be reproducible labels Feb 7, 2025
@nics-le
Copy link
Author

nics-le commented Feb 8, 2025

For an immediate fix, you could also use just one tile for the node.

You mean having the liquid part as separate transparent node using just one tile?

@nics-le
Copy link
Author

nics-le commented Feb 8, 2025

As for a proper solution for at least your issue, I think it would suffice if use_texture_alpha could be specified on a per-tile basis (similar to backface_culling), with the node use_texture_alpha as the default. Your node would then have use_texture_alpha = "clip" (or "opaque" even); only the water surface would have use_texture_alpha = "blend" (and would thus be rendered in the semitransparent pass, after the solid surfaces have been rendered).

This is an interesting solution. I'm not into minetest code and cpp but the solution you are describing sounds like a much simpler logic then having complex transparency sorting distances. Maybe it could be a cheap (in terms of computing resources) way to allow more complex nodes with semi-transparency?

Do you think it's worth it to create a new feature request from it?

Btw I really appreciate Luanti's attempt to keep it playable on older machines, as well as from a social and an environmental point of view :)

@Desour
Copy link
Member

Desour commented Feb 8, 2025

For an immediate fix, you could also use just one tile for the node.

You mean having the liquid part as separate transparent node using just one tile?

No. You can do it with one node. You do some uv mapping and put the water and wood textures in one texture. The result is that all faces use alpha blending, but they're all in one mesh buffer, so it will be sorted correctly.

Do you think it's worth it to create a new feature request from it?

Having per-tile alpha mode makes sense anyway. Idk why it isn't like this already.

@nics-le
Copy link
Author

nics-le commented Feb 8, 2025

@Desour

For an immediate fix, you could also use just one tile for the node.

You mean having the liquid part as separate transparent node using just one tile?

No. You can do it with one node. You do some uv mapping and put the water and wood textures in one texture. The result is that all faces use alpha blending, but they're all in one mesh buffer, so it will be sorted correctly.

Thank you for your advice and it worked, but during trying this approach I noticed some interesting behaviour:

First I have to say that I left the different materials of my mesh, but assigned the same tile to all of them. Since I increased opacity of water during copying the texture there were no need to add opacity modifier anymore. It worked:

tiles = {
		{name = "barrel_combined.png", backface_culling = false}, -- I know I could remove the other tiles
		{name = "barrel_combined.png", backface_culling = false},
		{name = "barrel_combined.png", backface_culling = false},
		{name = "barrel_combined.png", backface_culling = false},
	},

But I played around with tile settings, added opacity modifier again and noticed that this "complete see through" issue only happens if I assign different values to opacity. So this:

    tiles = {
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
		{name = "barrel_combined.png^[opacity:180]", backface_culling = false},
	},

results in this:

Image

But If I set all of them to the same value:

    tiles = {
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
		{name = "barrel_combined.png^[opacity:190]", backface_culling = false},
	},

it looks like this:

Image

I think that means that I don't have to combine the textures as long as I do not use opacity modifier (or at least do not use different values inside a node)

@Desour
Copy link
Member

Desour commented Feb 8, 2025

Materials (tiles) that are the same (same texture, same backface culling, ...) are grouped together by meshgen. So this is expected. :)

@nics-le
Copy link
Author

nics-le commented Feb 8, 2025

Materials (tiles) that are the same (same texture, same backface culling, ...) are grouped together by meshgen. So this is expected. :)

ahh, now I got it! :)

Thanks again for your help (both of you). I think I can close this issue now

@nics-le nics-le closed this as completed Feb 8, 2025
@appgurueu
Copy link
Contributor

Side note: barrel_combined.png^[opacity:180] is not a valid texture modifier (even though Luanti may allow it presently). You need to remove the final ]. (Yes, texture modifiers use unmatched brackets like that.) :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants