I’ve been exploring different ways of rendering transparent objects with opacity from within a glTF model and came across an unusual solution.
Upon traversing the scene I found that setting child.material.transparent
equal to a new material solved my problem. I assumed this was because transparent expected a boolean value and that setting it to a new material might equal true
but that’s not the case because child.material.transparent = true
produces an entirely different result.
I understand that there has already been extensive discussion around rendering transparent objects, but I’m looking for any sort of explanation as to why my example seems to work.
Here’s the relevant code:
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
const gltfLoader = new GLTFLoader(loadingManager)
/* Canvas */
const canvas = document.querySelector('canvas.webgl')
/* Scene */
const scene = new THREE.Scene()
/* Models */
gltfLoader.load(
'/models/ARHouse/ar-house-glass.glb',
(gltf) => {
scene.add(gltf.scene)
scene.traverse((child) => {
if(child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial){
child.material.transparent = new THREE.MeshStandardMaterial()
}
})
}
)
/* Lights */
const ambientLight = new THREE.AmbientLight(0xffffff, 1)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
directionalLight.position.set(10, 20, 5)
scene.add(ambientLight, directionalLight)
/* Sizes */
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/* Camera */
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 300)
camera.position.set(-47, 25, 72)
scene.add(camera)
/* Controls */
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true
controls.maxDistance = 150
controls.minDistance = 70
controls.rotateSpeed = 0.3
controls.maxPolarAngle = Math.PI / 2;
/* Renderer */
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.setClearColor(0xcccccc)
renderer.physicallyCorrectLights = true
renderer.outputEncoding = THREE.sRGBEncoding
/* Animate */
const tick = () =>
{
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
stats.end()
}
tick()