Three Fiber not showing transparent png texture

I would like to display a small logo, a transparent png, on the back of each tile in my game. However, the png is not displaying.

Here is the png:

enter image description here

Here is the code for the texture:

import { TextureLoader } from 'three/src/loaders/TextureLoader';

import { useLoader } from '@react-three/fiber'

import * as THREE from 'three'

export default function Tile() {
    ...
    const tileBackTexture = useLoader(THREE.TextureLoader, './presets_library/Tile_Back_Logo.png')
	const tileBackTextureMaterial = new THREE.MeshBasicMaterial({ 
		map: tileBackTexture, 
		alphaMap: tileBackTexture,
		transparent: true,
		side: THREE.DoubleSide,
		alphaTest: 0.5,
		depthWrite: false,
		opacity: 0.0,
	});
    ...
    return (
        <mesh geometry={nodes.Tile_Back_Face.geometry} material={tileBackTextureMaterial} />
    )
}

Here is the result:

enter image description here

With the model, I made a separate, floating face just for the loaded texture. I have made sure that the png itself had a transparent background. With loading the texture, I made sure transparent was set to true, map was set to the loaded png, that alphaMap was set to the loaded png, but nothing changed.

I’ve also tried making the png smaller, adding an opacity attribute, but I can’t seem to find what might be preventing it from showing up.

If anyone knows what might be going wrong, please let me know.

Thank you.

Update:

Even drawing the image on a canvas and using that image to create the texture and material doesn’t show it:

	let img = new Image();
	img.crossOrigin='Anonymous';
	
	let ctx = canvasRef.current.getContext('2d', { alpha: true, desynchronized: false, colorSpace: 'srgb', willReadFrequently: true})
	ctx.globalCompositeOperation = "copy";

	img.onload = function () {
		ctx.width = img.width;
		ctx.height = img.height;
		ctx.imageSmoothingEnabled = false;
		
		ctx.drawImage(img, 0, 0);
	}

	img.src = './presets_library/Tile_Back_Logo_Small.png';
	
	const texture = new THREE.Texture(canvasRef.current);
	
	const material = new THREE.MeshBasicMaterial({ 
		map: texture,
		alphaMap: texture, 
	});

The canvasRef is displaying the png, yet for some reason can’t be seen on the tiles.

All you need is transparent=true map=texture. If the image is transparent it will work.

I am confused, is react fiber threejs?

My apologies, I should have proofread that. I meant to say React Three Fiber, which uses React js and Three js

There must be something wrong with the png I made. The weird thing though is for some reason it seems to have no problems when embedding it here, or displaying it on a canvas element.

nothing wrong with that png vigorous-jepsen-4m9kl9 - CodeSandbox

<meshBasicMaterial transparent map={texture} />
1 Like

I tried doing a material jsx within a mesh element, but it still won’t work. It seems that svgs work ok, so I just made the logo an svg and added all of its shapes together into a group. Thank you all for your help!

there has to be something wrong with how you define a material then. the example above uses your png from the first post and as you see it’s transparent. all you need in threejs is that one flag “transparent”, nothing else, no depthtest, alphamap etc.

Just to clarify, use only a map and a transparent attribute? If that is the case, it does not display it either.

you need to open the sandbox i posted, it’s there, you see it working? there is no different between fiber and three, fiber is threejs and all rules apply. in threejs you don’t need anything but a material, a transparent flag, a map prop pointing to a texture that has an alpha channel, like the png you posted.

1 Like

Yes, I see it. Thank you so much for this example! I will try it again.

Update: SUCCESS! Thank you for your time and patience with my issue, your example has taught me a lot.

I think I should have just used a plane geometry like in your example, instead of trying to use a floating face from the model as the geometry. Also, instead of doing useLoader to get the texture, and then making a new material based on that texture, I should have just used the useTexture hook from your example, because less steps!

1 Like

useloader(three.textureloader, url) is fine, but usetexture does a little more than just loading. in threejs textures aren’t uploaded to the gpu until they are “seen” by a camera and rendered out. this creates bad runtime jank. imagine your mesh is not visible at first, and while the game/app is running you bump into it and suddenly it freezes because of upload. usetexture pre-emptively uploads. most extra loading hooks in drei do things like that. useloader(gltfloader, url) for instance doesn’t deal with draco, gltfloader doesn’t know how, but drei usegltf sets it up ootb, … if there’s a drei hook there’s usually a good reason.

Wow, I had no idea it worked that way. Where did you learn this deep understanding of useLoader and drei Hooks? Is such an explanation found in the documentation? It might help for me to read up on it. I guess drei is more helpful than I thought, and I should be implementing it much more. Thanks for this detailed explanation, drcmda!

i made these hooks. :wink:

That definitely does help! :joy: