Three.js - Textures

Aus Wikizone
Version vom 28. Dezember 2021, 19:13 Uhr von 134.3.241.3 (Diskussion)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche
ThreeJS - Snippets
Mesh Objekt > Geometry > Material > Textur

Prinzip'[Bearbeiten]

Manuell:

  • Bild Objekt erstellen
  • Texture Objekt erstellen und Bild Objekt zuordnen
  • Bildsource dem Bildobjekt zuordnen >
  • wenn Bild geladen ist (z.B addEventListener oder onload wie unten)texture.needsUpdate setzen, damit ThreeJs die Texture updaten kann
  • Texture dem Material zuordnen (Property map)

Mit TextureLoader (recommended):

  • Wenn gewünscht LoadingManager erstellen
  • TextureLoader erstellen und LoadingManager übergeben
  • Bildquelle mit .load() in TextureLoader laden -> gibt texture Objekt zurück
  • texture dem Material zuordnen

Beispiele[Bearbeiten]

Beispiel 1 - manuell laden

/**
 * Textures
 */
const image = new Image()
const texture = new THREE.Texture(image) 
image.src = '/textures/door/color.jpg'
image.onload = () => 
{
    texture.needsUpdate = true
}

//...

const material = new THREE.MeshBasicMaterial({ map: texture })

TextureLoader[Bearbeiten]

Der TextureLoader macht im Prinzip das Gleiche, erspart uns aber die onload Funktion :-). Ein TextureLoader kann für mehrere Texturen verwendet werden.

/**
 * Textures
 */
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load('/textures/door/color.jpg')
//...
const material = new THREE.MeshBasicMaterial({ map: texture })

TextureLoader Callbacks Manchmal nützlich für Fehlersuche etc.

const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load(
    '/textures/door/color.jpg',
    () =>
    {
        console.log('load')
    },
    () =>
    {
        console.log('progress')
    },
    () =>
    {
        console.log('error')
    }
)

Loading Manager[Bearbeiten]

Nützlich wenn viele Assets geladen werden müssen. Also z.B. viele Texturen. Wird erstellt und dann als Parameter dem TextureLoader übergeben. Dann kann man über die Callbacks den Ladevorgang checken und darauf reagieren.

const loadingManager = new THREE.LoadingManager()

loadingManager.onStart = () =>
{
    console.log('onStart')
}
loadingManager.onLoad = () =>
{
    console.log('onLoad')
}
loadingManager.onProgress = () =>
{
    console.log('onProgress')
}
loadingManager.onError = () =>
{
    console.log('onError')
}

const textureLoader = new THREE.TextureLoader(loadingManager)

const colorTexture = textureLoader.load('/textures/door/color.jpg')
const alphaTexture = textureLoader.load('/textures/door/alpha.jpg')
const heightTexture = textureLoader.load('/textures/door/height.jpg')
const normalTexture = textureLoader.load('/textures/door/normal.jpg')
const ambientOcclusionTexture = textureLoader.load('/textures/door/ambientOcclusion.jpg')
const metalnessTexture = textureLoader.load('/textures/door/metalness.jpg')
const roughnessTexture = textureLoader.load('/textures/door/roughness.jpg')

UV Wrapping[Bearbeiten]

Wrapping Mode[Bearbeiten]

THREE.RepeatWrapping
THREE.ClampToEdgeWrapping // default
THREE.MirroredRepeatWrapping
const colorTexture = textureLoader.load('/textures/door/color.jpg')

// TEXTURE TRANSFORMATIONS
colorTexture.repeat.x = 2
colorTexture.repeat.y = 3

colorTexture.wrapS = THREE.RepeatWrapping
colorTexture.wrapT = THREE.RepeatWrapping
//colorTexture.wrapS = THREE.MirroredRepeatWrapping
//colorTexture.wrapT = THREE.MirroredRepeatWrapping

colorTexture.offset.x = 0.5
colorTexture.offset.y = 0.5

colorTexture.center.x = 0.5
colorTexture.center.y = 0.5
colorTexture.rotation = Math.PI * 0.25

Mipmapping[Bearbeiten]

Je nach Entfernung eines Objekts wird eine Textur kleiner oder größer angezeigt. Daher erstellt ThreeJS kleinere Versionen einer Textur und speichert diese zusammen mit dem Original in einer Mipmap. Dazu wird die original Texture immer wieder um die Hälfte verkleinert bis nur noch ein Pixel vorhanden ist. Im Prinzip ist die Map ein Bild aus allen Bildern. Diesen Prozess nennt man Mipmapping.

Für das Erstellen dieser Bildversionen kann man verschiedene Filter einsetzen. Diese resultieren z.B. in besserer Schärfe oder weniger Moiree Effekten, resultieren aber auch in unterschiedlicher Performance.

Minification

Wenn das Objekt klein dargestellt wird, hat der Screen für das Bild weniger Pixel zur verfügung als die Textur hergibt. In dem Fall spricht man von Minification.

const colorTexture = textureLoader.load('/textures/checkerboard-1024x1024.png')
colorTexture.generateMipmaps = false // NearestFilter doesn't need Mipmap
colorTexture.minFilter = THREE.NearestFilter // oft bessere Schärfe aber auch mehr Moiré

Magnification

Im gegenteiligen Fall - das Objekt ist sehr nahe reichen die Bildpixel der Textur nicht mehr aus und sie muss skaliert werden. Auch hier kann man die selben Filter einsetzen. Der Standardfilter interpoliert die Pixel und erzeugt eine Unschärfe. Das passt in den meisten Fällen am besten. Bei Geometrischen Formen (z.b. wie in Minecraft-Kacheln) funktioniert der Nearest Filter gut, der einfach die Pixel wiederholt.

const colorTexture = textureLoader.load('/textures/minecraft.png')
colorTexture.magFilter = THREE.NearestFilter

Hinweise für bessere Performance

  • Mipmapping halbiert das Bild bis nur noch ein Pixel übrig ist. Daher sollte die Pixelanzahl des Bildes eine zweier Potenz sein. Am besten nimmt man Formate wie ... 256x256 / 512x1024 / 1024x1024 ... Oft nimmt man quadratische Formate.
  • Da der NearestFilter keine Interpolation macht sondern nur Pixel wegwirft bzw. verdoppelt, hat er auch eine etwas bessere Performance als andere Filter.
  • Wenn der NearestFilter für die Minification genutzt wird kann man das Mipmapping ausschalten. der Filter ignoriert einfach die nicht benötigten Pixel der Originaltextur.
  • Transparenz kann über ein transparentes png erreicht werden oder über über eine Alpha-Kanal Bildversion (weiß = opak, schwarz = transparent). Alpha ist GPU-Freundlicher, ein einzelnes png kann vielleicht etwas Ladezeit sparen.
  • Normal-Maps geben über die Farbe die Richtung der Normalen (=Oberfläche) vor. Das sollte exakt sein, deshalb hier lieber ein png Verwenden (verlustfrei).
colorTexture.generateMipmaps = false // NearestFilter doesn't need that
colorTexture.minFilter = THREE.NearestFilter
colorTexture.magFilter = THREE.NearestFilter
  • Es ist möglich mehrere Texturen in einem Bild zu vereinen. Z.b. kann man den Rotkanal für eine Heightmap und den Blaukanal als Alphakanal verwenden. Dies verkürzt die ladezeit.