Three.js - baked map texture
Aus Wikizone
Links[Bearbeiten]
Blender uv-mapping (mit Three.js workflow) ThreeJS - Snippets
Einführung[Bearbeiten]
Baked maps sind vorgerenderte Texturen. Sie enthalten quasi alle Lichter und Schatten. Sie werden im 3D Programm erstellt und können dann in Blender als Textur geladen werden. Wie man die Textur erstellt findest du unter Blender uv-mapping.
So wird eine Map eingebunden:
Fallstricke[Bearbeiten]
- Texture wird falsch gemappt flipY
const bakedTexture = textureLoader.load('baked.jpg')
bakedTexture.flipY = false
- ColorSpace falsch Farbe nicht so gut wie im original Render Texture und Renderer muss eingestellt werden (z.b. auf sRGB)
bakedTexture.encoding = THREE.sRGBEncoding //... renderer.outputEncoding = THREE.sRGBEncoding
Komplettes Beispiel[Bearbeiten]
import './style.css'
import * as dat from 'lil-gui'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js' // if using compressed gltf
/**
* Base
*/
// Debug
const gui = new dat.GUI({
width: 400
})
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Loaders
*/
// Texture loader
const textureLoader = new THREE.TextureLoader()
// Draco loader if using compressed gltf
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('draco/')
// GLTF loader
const gltfLoader = new GLTFLoader()
gltfLoader.setDRACOLoader(dracoLoader)
/**
* Textures
*/
const bakedTexture = textureLoader.load('baked.jpg')
bakedTexture.flipY = false
bakedTexture.encoding = THREE.sRGBEncoding
/**
* Materials
*/
const bakedMaterial = new THREE.MeshBasicMaterial({ map: bakedTexture,side: THREE.DoubleSide })
const portalLightMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff})
/**
* Portal
*/
gltfLoader.load(
'portal.glb',
(gltf) => {
//this way we cam traverse bigger scenes but as we merged we could do it manually like:
//const bakedMesh = gltf.scene.children.find((child) => child.name === 'baked')
gltf.scene.traverse(
(child) => {
child.material = bakedMaterial
}
)
scene.add(gltf.scene)
// search emmisive materials
const emissions = ["Lamp1", "Lamp2", "LampPortal"];
const lights = gltf.scene.children.filter( child => emissions.includes(child.name) )
lights.forEach( light => light.material = portalLightMaterial )
console.log(lights)
//const portalLightMesh = gltf.scene.children.find((child) => child.name === 'portalLight')// Brunos solution for each light
}
)
/**
* 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
*/
// Base camera
const camera = new THREE.PerspectiveCamera(45, sizes.width / sizes.height, 0.1, 100)
camera.position.x = 4
camera.position.y = 2
camera.position.z = 4
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.outputEncoding = THREE.sRGBEncoding
/**
* Animate
*/
const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()