Three.js - baked map texture: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
 
(2 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
Links
+
== Links ==
  [[Blender uv-mapping]] (mit Three.js workflow
+
  [[Blender uv-mapping]] (mit Three.js workflow)
 +
[[ThreeJS - Snippets]]
  
Einführung
+
== Einführung ==
  
 
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.  
 
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.  
Zeile 11: Zeile 12:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Fallstricke:
+
== Fallstricke ==
  
 
* Texture wird '''falsch gemappt''' flipY
 
* Texture wird '''falsch gemappt''' flipY
Zeile 20: Zeile 21:
 
  //...
 
  //...
 
  renderer.outputEncoding = THREE.sRGBEncoding
 
  renderer.outputEncoding = THREE.sRGBEncoding
 +
 +
== Komplettes Beispiel ==
 +
<syntaxhighlight lang="javascript">
 +
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()
 +
</syntaxhighlight>

Aktuelle Version vom 5. Februar 2022, 20:29 Uhr

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()