Reputation: 4124
I would like to render a translucent PNG texture behind a see-through Physical Material. However, THREE.js doesn't render the translucent texture through the Physical Material at all.
I figured out that setting transparent: false
on the material makes it visible, but that obviously makes my texture opaque, which is not what I want.
How can I make a translucent PNG texture visible through Physical Material?
$(document).ready(() => {
const renderer = new THREE.WebGLRenderer({
canvas: document.getElementById('canvas'),
});
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0000ff);
scene.add(new THREE.AmbientLight(0xffffff, 1));
const texture = new THREE.TextureLoader().load('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE4AAABOCAYAAACOqiAdAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADdSURBVHhe7dAhCgIBFADR1SgYLDatHsv7n2ItXzDILg7Y3ivT57Cu63P57jHdcpvuuU63XKZ7ztO30/TTffo3xyk/Mi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi4yLjIuMi5ZlhcxLwSYJ4qy6wAAAABJRU5ErkJggg==');
const camera = new THREE.PerspectiveCamera(65, renderer.domElement.clientWidth / renderer.domElement.clientHeight, 0.1, 1000);
{
const geometry = new THREE.PlaneGeometry(4, 4);
const material = new THREE.MeshStandardMaterial({
color: 0xffff00,
side: THREE.DoubleSide,
});
const plane = new THREE.Mesh(geometry, material);
plane.position.z = 1;
scene.add(plane);
}
{
const geometry = new THREE.PlaneGeometry(3, 3);
const material = new THREE.MeshStandardMaterial({
color: 0xff0000,
side: THREE.DoubleSide,
map: texture,
transparent: true,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
document.getElementById('transparent').onchange = (evt) => {
material.transparent = evt.target.checked;
material.needsUpdate = true;
};
}
{
const geometry = new THREE.PlaneGeometry(3, 3);
const material = new THREE.MeshPhysicalMaterial({
side: THREE.DoubleSide,
roughness: 0.2,
transmission: 0.8,
color: 0xffffff,
});
const plane = new THREE.Mesh(geometry, material);
plane.position.z = -2;
plane.position.x = 1;
scene.add(plane);
}
const startTime = performance.now();
function render() {
const now = performance.now();
const angle = (now - startTime) * 0.002;
camera.position.set(Math.cos(angle) * 2, Math.sin(angle) * 2, -5);
camera.lookAt(0, 0, 0);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
});
<script src="https://code.jquery.com/jquery-3.7.0.slim.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
window.THREE = THREE;
</script>
<div style="position: absolute; left: 0; top: 0; z-index: 1; color: white;">
<input type="checkbox" id="transparent" name="transparent" checked /><label for="transparent"> Transparent</label>
</div>
<canvas id="canvas" width="350" height="150" style="position: absolute; left: 0; top: 0;" />
26/07/2023: Updated code to THREE r154. Problem still exists.
Upvotes: 1
Views: 1793
Reputation: 11960
The "transmission" feature of THREE.MeshPhysicalMaterial is a more advanced type of physically-based transparency that requires additional rendering passes. Currently three.js (and most other realtime engines I'm aware of) cannot display alpha-blending (.transparent=true
) or transmissive (.transmission>0
) materials through a transmissive material. If you need multiple layers of transparency you'll need to stick with alpha blending and not transmission, provided by .transparent=true
and opacity or a texture with an alpha channel.
Related discussion: https://github.com/mrdoob/three.js/issues/22009
Upvotes: 3