<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki.stephanschlegel.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=134.3.241.3</id>
	<title>Wikizone - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.stephanschlegel.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=134.3.241.3"/>
	<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Spezial:Beitr%C3%A4ge/134.3.241.3"/>
	<updated>2026-05-06T13:57:09Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.35.14</generator>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Particles&amp;diff=25816</id>
		<title>Three.js - Particles</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Particles&amp;diff=25816"/>
		<updated>2022-01-16T19:19:56Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* GUI mit onChange / onFinishChange */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; [[ThreeJS - Snippets]]&lt;br /&gt;
&lt;br /&gt;
The good thing with particles is that you can have hundreds of thousands of them on screen with a reasonable frame rate. The downside is that each particle is composed of a plane (two triangles) always facing the camera.&lt;br /&gt;
&lt;br /&gt;
== Snippets ==&lt;br /&gt;
=== Basic Example ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //change size if near/far - default ist true&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Eigene Geometrie mit zufälligen Punkten ===&lt;br /&gt;
Um Punkte zu einer Geometrie hinzuzufügen muss man &lt;br /&gt;
* die Punkte in ein Array packen &lt;br /&gt;
* Das Array der Geometrie hinzufügen. Dazu einfach das positions Attribut füllen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 500&lt;br /&gt;
// create array&lt;br /&gt;
const positionsArray = new Float32Array(count * 3) //3 vals per point&lt;br /&gt;
// fill array&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = (Math.random() - 0.5) * 4&lt;br /&gt;
}  &lt;br /&gt;
// put array values in geometry&lt;br /&gt;
particlesGeometry.setAttribute(&lt;br /&gt;
    &amp;#039;position&amp;#039;,&lt;br /&gt;
    new THREE.BufferAttribute(positionsArray,3) //3 means 3 values belong together (one 3D Koordinate)&lt;br /&gt;
) &lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({size: 0.02})&lt;br /&gt;
&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Transparenz und Blending ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    color: &amp;#039;#ff88cc&amp;#039;,&lt;br /&gt;
    transparent: true,&lt;br /&gt;
    alphaMap: particlesTexture,&lt;br /&gt;
&lt;br /&gt;
    // 3 Solutions for better alpha with not much performance impact&lt;br /&gt;
    //alphaTest: 0.001, // beware of artefacts at borders&lt;br /&gt;
    //depthTest: false, // works if just one color&lt;br /&gt;
    depthWrite: false, // many times the right solution&lt;br /&gt;
&lt;br /&gt;
    // 1 Solution for blending particles (beware of performance)&lt;br /&gt;
    blending: THREE.AdditiveBlending&lt;br /&gt;
&lt;br /&gt;
    size: 0.1,&lt;br /&gt;
    sizeAttenuation: true, //change size if near/far?&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zufällige Farben und Positionen ===&lt;br /&gt;
Ähnlich wie bei der Position erzeugen wir für die Farben ein Array mit Zufallszahlen und übergeben diese, dieses mal an das Color Attribut. Achtung vertexColor muss auf true gestellt werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const particlesTexture = textureLoader.load(&amp;#039;/textures/particles/2.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
//const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
const particlesGeometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 20000&lt;br /&gt;
const positionsArray = new Float32Array(count * 3)&lt;br /&gt;
const colorsArray = new Float32Array(count * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = (Math.random() - 0.5) * 10 // -5 to 5&lt;br /&gt;
    colorsArray[i] = Math.random() // 0 to 1&lt;br /&gt;
}  &lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;position&amp;#039;, new THREE.BufferAttribute(positionsArray,3)) &lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;color&amp;#039;, new THREE.BufferAttribute(colorsArray,3)) &lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    color: &amp;#039;#ff88cc&amp;#039;,&lt;br /&gt;
    transparent: true,&lt;br /&gt;
    alphaMap: particlesTexture,&lt;br /&gt;
    depthWrite: false, // many times the right solution&lt;br /&gt;
    // To set color for each point (vertex9 we need to set:&lt;br /&gt;
    vertexColors: true,&lt;br /&gt;
    size: 0.1,&lt;br /&gt;
    sizeAttenuation: true, //change size if near/far?&lt;br /&gt;
})&lt;br /&gt;
 &lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wave Animation (bad way) ===&lt;br /&gt;
Man kann die Positionen der Partikel direkt im ArrayBuffer manipulieren. Dies solltest du aber nur für eine Hand voll Punkte und nicht für tausende von Objekten verwenden. Bessere Lösung: Custom Shader&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update particles&lt;br /&gt;
&lt;br /&gt;
    // You can apply a rotation on the whole object&lt;br /&gt;
    // particles.rotation.y = elapsedTime * 0.1&lt;br /&gt;
&lt;br /&gt;
    // Or update individual vertices&lt;br /&gt;
    // NOTE - ONLY USE THIS FOR A FEW PARTICLES. &lt;br /&gt;
    // FOR MANY PARTICLES YOU SHOULD USE A CUSTOM SHADER&lt;br /&gt;
    for(let i=0; i &amp;lt; count; i++){&lt;br /&gt;
        const i3 = i * 3 // x = i3, y = i3+1, z = i3+2&lt;br /&gt;
        // get x value of this particle&lt;br /&gt;
        const x = particlesGeometry.attributes.position.array[i3]&lt;br /&gt;
        // and use it as a offset for y&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3+1] = Math.sin(elapsedTime + x)&lt;br /&gt;
    }&lt;br /&gt;
    // tell Three.js, that this attribute has changed&lt;br /&gt;
    particlesGeometry.attributes.position.needsUpdate = true &lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tutorial ==&lt;br /&gt;
Based on: https://threejs-journey.com/lessons/18&lt;br /&gt;
=== Geometry ===&lt;br /&gt;
&lt;br /&gt;
You can use any of the basic Three.js geometries. For the same reasons as for the Mesh, it&amp;#039;s preferable to use BufferGeometries. Each vertex of the geometry will become a particle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereGeometry(1, 32, 32)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PointsMaterial ===&lt;br /&gt;
&lt;br /&gt;
We need a special type of material called &amp;#039;&amp;#039;&amp;#039;PointsMaterial&amp;#039;&amp;#039;&amp;#039;. This material can already do a lot, but we will discover how to create our &amp;#039;&amp;#039;&amp;#039;own particles material&amp;#039;&amp;#039;&amp;#039; to go even further in a future lesson.&lt;br /&gt;
&lt;br /&gt;
The PointsMaterial has multiple properties specific to particles like the size to control all &amp;#039;&amp;#039;&amp;#039;particles size&amp;#039;&amp;#039;&amp;#039; and the &amp;#039;&amp;#039;&amp;#039;sizeAttenuation&amp;#039;&amp;#039;&amp;#039; to specify if distant particles should be smaller than close particles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As always, we can also &amp;#039;&amp;#039;&amp;#039;change those properties&amp;#039;&amp;#039;&amp;#039; after creating the material:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial()&lt;br /&gt;
particlesMaterial.size = 0.02&lt;br /&gt;
particlesMaterial.sizeAttenuation = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Points ===&lt;br /&gt;
&lt;br /&gt;
Finally, we can create the final particles the same way we create a Mesh, but this time by using the Points class. Don&amp;#039;t forget to add it to the scene:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That was easy. Let&amp;#039;s customize those particles.&lt;br /&gt;
&lt;br /&gt;
=== Custom geometry ===&lt;br /&gt;
&lt;br /&gt;
To create a custom geometry, &amp;#039;&amp;#039;&amp;#039;we can start from a BufferGeometry&amp;#039;&amp;#039;&amp;#039;, and add a position attribute as we did in the Geometries lesson. Replace the SphereGeometry with custom geometry and add the &amp;#039;position&amp;#039; attribute as we did before:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 500&lt;br /&gt;
&lt;br /&gt;
const positions = new Float32Array(count * 3) // Multiply by 3 because each position is composed of 3 values (x, y, z)&lt;br /&gt;
&lt;br /&gt;
for(let i = 0; i &amp;lt; count * 3; i++) // Multiply by 3 for same reason&lt;br /&gt;
{&lt;br /&gt;
    positions[i] = (Math.random() - 0.5) * 10 // Math.random() - 0.5 to have a random value between -0.5 and +0.5&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;position&amp;#039;, new THREE.BufferAttribute(positions, 3)) // Create the Three.js BufferAttribute and specify that each information is composed of 3 values&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&amp;#039;t be frustrated if you can&amp;#039;t pull out this code by yourself. It&amp;#039;s a little complex, and variables are using strange formats.&lt;br /&gt;
&lt;br /&gt;
You should get a bunch of particles all around the scene. Now is an excellent time to have fun and test the limits of your computer. Try 5000, 50000, 500000 maybe. You can have millions of particles and still have a reasonable frame rate.&lt;br /&gt;
&lt;br /&gt;
You can imagine that there are limits. On an inferior computer or a smartphone, you won&amp;#039;t be able to have a 60fps experience with millions of particles. We are also going to add effects that will drastically reduce the frame rate. But still, that&amp;#039;s quite impressive.&lt;br /&gt;
&lt;br /&gt;
For now, let&amp;#039;s keep the count to 5000 and change the size to 0.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const count = 5000&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
particlesMaterial.size = 0.1&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Color, map and alpha map ===&lt;br /&gt;
&lt;br /&gt;
We can &amp;#039;&amp;#039;&amp;#039;change the color of all particles&amp;#039;&amp;#039;&amp;#039; with the color property on the PointsMaterial. Don&amp;#039;t forget that you need to use the Color class if you&amp;#039;re changing this property after instancing the material:&lt;br /&gt;
&lt;br /&gt;
 particlesMaterial.color = new THREE.Color(&amp;#039;#ff88cc&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
We can also use the &amp;#039;&amp;#039;&amp;#039;map property to put a texture on those particles&amp;#039;&amp;#039;&amp;#039;. Use the TextureLoader already in the code to load one of the textures located in /static/textures/particles/:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const particleTexture = textureLoader.load(&amp;#039;/textures/particles/2.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
particlesMaterial.map = particleTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These textures are resized versions of the pack provided by Kenney and you can find the full pack here: https://www.kenney.nl/assets/particle-pack. But you can also create your own.&lt;br /&gt;
&lt;br /&gt;
As you can see, the color property is changing the map, just like with the other materials.&lt;br /&gt;
&lt;br /&gt;
If you look closely, you&amp;#039;ll see that the front particles are hiding the back particles.&lt;br /&gt;
&lt;br /&gt;
We need to &amp;#039;&amp;#039;&amp;#039;activate transparency&amp;#039;&amp;#039;&amp;#039; with transparent and use the texture on the &amp;#039;&amp;#039;&amp;#039;alphaMap property&amp;#039;&amp;#039;&amp;#039; instead of the map:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// particlesMaterial.map = particleTexture&lt;br /&gt;
particlesMaterial.transparent = true&lt;br /&gt;
particlesMaterial.alphaMap = particleTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that&amp;#039;s better, but we can still randomly see some edges of the particles.&lt;br /&gt;
&lt;br /&gt;
That is because the particles are drawn in the same order as they are created, and WebGL doesn&amp;#039;t really know which one is in front of the other.&lt;br /&gt;
&lt;br /&gt;
There are multiple ways of fixing this.&lt;br /&gt;
==== Using alphaTest ====&lt;br /&gt;
&lt;br /&gt;
The alphaTest is a value between 0 and 1 that enables the WebGL to know when not to render the pixel according to that pixel&amp;#039;s transparency. By default, the value is 0 meaning that the pixel will be rendered anyway. &amp;#039;&amp;#039;&amp;#039;If we use a small value such as 0.001, the pixel won&amp;#039;t be rendered if the alpha is 0&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
 particlesMaterial.alphaTest = 0.001                      &lt;br /&gt;
&lt;br /&gt;
This solution isn&amp;#039;t perfect and if you watch closely, you can still see glitches, but it&amp;#039;s already more satisfying.&lt;br /&gt;
==== Using depthTest ====&lt;br /&gt;
&lt;br /&gt;
When drawing, the WebGL tests if what&amp;#039;s being drawn is closer than what&amp;#039;s already drawn. That is called depth testing and can be deactivated (you can comment the alphaTest):&lt;br /&gt;
&lt;br /&gt;
 // particlesMaterial.alphaTest = 0.001&lt;br /&gt;
 particlesMaterial.depthTest = false                        &lt;br /&gt;
&lt;br /&gt;
While this solution seems to completely &amp;#039;&amp;#039;&amp;#039;fix our problem&amp;#039;&amp;#039;&amp;#039;, deactivating the depth testing might &amp;#039;&amp;#039;&amp;#039;create bugs if you have other objects in your scene or particles with different colors&amp;#039;&amp;#039;&amp;#039;. The particles might be drawn as if they were above the rest of the scene.&lt;br /&gt;
&lt;br /&gt;
Add a cube to the scene to see that:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const cube = new THREE.Mesh(&lt;br /&gt;
    new THREE.BoxGeometry(),&lt;br /&gt;
    new THREE.MeshBasicMaterial()&lt;br /&gt;
)&lt;br /&gt;
scene.add(cube)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using depthWrite ====&lt;br /&gt;
&lt;br /&gt;
As we said, the WebGL is testing if what&amp;#039;s being drawn is closer than what&amp;#039;s already drawn. The depth of what&amp;#039;s being drawn is stored in what we call a depth buffer. Instead of not testing if the particle is closer than what&amp;#039;s in this depth buffer, we can tell the WebGL not to write particles in that depth buffer (you can comment the depthTest):&lt;br /&gt;
&lt;br /&gt;
 // particlesMaterial.alphaTest = 0.001&lt;br /&gt;
 // particlesMaterial.depthTest = false&lt;br /&gt;
 particlesMaterial.depthWrite = false&lt;br /&gt;
&lt;br /&gt;
In our case, this solution will &amp;#039;&amp;#039;&amp;#039;fix the problem with almost no drawback&amp;#039;&amp;#039;&amp;#039;. Sometimes, &amp;#039;&amp;#039;&amp;#039;other objects might be drawn behind or in front of the particles&amp;#039;&amp;#039;&amp;#039; depending on many factors like the transparency, in which order you added the objects to your scene, etc.&lt;br /&gt;
&lt;br /&gt;
We saw multiple techniques, and there is no perfect solution. You&amp;#039;ll have to adapt and &amp;#039;&amp;#039;&amp;#039;find the best combination&amp;#039;&amp;#039;&amp;#039; according to the project.&lt;br /&gt;
&lt;br /&gt;
=== Blending ===&lt;br /&gt;
&lt;br /&gt;
Currently, the WebGL draws the pixels one on top of the other.&lt;br /&gt;
&lt;br /&gt;
By changing the blending property, we can tell the WebGL not only to draw the pixel, but also to &amp;#039;&amp;#039;&amp;#039;add the color of that pixel to the color of the pixel already drawn&amp;#039;&amp;#039;&amp;#039;. That will have a saturation effect that can look amazing.&lt;br /&gt;
&lt;br /&gt;
To test that, simply change the blending property to &amp;#039;&amp;#039;THREE.AdditiveBlending&amp;#039;&amp;#039; (keep the depthWrite property):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// particlesMaterial.alphaTest = 0.001&lt;br /&gt;
// particlesMaterial.depthTest = false&lt;br /&gt;
particlesMaterial.depthWrite = false&lt;br /&gt;
particlesMaterial.blending = THREE.AdditiveBlending&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add more particles (let&amp;#039;s say 20000) to better enjoy this effect.&lt;br /&gt;
&lt;br /&gt;
But be careful, this effect will impact the performances, and you won&amp;#039;t be able to have as many particles as before at 60fps.&lt;br /&gt;
&lt;br /&gt;
Now, we can remove the cube.&lt;br /&gt;
&lt;br /&gt;
=== Different colors ===&lt;br /&gt;
&lt;br /&gt;
We can have a different color for each particle. We first need to add a new attribute named color as we did for the position. A color is composed of red, green, and blue (3 values), so the code will be very similar to the position attribute. We can actually use the same loop for these two attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const positions = new Float32Array(count * 3)&lt;br /&gt;
const colors = new Float32Array(count * 3)&lt;br /&gt;
&lt;br /&gt;
for(let i = 0; i &amp;lt; count * 3; i++)&lt;br /&gt;
{&lt;br /&gt;
    positions[i] = (Math.random() - 0.5) * 10&lt;br /&gt;
    colors[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;position&amp;#039;, new THREE.BufferAttribute(positions, 3))&lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;color&amp;#039;, new THREE.BufferAttribute(colors, 3))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Be careful with singulars and plurals.&lt;br /&gt;
&lt;br /&gt;
To activate those vertex colors, simply change the &amp;#039;&amp;#039;&amp;#039;vertexColors property to true&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
 particlesMaterial.vertexColors = true&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;main color&amp;#039;&amp;#039;&amp;#039; of the material &amp;#039;&amp;#039;&amp;#039;still affects these vertex colors&amp;#039;&amp;#039;&amp;#039;. Feel free to change that color or even comment it.&lt;br /&gt;
&lt;br /&gt;
 // particlesMaterial.color = new THREE.Color(&amp;#039;#ff88cc&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
=== Animate ===&lt;br /&gt;
&lt;br /&gt;
There are multiple ways of animating particles.&lt;br /&gt;
==== By using the points as an object ====&lt;br /&gt;
&lt;br /&gt;
Because the &amp;#039;&amp;#039;&amp;#039;Points&amp;#039;&amp;#039;&amp;#039; class inherits from the &amp;#039;&amp;#039;&amp;#039;Object3D&amp;#039;&amp;#039;&amp;#039; class, you can &amp;#039;&amp;#039;&amp;#039;move, rotate and scale&amp;#039;&amp;#039;&amp;#039; the points as you wish.&lt;br /&gt;
&lt;br /&gt;
Rotate the particles in the tick function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update particles&lt;br /&gt;
    particles.rotation.y = elapsedTime * 0.2&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While this is already cool, we want &amp;#039;&amp;#039;&amp;#039;more control over each particle.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
By changing the attributes&lt;br /&gt;
&lt;br /&gt;
Another solution would be to &amp;#039;&amp;#039;&amp;#039;update each vertex position separately&amp;#039;&amp;#039;&amp;#039;. This way, vertices can have different trajectories. We are going to animate the particles as if they were floating on waves but first, let&amp;#039;s see how we can update the vertices.&lt;br /&gt;
&lt;br /&gt;
Start by commenting the previous rotation we did on the whole particles:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    // particles.rotation.y = elapsedTime * 0.2&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update each vertex, we have to &amp;#039;&amp;#039;&amp;#039;update the right part in the position attribute&amp;#039;&amp;#039;&amp;#039; because all the vertices are stored in this &amp;#039;&amp;#039;&amp;#039;one dimension array&amp;#039;&amp;#039;&amp;#039; where the first 3 values correspond to the x, y and z coordinates of the first vertex, then the next 3 values correspond to the x, y and z of the second vertex, etc.&lt;br /&gt;
&lt;br /&gt;
We only want the vertices to move up and down, meaning that we are going to update the y axis only. Because the position attribute is a one dimension array, we have to &amp;#039;&amp;#039;&amp;#039;go through it 3 by 3 and only update the second value which is the y coordinate&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s start by going through each vertices:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
        // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        const i3 = i * 3&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, we chose to have a simple for loop that goes from 0 to count and we created a &amp;#039;&amp;#039;&amp;#039;i3 variable inside that goes 3 by 3 simply by multiplying i by 3.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The easiest way to simulate &amp;#039;&amp;#039;&amp;#039;waves movement&amp;#039;&amp;#039;&amp;#039; is to use a simple &amp;#039;&amp;#039;&amp;#039;sinus&amp;#039;&amp;#039;&amp;#039;. First, we are going to update all vertices to go up and down on the same frequency.&lt;br /&gt;
&lt;br /&gt;
The y coordinate can be access in the array at the index i3 + 1:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        const i3 = i * 3&lt;br /&gt;
&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, nothing is moving. The problem is that &amp;#039;&amp;#039;&amp;#039;Three.js has to be notified that the geometry changed&amp;#039;&amp;#039;&amp;#039;. To do that, we have to set the &amp;#039;&amp;#039;&amp;#039;needsUpdate to true&amp;#039;&amp;#039;&amp;#039; on the position attribute once we are done updating the vertices:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        const i3 = i * 3&lt;br /&gt;
&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime)&lt;br /&gt;
    }&lt;br /&gt;
    particlesGeometry.attributes.position.needsUpdate = true &lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All the particles should be moving up and down like a plane.&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s a good start and we are almost there. All we need to do now is &amp;#039;&amp;#039;&amp;#039;apply an offset to the sinus between the particles&amp;#039;&amp;#039;&amp;#039; so that we get that &amp;#039;&amp;#039;&amp;#039;wave shape.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
To do that, we can &amp;#039;&amp;#039;&amp;#039;use the x coordinate&amp;#039;&amp;#039;&amp;#039;. And to get this value we can use the same technique that we used for the y coordinate but instead of i3 + 1, it&amp;#039;s just i3:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        let i3 = i * 3&lt;br /&gt;
&lt;br /&gt;
        const x = particlesGeometry.attributes.position.array[i3]&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime + x)&lt;br /&gt;
    }&lt;br /&gt;
    particlesGeometry.attributes.position.needsUpdate = true&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should get beautiful waves of particles. Unfortunately, &amp;#039;&amp;#039;&amp;#039;you should avoid this technique&amp;#039;&amp;#039;&amp;#039;. If we have 20000 particles, we are going through each one, calculating a new position, and updating the whole attribute on each frame. That can work with a small number of particles, but &amp;#039;&amp;#039;&amp;#039;we want millions of particles.&lt;br /&gt;
By using a custom shader&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;To update these millions of particles on each frame with a good framerate, we need to create our own material with our own shaders. But shaders are for a later lesson.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== GUI zum generieren von Objekten mit onChange / onFinishChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gui.add(params, &amp;#039;count&amp;#039;).min(100).max(1000000).step(100).onFinishChange(generateGalaxy)&lt;br /&gt;
gui.add(params, &amp;#039;size&amp;#039;).min(0.001).max(0.1).step(0.001).onFinishChange(generateGalaxy)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Vorsicht Memory-Leaks -&amp;gt; darauf achten, dass alte Geometrien / Materialien gelöscht werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const generateGalaxy = () =&amp;gt; {&lt;br /&gt;
    if(points != null){&lt;br /&gt;
        /**&lt;br /&gt;
         * Destroy old galaxy&lt;br /&gt;
         */&lt;br /&gt;
        pGeometry.dispose()&lt;br /&gt;
        pMaterial.dispose()&lt;br /&gt;
        scene.remove(points)&lt;br /&gt;
    }&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Particles&amp;diff=25815</id>
		<title>Three.js - Particles</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Particles&amp;diff=25815"/>
		<updated>2022-01-16T19:19:09Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; [[ThreeJS - Snippets]]&lt;br /&gt;
&lt;br /&gt;
The good thing with particles is that you can have hundreds of thousands of them on screen with a reasonable frame rate. The downside is that each particle is composed of a plane (two triangles) always facing the camera.&lt;br /&gt;
&lt;br /&gt;
== Snippets ==&lt;br /&gt;
=== Basic Example ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //change size if near/far - default ist true&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Eigene Geometrie mit zufälligen Punkten ===&lt;br /&gt;
Um Punkte zu einer Geometrie hinzuzufügen muss man &lt;br /&gt;
* die Punkte in ein Array packen &lt;br /&gt;
* Das Array der Geometrie hinzufügen. Dazu einfach das positions Attribut füllen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 500&lt;br /&gt;
// create array&lt;br /&gt;
const positionsArray = new Float32Array(count * 3) //3 vals per point&lt;br /&gt;
// fill array&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = (Math.random() - 0.5) * 4&lt;br /&gt;
}  &lt;br /&gt;
// put array values in geometry&lt;br /&gt;
particlesGeometry.setAttribute(&lt;br /&gt;
    &amp;#039;position&amp;#039;,&lt;br /&gt;
    new THREE.BufferAttribute(positionsArray,3) //3 means 3 values belong together (one 3D Koordinate)&lt;br /&gt;
) &lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({size: 0.02})&lt;br /&gt;
&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Transparenz und Blending ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    color: &amp;#039;#ff88cc&amp;#039;,&lt;br /&gt;
    transparent: true,&lt;br /&gt;
    alphaMap: particlesTexture,&lt;br /&gt;
&lt;br /&gt;
    // 3 Solutions for better alpha with not much performance impact&lt;br /&gt;
    //alphaTest: 0.001, // beware of artefacts at borders&lt;br /&gt;
    //depthTest: false, // works if just one color&lt;br /&gt;
    depthWrite: false, // many times the right solution&lt;br /&gt;
&lt;br /&gt;
    // 1 Solution for blending particles (beware of performance)&lt;br /&gt;
    blending: THREE.AdditiveBlending&lt;br /&gt;
&lt;br /&gt;
    size: 0.1,&lt;br /&gt;
    sizeAttenuation: true, //change size if near/far?&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Zufällige Farben und Positionen ===&lt;br /&gt;
Ähnlich wie bei der Position erzeugen wir für die Farben ein Array mit Zufallszahlen und übergeben diese, dieses mal an das Color Attribut. Achtung vertexColor muss auf true gestellt werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const particlesTexture = textureLoader.load(&amp;#039;/textures/particles/2.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
//const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
const particlesGeometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 20000&lt;br /&gt;
const positionsArray = new Float32Array(count * 3)&lt;br /&gt;
const colorsArray = new Float32Array(count * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = (Math.random() - 0.5) * 10 // -5 to 5&lt;br /&gt;
    colorsArray[i] = Math.random() // 0 to 1&lt;br /&gt;
}  &lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;position&amp;#039;, new THREE.BufferAttribute(positionsArray,3)) &lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;color&amp;#039;, new THREE.BufferAttribute(colorsArray,3)) &lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    color: &amp;#039;#ff88cc&amp;#039;,&lt;br /&gt;
    transparent: true,&lt;br /&gt;
    alphaMap: particlesTexture,&lt;br /&gt;
    depthWrite: false, // many times the right solution&lt;br /&gt;
    // To set color for each point (vertex9 we need to set:&lt;br /&gt;
    vertexColors: true,&lt;br /&gt;
    size: 0.1,&lt;br /&gt;
    sizeAttenuation: true, //change size if near/far?&lt;br /&gt;
})&lt;br /&gt;
 &lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wave Animation (bad way) ===&lt;br /&gt;
Man kann die Positionen der Partikel direkt im ArrayBuffer manipulieren. Dies solltest du aber nur für eine Hand voll Punkte und nicht für tausende von Objekten verwenden. Bessere Lösung: Custom Shader&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update particles&lt;br /&gt;
&lt;br /&gt;
    // You can apply a rotation on the whole object&lt;br /&gt;
    // particles.rotation.y = elapsedTime * 0.1&lt;br /&gt;
&lt;br /&gt;
    // Or update individual vertices&lt;br /&gt;
    // NOTE - ONLY USE THIS FOR A FEW PARTICLES. &lt;br /&gt;
    // FOR MANY PARTICLES YOU SHOULD USE A CUSTOM SHADER&lt;br /&gt;
    for(let i=0; i &amp;lt; count; i++){&lt;br /&gt;
        const i3 = i * 3 // x = i3, y = i3+1, z = i3+2&lt;br /&gt;
        // get x value of this particle&lt;br /&gt;
        const x = particlesGeometry.attributes.position.array[i3]&lt;br /&gt;
        // and use it as a offset for y&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3+1] = Math.sin(elapsedTime + x)&lt;br /&gt;
    }&lt;br /&gt;
    // tell Three.js, that this attribute has changed&lt;br /&gt;
    particlesGeometry.attributes.position.needsUpdate = true &lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tutorial ==&lt;br /&gt;
Based on: https://threejs-journey.com/lessons/18&lt;br /&gt;
=== Geometry ===&lt;br /&gt;
&lt;br /&gt;
You can use any of the basic Three.js geometries. For the same reasons as for the Mesh, it&amp;#039;s preferable to use BufferGeometries. Each vertex of the geometry will become a particle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereGeometry(1, 32, 32)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PointsMaterial ===&lt;br /&gt;
&lt;br /&gt;
We need a special type of material called &amp;#039;&amp;#039;&amp;#039;PointsMaterial&amp;#039;&amp;#039;&amp;#039;. This material can already do a lot, but we will discover how to create our &amp;#039;&amp;#039;&amp;#039;own particles material&amp;#039;&amp;#039;&amp;#039; to go even further in a future lesson.&lt;br /&gt;
&lt;br /&gt;
The PointsMaterial has multiple properties specific to particles like the size to control all &amp;#039;&amp;#039;&amp;#039;particles size&amp;#039;&amp;#039;&amp;#039; and the &amp;#039;&amp;#039;&amp;#039;sizeAttenuation&amp;#039;&amp;#039;&amp;#039; to specify if distant particles should be smaller than close particles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As always, we can also &amp;#039;&amp;#039;&amp;#039;change those properties&amp;#039;&amp;#039;&amp;#039; after creating the material:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial()&lt;br /&gt;
particlesMaterial.size = 0.02&lt;br /&gt;
particlesMaterial.sizeAttenuation = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Points ===&lt;br /&gt;
&lt;br /&gt;
Finally, we can create the final particles the same way we create a Mesh, but this time by using the Points class. Don&amp;#039;t forget to add it to the scene:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That was easy. Let&amp;#039;s customize those particles.&lt;br /&gt;
&lt;br /&gt;
=== Custom geometry ===&lt;br /&gt;
&lt;br /&gt;
To create a custom geometry, &amp;#039;&amp;#039;&amp;#039;we can start from a BufferGeometry&amp;#039;&amp;#039;&amp;#039;, and add a position attribute as we did in the Geometries lesson. Replace the SphereGeometry with custom geometry and add the &amp;#039;position&amp;#039; attribute as we did before:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 500&lt;br /&gt;
&lt;br /&gt;
const positions = new Float32Array(count * 3) // Multiply by 3 because each position is composed of 3 values (x, y, z)&lt;br /&gt;
&lt;br /&gt;
for(let i = 0; i &amp;lt; count * 3; i++) // Multiply by 3 for same reason&lt;br /&gt;
{&lt;br /&gt;
    positions[i] = (Math.random() - 0.5) * 10 // Math.random() - 0.5 to have a random value between -0.5 and +0.5&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;position&amp;#039;, new THREE.BufferAttribute(positions, 3)) // Create the Three.js BufferAttribute and specify that each information is composed of 3 values&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&amp;#039;t be frustrated if you can&amp;#039;t pull out this code by yourself. It&amp;#039;s a little complex, and variables are using strange formats.&lt;br /&gt;
&lt;br /&gt;
You should get a bunch of particles all around the scene. Now is an excellent time to have fun and test the limits of your computer. Try 5000, 50000, 500000 maybe. You can have millions of particles and still have a reasonable frame rate.&lt;br /&gt;
&lt;br /&gt;
You can imagine that there are limits. On an inferior computer or a smartphone, you won&amp;#039;t be able to have a 60fps experience with millions of particles. We are also going to add effects that will drastically reduce the frame rate. But still, that&amp;#039;s quite impressive.&lt;br /&gt;
&lt;br /&gt;
For now, let&amp;#039;s keep the count to 5000 and change the size to 0.1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const count = 5000&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
particlesMaterial.size = 0.1&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Color, map and alpha map ===&lt;br /&gt;
&lt;br /&gt;
We can &amp;#039;&amp;#039;&amp;#039;change the color of all particles&amp;#039;&amp;#039;&amp;#039; with the color property on the PointsMaterial. Don&amp;#039;t forget that you need to use the Color class if you&amp;#039;re changing this property after instancing the material:&lt;br /&gt;
&lt;br /&gt;
 particlesMaterial.color = new THREE.Color(&amp;#039;#ff88cc&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
We can also use the &amp;#039;&amp;#039;&amp;#039;map property to put a texture on those particles&amp;#039;&amp;#039;&amp;#039;. Use the TextureLoader already in the code to load one of the textures located in /static/textures/particles/:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const particleTexture = textureLoader.load(&amp;#039;/textures/particles/2.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
particlesMaterial.map = particleTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These textures are resized versions of the pack provided by Kenney and you can find the full pack here: https://www.kenney.nl/assets/particle-pack. But you can also create your own.&lt;br /&gt;
&lt;br /&gt;
As you can see, the color property is changing the map, just like with the other materials.&lt;br /&gt;
&lt;br /&gt;
If you look closely, you&amp;#039;ll see that the front particles are hiding the back particles.&lt;br /&gt;
&lt;br /&gt;
We need to &amp;#039;&amp;#039;&amp;#039;activate transparency&amp;#039;&amp;#039;&amp;#039; with transparent and use the texture on the &amp;#039;&amp;#039;&amp;#039;alphaMap property&amp;#039;&amp;#039;&amp;#039; instead of the map:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// particlesMaterial.map = particleTexture&lt;br /&gt;
particlesMaterial.transparent = true&lt;br /&gt;
particlesMaterial.alphaMap = particleTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that&amp;#039;s better, but we can still randomly see some edges of the particles.&lt;br /&gt;
&lt;br /&gt;
That is because the particles are drawn in the same order as they are created, and WebGL doesn&amp;#039;t really know which one is in front of the other.&lt;br /&gt;
&lt;br /&gt;
There are multiple ways of fixing this.&lt;br /&gt;
==== Using alphaTest ====&lt;br /&gt;
&lt;br /&gt;
The alphaTest is a value between 0 and 1 that enables the WebGL to know when not to render the pixel according to that pixel&amp;#039;s transparency. By default, the value is 0 meaning that the pixel will be rendered anyway. &amp;#039;&amp;#039;&amp;#039;If we use a small value such as 0.001, the pixel won&amp;#039;t be rendered if the alpha is 0&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
 particlesMaterial.alphaTest = 0.001                      &lt;br /&gt;
&lt;br /&gt;
This solution isn&amp;#039;t perfect and if you watch closely, you can still see glitches, but it&amp;#039;s already more satisfying.&lt;br /&gt;
==== Using depthTest ====&lt;br /&gt;
&lt;br /&gt;
When drawing, the WebGL tests if what&amp;#039;s being drawn is closer than what&amp;#039;s already drawn. That is called depth testing and can be deactivated (you can comment the alphaTest):&lt;br /&gt;
&lt;br /&gt;
 // particlesMaterial.alphaTest = 0.001&lt;br /&gt;
 particlesMaterial.depthTest = false                        &lt;br /&gt;
&lt;br /&gt;
While this solution seems to completely &amp;#039;&amp;#039;&amp;#039;fix our problem&amp;#039;&amp;#039;&amp;#039;, deactivating the depth testing might &amp;#039;&amp;#039;&amp;#039;create bugs if you have other objects in your scene or particles with different colors&amp;#039;&amp;#039;&amp;#039;. The particles might be drawn as if they were above the rest of the scene.&lt;br /&gt;
&lt;br /&gt;
Add a cube to the scene to see that:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const cube = new THREE.Mesh(&lt;br /&gt;
    new THREE.BoxGeometry(),&lt;br /&gt;
    new THREE.MeshBasicMaterial()&lt;br /&gt;
)&lt;br /&gt;
scene.add(cube)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using depthWrite ====&lt;br /&gt;
&lt;br /&gt;
As we said, the WebGL is testing if what&amp;#039;s being drawn is closer than what&amp;#039;s already drawn. The depth of what&amp;#039;s being drawn is stored in what we call a depth buffer. Instead of not testing if the particle is closer than what&amp;#039;s in this depth buffer, we can tell the WebGL not to write particles in that depth buffer (you can comment the depthTest):&lt;br /&gt;
&lt;br /&gt;
 // particlesMaterial.alphaTest = 0.001&lt;br /&gt;
 // particlesMaterial.depthTest = false&lt;br /&gt;
 particlesMaterial.depthWrite = false&lt;br /&gt;
&lt;br /&gt;
In our case, this solution will &amp;#039;&amp;#039;&amp;#039;fix the problem with almost no drawback&amp;#039;&amp;#039;&amp;#039;. Sometimes, &amp;#039;&amp;#039;&amp;#039;other objects might be drawn behind or in front of the particles&amp;#039;&amp;#039;&amp;#039; depending on many factors like the transparency, in which order you added the objects to your scene, etc.&lt;br /&gt;
&lt;br /&gt;
We saw multiple techniques, and there is no perfect solution. You&amp;#039;ll have to adapt and &amp;#039;&amp;#039;&amp;#039;find the best combination&amp;#039;&amp;#039;&amp;#039; according to the project.&lt;br /&gt;
&lt;br /&gt;
=== Blending ===&lt;br /&gt;
&lt;br /&gt;
Currently, the WebGL draws the pixels one on top of the other.&lt;br /&gt;
&lt;br /&gt;
By changing the blending property, we can tell the WebGL not only to draw the pixel, but also to &amp;#039;&amp;#039;&amp;#039;add the color of that pixel to the color of the pixel already drawn&amp;#039;&amp;#039;&amp;#039;. That will have a saturation effect that can look amazing.&lt;br /&gt;
&lt;br /&gt;
To test that, simply change the blending property to &amp;#039;&amp;#039;THREE.AdditiveBlending&amp;#039;&amp;#039; (keep the depthWrite property):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// particlesMaterial.alphaTest = 0.001&lt;br /&gt;
// particlesMaterial.depthTest = false&lt;br /&gt;
particlesMaterial.depthWrite = false&lt;br /&gt;
particlesMaterial.blending = THREE.AdditiveBlending&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add more particles (let&amp;#039;s say 20000) to better enjoy this effect.&lt;br /&gt;
&lt;br /&gt;
But be careful, this effect will impact the performances, and you won&amp;#039;t be able to have as many particles as before at 60fps.&lt;br /&gt;
&lt;br /&gt;
Now, we can remove the cube.&lt;br /&gt;
&lt;br /&gt;
=== Different colors ===&lt;br /&gt;
&lt;br /&gt;
We can have a different color for each particle. We first need to add a new attribute named color as we did for the position. A color is composed of red, green, and blue (3 values), so the code will be very similar to the position attribute. We can actually use the same loop for these two attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const positions = new Float32Array(count * 3)&lt;br /&gt;
const colors = new Float32Array(count * 3)&lt;br /&gt;
&lt;br /&gt;
for(let i = 0; i &amp;lt; count * 3; i++)&lt;br /&gt;
{&lt;br /&gt;
    positions[i] = (Math.random() - 0.5) * 10&lt;br /&gt;
    colors[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;position&amp;#039;, new THREE.BufferAttribute(positions, 3))&lt;br /&gt;
particlesGeometry.setAttribute(&amp;#039;color&amp;#039;, new THREE.BufferAttribute(colors, 3))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Be careful with singulars and plurals.&lt;br /&gt;
&lt;br /&gt;
To activate those vertex colors, simply change the &amp;#039;&amp;#039;&amp;#039;vertexColors property to true&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
 particlesMaterial.vertexColors = true&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;main color&amp;#039;&amp;#039;&amp;#039; of the material &amp;#039;&amp;#039;&amp;#039;still affects these vertex colors&amp;#039;&amp;#039;&amp;#039;. Feel free to change that color or even comment it.&lt;br /&gt;
&lt;br /&gt;
 // particlesMaterial.color = new THREE.Color(&amp;#039;#ff88cc&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
=== Animate ===&lt;br /&gt;
&lt;br /&gt;
There are multiple ways of animating particles.&lt;br /&gt;
==== By using the points as an object ====&lt;br /&gt;
&lt;br /&gt;
Because the &amp;#039;&amp;#039;&amp;#039;Points&amp;#039;&amp;#039;&amp;#039; class inherits from the &amp;#039;&amp;#039;&amp;#039;Object3D&amp;#039;&amp;#039;&amp;#039; class, you can &amp;#039;&amp;#039;&amp;#039;move, rotate and scale&amp;#039;&amp;#039;&amp;#039; the points as you wish.&lt;br /&gt;
&lt;br /&gt;
Rotate the particles in the tick function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update particles&lt;br /&gt;
    particles.rotation.y = elapsedTime * 0.2&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While this is already cool, we want &amp;#039;&amp;#039;&amp;#039;more control over each particle.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
By changing the attributes&lt;br /&gt;
&lt;br /&gt;
Another solution would be to &amp;#039;&amp;#039;&amp;#039;update each vertex position separately&amp;#039;&amp;#039;&amp;#039;. This way, vertices can have different trajectories. We are going to animate the particles as if they were floating on waves but first, let&amp;#039;s see how we can update the vertices.&lt;br /&gt;
&lt;br /&gt;
Start by commenting the previous rotation we did on the whole particles:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    // particles.rotation.y = elapsedTime * 0.2&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update each vertex, we have to &amp;#039;&amp;#039;&amp;#039;update the right part in the position attribute&amp;#039;&amp;#039;&amp;#039; because all the vertices are stored in this &amp;#039;&amp;#039;&amp;#039;one dimension array&amp;#039;&amp;#039;&amp;#039; where the first 3 values correspond to the x, y and z coordinates of the first vertex, then the next 3 values correspond to the x, y and z of the second vertex, etc.&lt;br /&gt;
&lt;br /&gt;
We only want the vertices to move up and down, meaning that we are going to update the y axis only. Because the position attribute is a one dimension array, we have to &amp;#039;&amp;#039;&amp;#039;go through it 3 by 3 and only update the second value which is the y coordinate&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s start by going through each vertices:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
        // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        const i3 = i * 3&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, we chose to have a simple for loop that goes from 0 to count and we created a &amp;#039;&amp;#039;&amp;#039;i3 variable inside that goes 3 by 3 simply by multiplying i by 3.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The easiest way to simulate &amp;#039;&amp;#039;&amp;#039;waves movement&amp;#039;&amp;#039;&amp;#039; is to use a simple &amp;#039;&amp;#039;&amp;#039;sinus&amp;#039;&amp;#039;&amp;#039;. First, we are going to update all vertices to go up and down on the same frequency.&lt;br /&gt;
&lt;br /&gt;
The y coordinate can be access in the array at the index i3 + 1:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        const i3 = i * 3&lt;br /&gt;
&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, nothing is moving. The problem is that &amp;#039;&amp;#039;&amp;#039;Three.js has to be notified that the geometry changed&amp;#039;&amp;#039;&amp;#039;. To do that, we have to set the &amp;#039;&amp;#039;&amp;#039;needsUpdate to true&amp;#039;&amp;#039;&amp;#039; on the position attribute once we are done updating the vertices:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        const i3 = i * 3&lt;br /&gt;
&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime)&lt;br /&gt;
    }&lt;br /&gt;
    particlesGeometry.attributes.position.needsUpdate = true &lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All the particles should be moving up and down like a plane.&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s a good start and we are almost there. All we need to do now is &amp;#039;&amp;#039;&amp;#039;apply an offset to the sinus between the particles&amp;#039;&amp;#039;&amp;#039; so that we get that &amp;#039;&amp;#039;&amp;#039;wave shape.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
To do that, we can &amp;#039;&amp;#039;&amp;#039;use the x coordinate&amp;#039;&amp;#039;&amp;#039;. And to get this value we can use the same technique that we used for the y coordinate but instead of i3 + 1, it&amp;#039;s just i3:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
    {&lt;br /&gt;
        let i3 = i * 3&lt;br /&gt;
&lt;br /&gt;
        const x = particlesGeometry.attributes.position.array[i3]&lt;br /&gt;
        particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime + x)&lt;br /&gt;
    }&lt;br /&gt;
    particlesGeometry.attributes.position.needsUpdate = true&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should get beautiful waves of particles. Unfortunately, &amp;#039;&amp;#039;&amp;#039;you should avoid this technique&amp;#039;&amp;#039;&amp;#039;. If we have 20000 particles, we are going through each one, calculating a new position, and updating the whole attribute on each frame. That can work with a small number of particles, but &amp;#039;&amp;#039;&amp;#039;we want millions of particles.&lt;br /&gt;
By using a custom shader&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;To update these millions of particles on each frame with a good framerate, we need to create our own material with our own shaders. But shaders are for a later lesson.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== GUI mit onChange / onFinishChange ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gui.add(params, &amp;#039;count&amp;#039;).min(100).max(1000000).step(100).onFinishChange(generateGalaxy)&lt;br /&gt;
gui.add(params, &amp;#039;size&amp;#039;).min(0.001).max(0.1).step(0.001).onFinishChange(generateGalaxy)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Vorsicht Memory-Leaks -&amp;gt; darauf achten, dass alte Geometrien / Materialien gelöscht werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const generateGalaxy = () =&amp;gt; {&lt;br /&gt;
    if(points != null){&lt;br /&gt;
        /**&lt;br /&gt;
         * Destroy old galaxy&lt;br /&gt;
         */&lt;br /&gt;
        pGeometry.dispose()&lt;br /&gt;
        pMaterial.dispose()&lt;br /&gt;
        scene.remove(points)&lt;br /&gt;
    }&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25814</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25814"/>
		<updated>2022-01-16T18:15:25Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Helfer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Test cube&lt;br /&gt;
 */&lt;br /&gt;
 const cube = new THREE.Mesh(&lt;br /&gt;
    new THREE.BoxGeometry(1, 1, 1),&lt;br /&gt;
    new THREE.MeshBasicMaterial()&lt;br /&gt;
)&lt;br /&gt;
scene.add(cube)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Models Importieren ==&lt;br /&gt;
[[Three.js - Import Models]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/FlightHelmet/glTF/FlightHelmet.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt; { &lt;br /&gt;
        console.log(gltf) //success - show what we got&lt;br /&gt;
        const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
        for(const child of children){&lt;br /&gt;
            scene.add(child)&lt;br /&gt;
        }&lt;br /&gt;
        //scene.add(gltf.scene)&lt;br /&gt;
        //scene.add(gltf.scene.children[1])&lt;br /&gt;
    },&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== DRACO Loader nutzen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
import { DRACOLoader } from &amp;#039;three/examples/jsm/loaders/DRACOLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const dracoLoader = new DRACOLoader()&lt;br /&gt;
dracoLoader.setDecoderPath(&amp;quot;/draco/&amp;quot;) // get webassembly version (faster but you have to provide the appropriate draco files)&lt;br /&gt;
&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.setDRACOLoader(dracoLoader)&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF-Draco/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt; { &lt;br /&gt;
        scene.add(gltf.scene)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=3D-Drucker_kalibrieren_und_einstellen&amp;diff=25813</id>
		<title>3D-Drucker kalibrieren und einstellen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=3D-Drucker_kalibrieren_und_einstellen&amp;diff=25813"/>
		<updated>2022-01-15T19:13:56Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Ablauf */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Ablauf ==&lt;br /&gt;
Was kann man Einstellen und auf was hat es Einfluss?&lt;br /&gt;
* Laufwägen - Andruck der Rollen checken&lt;br /&gt;
* Motoren eSteps kalibrieren&lt;br /&gt;
** Achsen für Maßhaltigkeit (Calibration Cube)&lt;br /&gt;
** Extruder für Flow&lt;br /&gt;
&lt;br /&gt;
== Bedleveling - Druckbett einstellen ==&lt;br /&gt;
 https://drucktipps3d.de/bettleveling-bettleveling-und-immer-wieder-bettleveling/&lt;br /&gt;
&lt;br /&gt;
* Bett vorheizen&lt;br /&gt;
* Autohome&lt;br /&gt;
* Stepper aus (außer z bei bettwewegern) &lt;br /&gt;
* links vorn, links hinten, rechts hinten, rechts vorn&lt;br /&gt;
* 2. Runde, Mitte&lt;br /&gt;
=== Feintuning ===&lt;br /&gt;
Feinausrichtung.&lt;br /&gt;
&lt;br /&gt;
Dder erste Layer entscheidet.&lt;br /&gt;
&lt;br /&gt;
* Druckobjekt aus 5 Quadraten mit ca. 20mm Kantenlänge, Höhe 0,2mm (1 Layer) &lt;br /&gt;
* 4 Ecken und der Mitte anordnen.&lt;br /&gt;
* Im Slicer Skirt mit ca. 5 Linien hinzu&lt;br /&gt;
* Geschwindigkeit drastisch reduzieren (direkt im Drucker regeln z.B. 30%), dann kann man direkt reagieren und die Haftung ist gut.&lt;br /&gt;
&lt;br /&gt;
Beim Druck des Skirt könnt Ihr optisch und mit dem Finger fühlen ob und wie die Plastewurst auf dem Druckbett haftet und könnt das Druckbett nachjustieren. &lt;br /&gt;
An den Quadraten bekommt Ihr das Ergebnis Eurer Bemühung. Eine saubere geschlossene Fläche ist das Ziel. Fehlerbilder für Düsenabstand und andere Druckprobleme findet Ihr mit Erklärung auf der Seite von Simplify 3D. &lt;br /&gt;
&lt;br /&gt;
Wiederholt diesen Ausdruck bis das Ergebnis perfekt ist.&lt;br /&gt;
&lt;br /&gt;
== Probleme und Lösungen ==&lt;br /&gt;
&lt;br /&gt;
=== Stringing ===&lt;br /&gt;
* Feuchtes Filament &lt;br /&gt;
* Nozzle verschmuzt&lt;br /&gt;
* Retraction zu schwach oder/und zu schnell&lt;br /&gt;
* Kühlung falsch&lt;br /&gt;
* Bowdenzug hat viel Spiel&lt;br /&gt;
* Temperatur falsch (Heattower drucken)&lt;br /&gt;
&lt;br /&gt;
=== Über- Unterextrudierung ===&lt;br /&gt;
&lt;br /&gt;
=== Betthaftung ===&lt;br /&gt;
* Auflagefläche zu klein&lt;br /&gt;
* Nozzle zu weit weg (Druckbett leveln)&lt;br /&gt;
* Fett auf der Fläche&lt;br /&gt;
* Temperatur falsch (vor allem bei ABS etc wichtig)&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Flow Control / Fluss einstellen ===&lt;br /&gt;
Den Flow kann man in Cura einstellen. &lt;br /&gt;
Landen pro Schicht wirklich 0.4mm auf dem Bett, wenn 0.4mm eingestellt sind? &lt;br /&gt;
Abhängig haupsächlich von:&lt;br /&gt;
* Extruderkalibrierung &lt;br /&gt;
* Filament - Wenn das dicker ist kommt mehr raus&lt;br /&gt;
&lt;br /&gt;
==== Flow Tests ====&lt;br /&gt;
20mm Calibration Cube laden (Wandstärke 1 Schicht)&lt;br /&gt;
&lt;br /&gt;
Cura:&lt;br /&gt;
 Linienbreite 0.4mm, Wandanzahl: 1&lt;br /&gt;
 Obere Untere Schichten 0 (nur Wände)&lt;br /&gt;
 Infill keins&lt;br /&gt;
 Flow steht auf 100%&lt;br /&gt;
&lt;br /&gt;
Nach dem Drucken Wandstärke messen (am besten nur oben wg. Elefantenfüßen)&lt;br /&gt;
&lt;br /&gt;
 Soll-Wandstärke x 100 / IstWandstärke = Flow&lt;br /&gt;
&lt;br /&gt;
z.B. 0.4 * 100 / 0.48 = 83,5&lt;br /&gt;
&lt;br /&gt;
im Zweifel vlt. eher Aufrunden (Ungenauigkeiten, Hitze... tragen eher breiter auf)&lt;br /&gt;
&lt;br /&gt;
=== Extruder Fördermenge / eSteps einstellen ===&lt;br /&gt;
&lt;br /&gt;
10cm fördern, tatsächliche Fördermenge messen&lt;br /&gt;
 Neue Steps = Alte Steps / Tatsächlich geförderte Länge * gewünschte Länge&lt;br /&gt;
Neue Werte über Display oder über Terminalsoftware im Drucker speichern.&lt;br /&gt;
==&lt;br /&gt;
Die wichtigsten Befehle für Pronterface:&lt;br /&gt;
&lt;br /&gt;
M503 = gespeicherte e Steps anzeigen lassen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
M92 E(neue Steps) = neue e Steps im System hinterlegen (Punkte keine Kommas!)&lt;br /&gt;
&lt;br /&gt;
M500 = neuen Wert in der Firmware speichern&lt;br /&gt;
&lt;br /&gt;
https://www.pronterface.com/&lt;br /&gt;
&lt;br /&gt;
Regeln&lt;br /&gt;
&lt;br /&gt;
25%-75% Regel&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=3D-Drucker_kalibrieren_und_einstellen&amp;diff=25812</id>
		<title>3D-Drucker kalibrieren und einstellen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=3D-Drucker_kalibrieren_und_einstellen&amp;diff=25812"/>
		<updated>2022-01-15T13:14:14Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: Die Seite wurde neu angelegt: „== Ablauf == Was kann man Einstellen und auf was hat es Einfluss? * Laufwägen - Andruck der Rollen checken * Motoren eSteps kalibrieren ** Achsen für Maßhal…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Ablauf ==&lt;br /&gt;
Was kann man Einstellen und auf was hat es Einfluss?&lt;br /&gt;
* Laufwägen - Andruck der Rollen checken&lt;br /&gt;
* Motoren eSteps kalibrieren&lt;br /&gt;
** Achsen für Maßhaltigkeit (Calibration Cube)&lt;br /&gt;
** Extruder für Flow&lt;br /&gt;
&lt;br /&gt;
== Probleme und Lösungen ==&lt;br /&gt;
&lt;br /&gt;
=== Stringing ===&lt;br /&gt;
* Feuchtes Filament &lt;br /&gt;
* Nozzle verschmuzt&lt;br /&gt;
* Retraction zu schwach oder/und zu schnell&lt;br /&gt;
* Kühlung falsch&lt;br /&gt;
* Bowdenzug hat viel Spiel&lt;br /&gt;
* Temperatur falsch (Heattower drucken)&lt;br /&gt;
&lt;br /&gt;
=== Über- Unterextrudierung ===&lt;br /&gt;
&lt;br /&gt;
=== Betthaftung ===&lt;br /&gt;
* Auflagefläche zu klein&lt;br /&gt;
* Nozzle zu weit weg (Druckbett leveln)&lt;br /&gt;
* Fett auf der Fläche&lt;br /&gt;
* Temperatur falsch (vor allem bei ABS etc wichtig)&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Flow Control / Fluss einstellen ===&lt;br /&gt;
Den Flow kann man in Cura einstellen. &lt;br /&gt;
Landen pro Schicht wirklich 0.4mm auf dem Bett, wenn 0.4mm eingestellt sind? &lt;br /&gt;
Abhängig haupsächlich von:&lt;br /&gt;
* Extruderkalibrierung &lt;br /&gt;
* Filament - Wenn das dicker ist kommt mehr raus&lt;br /&gt;
&lt;br /&gt;
==== Flow Tests ====&lt;br /&gt;
20mm Calibration Cube laden (Wandstärke 1 Schicht)&lt;br /&gt;
&lt;br /&gt;
Cura:&lt;br /&gt;
 Linienbreite 0.4mm, Wandanzahl: 1&lt;br /&gt;
 Obere Untere Schichten 0 (nur Wände)&lt;br /&gt;
 Infill keins&lt;br /&gt;
 Flow steht auf 100%&lt;br /&gt;
&lt;br /&gt;
Nach dem Drucken Wandstärke messen (am besten nur oben wg. Elefantenfüßen)&lt;br /&gt;
&lt;br /&gt;
 Soll-Wandstärke x 100 / IstWandstärke = Flow&lt;br /&gt;
&lt;br /&gt;
z.B. 0.4 * 100 / 0.48 = 83,5&lt;br /&gt;
&lt;br /&gt;
im Zweifel vlt. eher Aufrunden (Ungenauigkeiten, Hitze... tragen eher breiter auf)&lt;br /&gt;
&lt;br /&gt;
=== Extruder Fördermenge / eSteps einstellen ===&lt;br /&gt;
&lt;br /&gt;
10cm fördern, tatsächliche Fördermenge messen&lt;br /&gt;
 Neue Steps = Alte Steps / Tatsächlich geförderte Länge * gewünschte Länge&lt;br /&gt;
Neue Werte über Display oder über Terminalsoftware im Drucker speichern.&lt;br /&gt;
==&lt;br /&gt;
Die wichtigsten Befehle für Pronterface:&lt;br /&gt;
&lt;br /&gt;
M503 = gespeicherte e Steps anzeigen lassen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
M92 E(neue Steps) = neue e Steps im System hinterlegen (Punkte keine Kommas!)&lt;br /&gt;
&lt;br /&gt;
M500 = neuen Wert in der Firmware speichern&lt;br /&gt;
&lt;br /&gt;
https://www.pronterface.com/&lt;br /&gt;
&lt;br /&gt;
Regeln&lt;br /&gt;
&lt;br /&gt;
25%-75% Regel&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=3D-Druck&amp;diff=25811</id>
		<title>3D-Druck</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=3D-Druck&amp;diff=25811"/>
		<updated>2022-01-15T12:46:56Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: Die Seite wurde neu angelegt: „== Links == 3D-Drucker kalibrieren und einstellen“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
[[3D-Drucker kalibrieren und einstellen]]&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Mac_-_Applescript&amp;diff=25798</id>
		<title>Mac - Applescript</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Mac_-_Applescript&amp;diff=25798"/>
		<updated>2022-01-05T13:22:53Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mit Applescript kann man viel auf dem Mac automatisieren.&lt;br /&gt;
&lt;br /&gt;
 [[Applescript - Browser Screenshots automatisieren]]&lt;br /&gt;
&lt;br /&gt;
== Automator ==&lt;br /&gt;
Automator vereinfacht das Scripting und ist im Prinzip ein Tool um Skripte aus vorgefertigten Bausteinen zusammenzuklicken&lt;br /&gt;
 https://mac.appstorm.net/how-to/productivity-how-to/automator-the-ultimate-automation-assistant/#more-4345&lt;br /&gt;
&lt;br /&gt;
== Mac - Scripts ==&lt;br /&gt;
=== .mov -&amp;gt; .mp4 mit Handbreak CLI ===&lt;br /&gt;
Benötigt handbreak&lt;br /&gt;
 https://handbrake.fr/downloads.php&lt;br /&gt;
=== .mov -&amp;gt; .gif mit ffmpeg ===&lt;br /&gt;
&lt;br /&gt;
converting .mov files (created by MacOS screencasts for example) to small .gif files that you can easily send via email.&lt;br /&gt;
&lt;br /&gt;
You will then have a quick action after right clicking any .mov file and can simply convert it to a small and optimised .gif file.&lt;br /&gt;
&lt;br /&gt;
    * fire up automator&lt;br /&gt;
    *     create a new quick action&lt;br /&gt;
    *     add a shell script to your workflow&lt;br /&gt;
    *     paste the following code and don’t forget to choose “as arguments” in the pass input dropdown&lt;br /&gt;
    *     save it&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shellscript&amp;quot;&amp;gt;&lt;br /&gt;
for f&lt;br /&gt;
do&lt;br /&gt;
    if [[ $f == *.mov ]]; then&lt;br /&gt;
        /usr/local/bin/ffmpeg -i &amp;quot;$f&amp;quot; -pix_fmt rgb24 -r 10 -f gif - | /usr/local/bin/gifsicle --optimize=3 &amp;gt; &amp;quot;$f&amp;quot;.gif&lt;br /&gt;
    fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is how everything should look after you are finished.&lt;br /&gt;
mov_to_giv_automator&lt;br /&gt;
&lt;br /&gt;
You &amp;#039;&amp;#039;&amp;#039;need ffmpeg and gifsicle installed&amp;#039;&amp;#039;&amp;#039; so if you haven’t install them via homebrew.&lt;br /&gt;
&lt;br /&gt;
 brew install ffmpeg&lt;br /&gt;
 brew install gifsicle&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Mac_-_Applescript&amp;diff=25797</id>
		<title>Mac - Applescript</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Mac_-_Applescript&amp;diff=25797"/>
		<updated>2022-01-05T13:18:15Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Automater */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mit Applescript kann man viel auf dem Mac automatisieren.&lt;br /&gt;
&lt;br /&gt;
 [[Applescript - Browser Screenshots automatisieren]]&lt;br /&gt;
&lt;br /&gt;
== Automator ==&lt;br /&gt;
Automator vereinfacht das Scripting und ist im Prinzip ein Tool um Skripte aus vorgefertigten Bausteinen zusammenzuklicken&lt;br /&gt;
 https://mac.appstorm.net/how-to/productivity-how-to/automator-the-ultimate-automation-assistant/#more-4345&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25796</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25796"/>
		<updated>2022-01-05T12:04:54Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Models Importieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Models Importieren ==&lt;br /&gt;
[[Three.js - Import Models]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/FlightHelmet/glTF/FlightHelmet.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt; { &lt;br /&gt;
        console.log(gltf) //success - show what we got&lt;br /&gt;
        const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
        for(const child of children){&lt;br /&gt;
            scene.add(child)&lt;br /&gt;
        }&lt;br /&gt;
        //scene.add(gltf.scene)&lt;br /&gt;
        //scene.add(gltf.scene.children[1])&lt;br /&gt;
    },&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== DRACO Loader nutzen ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
import { DRACOLoader } from &amp;#039;three/examples/jsm/loaders/DRACOLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const dracoLoader = new DRACOLoader()&lt;br /&gt;
dracoLoader.setDecoderPath(&amp;quot;/draco/&amp;quot;) // get webassembly version (faster but you have to provide the appropriate draco files)&lt;br /&gt;
&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.setDRACOLoader(dracoLoader)&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF-Draco/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt; { &lt;br /&gt;
        scene.add(gltf.scene)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25795</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25795"/>
		<updated>2022-01-05T11:47:59Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Mehrere Children */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    (error) =&amp;gt; {console.log(error)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[ThreeJS - Snippets]]&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanG=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Children ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorsicht&amp;#039;&amp;#039;&amp;#039; wenn es mehrere Children gibt die man alle importieren möchte:&lt;br /&gt;
&lt;br /&gt;
Die erste Lösung funktioniert nicht richtig. Bei jedem Schleifendurchlauf wird das Element aus dem (besonderen) gltf Array entnommen. Das Array verkürzt sich. Der Index der Schleife bleibt aber gleich, daher werden Objekte ausgelassen.&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// NOT WORKING&lt;br /&gt;
for(const child of gltf.scene.children){ // not working properly&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING&lt;br /&gt;
while(gltf.scene.children.length){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
for(const child of children){&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
for(let i = gltf.scene.children.length; i &amp;gt; 0; i--){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Draco Compression ===&lt;br /&gt;
* Benötigt den Dracoloader&lt;br /&gt;
* As we saw when browsing the files, the Draco version can be much lighter than the default version. Compression is applied to the buffer data (typically the geometry). It doesn&amp;#039;t matter if you are using the default glTF, the binary glTF or the embedded glTF.&lt;br /&gt;
* It&amp;#039;s not even exclusive to glTF, and you can use it with other formats. But both glTF and Draco got popular simultaneously, so the implementation went faster with glTF exporters.&lt;br /&gt;
* Google develops the algorithm under the open-source Apache License&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25794</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25794"/>
		<updated>2022-01-05T11:44:14Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Quickstart */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    (error) =&amp;gt; {console.log(error)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[ThreeJS - Snippets]]&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanG=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Children ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorsicht&amp;#039;&amp;#039;&amp;#039; wenn es mehrere Children gibt die man alle importieren möchte:&lt;br /&gt;
&lt;br /&gt;
Die erste Lösung funktioniert nicht richtig. Bei jedem Schleifendurchlauf wird das Element aus dem (besonderen) gltf Array entnommen. Das Array verkürzt sich. Der Index der Schleife bleibt aber gleich, daher werden Objekte ausgelassen.&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// NOT WORKING&lt;br /&gt;
for(const child of gltf.scene.children){ // not working properly&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING&lt;br /&gt;
while(gltf.scene.children.length){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
for(const child of children){&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
for(let i = gltf.scene.children.length; i &amp;gt; 0; i--){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25793</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25793"/>
		<updated>2022-01-05T11:37:16Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Models Importieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Models Importieren ==&lt;br /&gt;
[[Three.js - Import Models]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/FlightHelmet/glTF/FlightHelmet.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt; { &lt;br /&gt;
        console.log(gltf) //success - show what we got&lt;br /&gt;
        const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
        for(const child of children){&lt;br /&gt;
            scene.add(child)&lt;br /&gt;
        }&lt;br /&gt;
        //scene.add(gltf.scene)&lt;br /&gt;
        //scene.add(gltf.scene.children[1])&lt;br /&gt;
    },&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25792</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25792"/>
		<updated>2022-01-05T11:09:06Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Models Importieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Models Importieren ==&lt;br /&gt;
[[Three.js - Import Models]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/FlightHelmet/glTF/FlightHelmet.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt; { &lt;br /&gt;
        console.log(gltf) //success - show what we got&lt;br /&gt;
        const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
        for(const child of children){&lt;br /&gt;
            scene.add(child)&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //scene.add(gltf.scene.children[1])&lt;br /&gt;
    },&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25791</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25791"/>
		<updated>2022-01-05T11:07:59Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 [[ThreeJS - Snippets]]&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanG=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Children ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorsicht&amp;#039;&amp;#039;&amp;#039; wenn es mehrere Children gibt die man alle importieren möchte:&lt;br /&gt;
&lt;br /&gt;
Die erste Lösung funktioniert nicht richtig. Bei jedem Schleifendurchlauf wird das Element aus dem (besonderen) gltf Array entnommen. Das Array verkürzt sich. Der Index der Schleife bleibt aber gleich, daher werden Objekte ausgelassen.&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// NOT WORKING&lt;br /&gt;
for(const child of gltf.scene.children){ // not working properly&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING&lt;br /&gt;
while(gltf.scene.children.length){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
for(const child of children){&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
for(let i = gltf.scene.children.length; i &amp;gt; 0; i--){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25790</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25790"/>
		<updated>2022-01-05T11:06:53Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanG=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Children ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Vorsicht&amp;#039;&amp;#039;&amp;#039; wenn es mehrere Children gibt die man alle importieren möchte:&lt;br /&gt;
&lt;br /&gt;
Die erste Lösung funktioniert nicht richtig. Bei jedem Schleifendurchlauf wird das Element aus dem (besonderen) gltf Array entnommen. Das Array verkürzt sich. Der Index der Schleife bleibt aber gleich, daher werden Objekte ausgelassen.&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// NOT WORKING&lt;br /&gt;
for(const child of gltf.scene.children){ // not working properly&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING&lt;br /&gt;
while(gltf.scene.children.length){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
const children = [...gltf.scene.children] // duplicate&lt;br /&gt;
for(const child of children){&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
for(let i = gltf.scene.children.length; i &amp;gt; 0; i--){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25789</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25789"/>
		<updated>2022-01-05T10:52:47Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Loader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanG=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Vorsicht wenn es mehrere Children gibt die man alle importieren möchte:&lt;br /&gt;
&lt;br /&gt;
Diese Lösung funktioniert nicht richtig. Bei jedem add werden der gltf Scene Objekte entnommen und das Array verkürzt sich. Der Index der Schleife bleibt aber gleich, daher werden Objekte ausgelassen.&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// NOT WORKING&lt;br /&gt;
for(const child of gltf.scene.children){ // not working properly&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING&lt;br /&gt;
while(gltf.scene.children.length){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
for(let i = gltf.scene.children.length; i &amp;gt; 0; i--){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25788</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25788"/>
		<updated>2022-01-05T10:52:16Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Add the loaded model to our scene */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Vorsicht wenn es mehrere Children gibt die man alle importieren möchte:&lt;br /&gt;
&lt;br /&gt;
Diese Lösung funktioniert nicht richtig. Bei jedem add werden der gltf Scene Objekte entnommen und das Array verkürzt sich. Der Index der Schleife bleibt aber gleich, daher werden Objekte ausgelassen.&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// NOT WORKING&lt;br /&gt;
for(const child of gltf.scene.children){ // not working properly&lt;br /&gt;
  scene.add(child)&lt;br /&gt;
}&lt;br /&gt;
// WORKING&lt;br /&gt;
while(gltf.scene.children.length){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;br /&gt;
// WORKING TOO&lt;br /&gt;
for(let i = gltf.scene.children.length; i &amp;gt; 0; i--){&lt;br /&gt;
  scene.add(gltf.scene.children[0])&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25787</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25787"/>
		<updated>2022-01-05T10:24:59Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
 https://threejs-journey.com/lessons/23 - englischsprachige Teile in diesem Artikel und Beispiele&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25786</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25786"/>
		<updated>2022-01-05T10:21:49Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
* Nach dem Import immer über Console checken was drin ist. &lt;br /&gt;
* Wichtig Scale und Transform Values checken. Dann weißt du gleich wo du suchen mußt wenn du nichts siehts.&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;br /&gt;
&lt;br /&gt;
In den Beispielen nutzen wir gltf&lt;br /&gt;
&lt;br /&gt;
== Loader ==&lt;br /&gt;
=== Add the loaded model to our scene ===&lt;br /&gt;
Wo ist was?&lt;br /&gt;
&lt;br /&gt;
If you look at the object logged in the console, you&amp;#039;ll find a lot of elements. The most important part is the scene property because we have only one scene in the exported model.&lt;br /&gt;
&lt;br /&gt;
This scene contains everything we need. But it also includes more. Always start by studying what is available in it and watch the scale property of the different Groups, Object3D, and Mesh.&lt;br /&gt;
&lt;br /&gt;
We get something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
THREE.Group: scene&lt;br /&gt;
└───Array: children&lt;br /&gt;
    └───THREE.Object3D&lt;br /&gt;
        └───Array: children&lt;br /&gt;
            ├───THREE.PerspectiveCamera&lt;br /&gt;
            └───THREE.Mesh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Mesh should be our duck. We don&amp;#039;t really care about the PerspectiveCamera. Both the camera and the duck seem to be in the first and only Object3D in the scene&amp;#039;s children array. Even worst, that Object3D has a scale set to a minimal value.&lt;br /&gt;
&lt;br /&gt;
As you can see, it&amp;#039;s a little complex even to get our duck, and it&amp;#039;s where most beginners get lost.&lt;br /&gt;
&lt;br /&gt;
All we want is to get our duck in the scene. We have multiples ways of doing it:&lt;br /&gt;
&lt;br /&gt;
    Add the whole scene in our scene. We can do that because even if its name is scene, it&amp;#039;s in fact a Group.&lt;br /&gt;
    Add the children of the scene to our scene and ignore the unused PerspectiveCamera.&lt;br /&gt;
    Filter the children before adding to the scene to remove the unwanted objects like the PerspectiveCamera.&lt;br /&gt;
    Add only the Mesh but end up with a duck that could be wrongly scaled, positioned or rotated.&lt;br /&gt;
    Open the file in a 3D software and remove the PerspectiveCamera then export it again.&lt;br /&gt;
&lt;br /&gt;
Because our model structure is simple, we will add the Object3D to our scene, and ignore the unused PerspectiveCamera inside. In future lessons, we will add the whole scene as one object&lt;br /&gt;
&amp;lt;syntaxhighlight lanl=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    (gltf) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        scene.add(gltf.scene.children[0])&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25785</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25785"/>
		<updated>2022-01-05T10:02:09Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Quickstart */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
const gltfLoader = new GLTFLoader()&lt;br /&gt;
gltfLoader.load(&lt;br /&gt;
    &amp;#039;/models/Duck/glTF/Duck.gltf&amp;#039;,&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;success&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;progress&amp;#039;)},&lt;br /&gt;
    () =&amp;gt; {console.log(&amp;#039;error&amp;#039;)}&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25784</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25784"/>
		<updated>2022-01-05T09:57:08Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { GLTFLoader } from &amp;#039;three/examples/jsm/loaders/GLTFLoader.js&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25783</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25783"/>
		<updated>2022-01-05T09:55:36Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* GLTF */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF - Standard, Alle Assets einzeln in einem Ordner&lt;br /&gt;
 glTF-Binary - alle Assets in einer Binären Datei&lt;br /&gt;
 glTF-Draco - Eine Datei mit Draco Kompression (sehr klein muss aber entpackt werden)&lt;br /&gt;
 glTF-Embedded - Alle Dateien aus Standard Base64(?) Kodiert in einer Text-Datei&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25782</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25782"/>
		<updated>2022-01-05T09:35:52Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* GLTF */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;br /&gt;
&lt;br /&gt;
Verschiedene Varianten&lt;br /&gt;
&lt;br /&gt;
 glTF&lt;br /&gt;
 glTF-Binary&lt;br /&gt;
 glTF-Draco&lt;br /&gt;
 glTF-Embedded&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25781</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25781"/>
		<updated>2022-01-05T09:32:39Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
 https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
 https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
 https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
 https://github.com/google/draco Repository&lt;br /&gt;
 https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
 https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
 https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
 https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
 https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
 https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
 https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
 https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25780</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25780"/>
		<updated>2022-01-05T09:32:12Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
Others&lt;br /&gt;
&lt;br /&gt;
https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics Formats (wiki)&lt;br /&gt;
https://threejs.org/editor/ Three.js editor&lt;br /&gt;
&lt;br /&gt;
GLTF sample models&lt;br /&gt;
&lt;br /&gt;
https://github.com/KhronosGroup/glTF-Sample-Models Repository&lt;br /&gt;
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck Duck&lt;br /&gt;
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox Fox&lt;br /&gt;
&lt;br /&gt;
Draco&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/draco Repository&lt;br /&gt;
https://google.github.io/draco/ Website&lt;br /&gt;
&lt;br /&gt;
Three.js documentation&lt;br /&gt;
&lt;br /&gt;
https://threejs.org/docs/#api/en/objects/Mesh Mesh&lt;br /&gt;
https://threejs.org/docs/#api/en/materials/MeshStandardMaterial MeshStandardMaterial&lt;br /&gt;
https://threejs.org/docs/#api/en/lights/AmbientLight AmbientLight&lt;br /&gt;
https://threejs.org/docs/#api/en/lights/DirectionalLight DirectionalLight&lt;br /&gt;
https://threejs.org/docs/#examples/en/loaders/GLTFLoader GLTFLoader&lt;br /&gt;
https://threejs.org/docs/index.html#api/en/loaders/TextureLoader TextureLoader&lt;br /&gt;
https://threejs.org/docs/#api/en/loaders/managers/LoadingManager LoadingManager&lt;br /&gt;
https://threejs.org/docs/#api/en/objects/Group Group&lt;br /&gt;
https://threejs.org/docs/#api/en/core/Object3D Object3D&lt;br /&gt;
https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera&lt;br /&gt;
https://threejs.org/docs/#examples/en/loaders/DRACOLoader DracoLoader&lt;br /&gt;
https://threejs.org/docs/#api/en/objects/Bone Bone&lt;br /&gt;
https://threejs.org/docs/#api/en/objects/SkinnedMesh SkinnedMesh&lt;br /&gt;
https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip&lt;br /&gt;
https://threejs.org/docs/#api/en/animation/AnimationMixer AnimationMixer&lt;br /&gt;
https://threejs.org/docs/#api/en/animation/AnimationAction AnimationAction&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25779</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25779"/>
		<updated>2022-01-05T09:23:13Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
== Links ==&lt;br /&gt;
&amp;lt;div class=&amp;quot;js-scroll-mover scroll-mover text&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;p&amp;gt;Others&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics&amp;quot;&amp;gt;Formats (wiki)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/editor/&amp;quot;&amp;gt;Three.js editor&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;GLTF sample models&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://github.com/KhronosGroup/glTF-Sample-Models&amp;quot;&amp;gt;Repository&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck&amp;quot;&amp;gt;Duck&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Fox&amp;quot;&amp;gt;Fox&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Draco&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://github.com/google/draco&amp;quot;&amp;gt;Repository&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://google.github.io/draco/&amp;quot;&amp;gt;Website&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Three.js documentation&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/objects/Mesh&amp;quot;&amp;gt;Mesh&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/materials/MeshStandardMaterial&amp;quot;&amp;gt;MeshStandardMaterial&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/lights/AmbientLight&amp;quot;&amp;gt;AmbientLight&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/lights/DirectionalLight&amp;quot;&amp;gt;DirectionalLight&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#examples/en/loaders/GLTFLoader&amp;quot;&amp;gt;GLTFLoader&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/index.html#api/en/loaders/TextureLoader&amp;quot;&amp;gt;TextureLoader&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/loaders/managers/LoadingManager&amp;quot;&amp;gt;LoadingManager&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/objects/Group&amp;quot;&amp;gt;Group&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/core/Object3D&amp;quot;&amp;gt;Object3D&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/cameras/PerspectiveCamera&amp;quot;&amp;gt;PerspectiveCamera&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#examples/en/loaders/DRACOLoader&amp;quot;&amp;gt;DracoLoader&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/objects/Bone&amp;quot;&amp;gt;Bone&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/objects/SkinnedMesh&amp;quot;&amp;gt;SkinnedMesh&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/animation/AnimationClip&amp;quot;&amp;gt;AnimationClip&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/animation/AnimationMixer&amp;quot;&amp;gt;AnimationMixer&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/docs/#api/en/animation/AnimationAction&amp;quot;&amp;gt;AnimationAction&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25778</id>
		<title>Three.js - Import Models</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Import_Models&amp;diff=25778"/>
		<updated>2022-01-05T09:22:23Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: Die Seite wurde neu angelegt: „Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll? == Links == &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://en.wikipedia.org/wiki/List_o…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie importiert man Models in Three.js und welche Dateiformate sind sinnvoll?&lt;br /&gt;
== Links ==&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics&amp;quot;&amp;gt;Formats (wiki)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;a target=&amp;quot;_blank&amp;quot; href=&amp;quot;https://threejs.org/editor/&amp;quot;&amp;gt;Three.js editor&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
== Dateiformate ==&lt;br /&gt;
=== GLTF ===&lt;br /&gt;
* Von der Khronos Group (OpenGL, WebGL...) erfüllt viele Zwecke gerade wenn man im Web unterwegs ist.&lt;br /&gt;
* Kann einen Scene Graph mit übernehmen&lt;br /&gt;
* Kann JSON, binary, embeded textures mit einbinden&lt;br /&gt;
* Stand 2021 quasi Standard - funktioniert auch mit Unity, Blender etc.&lt;br /&gt;
&lt;br /&gt;
andere können aber auch sinnvoll sein: obj, effizient - ply klein schnelle dekompression....&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25777</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25777"/>
		<updated>2022-01-05T09:14:35Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Models Importieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Models Importieren ==&lt;br /&gt;
[[Three.js - Import Models]]&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25776</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25776"/>
		<updated>2022-01-05T09:14:16Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Particles */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Models Importieren ==&lt;br /&gt;
Three.js - Import Models&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_eigene_Geometrie_erzeugen&amp;diff=25775</id>
		<title>Three.js - eigene Geometrie erzeugen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_eigene_Geometrie_erzeugen&amp;diff=25775"/>
		<updated>2022-01-04T11:03:24Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* BufferGeometry - Geometrie eines Objekts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; https://threejs.org/manual/?q=geometr#en/custom-buffergeometry&lt;br /&gt;
== BufferGeometry - Geometrie eines Objekts ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;BufferGeometry&amp;#039;&amp;#039;&amp;#039; ist das Objekt mit dem Three.js alle &amp;#039;&amp;#039;&amp;#039;geometrischen Daten&amp;#039;&amp;#039;&amp;#039; darstellt. Eine BufferGeometry ist wiederum eine &amp;#039;&amp;#039;&amp;#039;Zusammenstellung von mehreren BufferAttribute&amp;#039;&amp;#039;&amp;#039; Objekten. &lt;br /&gt;
&lt;br /&gt;
Jedes BufferAttribute steht für einen Typ von Daten: &lt;br /&gt;
 positions&lt;br /&gt;
 normals&lt;br /&gt;
 colors&lt;br /&gt;
 uv&lt;br /&gt;
 ... &lt;br /&gt;
Jeder Vertex hat für jedes Attribut ein Set an Daten. Jeder Punkt bekommt also Infos über Position, Farbe etc. Achtung: Ein Würfel hat an einer Ecke 3 Vertices, da er 3 Flächen in unterschiedlicher Richtung hat. Die Normalen sind also Unterschiedlich. Sobald ein Wert sich ändert benötigt man einen neuen Vertex. Eine Ecke eines Würfels hat also 3 Vertices.&lt;br /&gt;
&lt;br /&gt;
== Geometrien erstellen ==&lt;br /&gt;
=== Der Weg zur Geometrie ===&lt;br /&gt;
* Arrays für Attribute erzeugen (am besten Typed Array wg. Performance)&lt;br /&gt;
* BufferGeometry Objekt erzeugen&lt;br /&gt;
* BufferAttribute Objekte erzeugen die jeweils Werte für alle Vertices enthalten und an die Geometrie übergeben.&lt;br /&gt;
=== Wie sehen die Geometrien aus ===&lt;br /&gt;
Beispiel Würfel. &lt;br /&gt;
siehe Link oben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 //TODO&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_eigene_Geometrie_erzeugen&amp;diff=25774</id>
		<title>Three.js - eigene Geometrie erzeugen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_eigene_Geometrie_erzeugen&amp;diff=25774"/>
		<updated>2022-01-04T10:49:46Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; https://threejs.org/manual/?q=geometr#en/custom-buffergeometry&lt;br /&gt;
== BufferGeometry - Geometrie eines Objekts ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;BufferGeometry&amp;#039;&amp;#039;&amp;#039; ist das Objekt mit dem Three.js alle &amp;#039;&amp;#039;&amp;#039;geometrischen Daten&amp;#039;&amp;#039;&amp;#039; darstellt. Eine BufferGeometry ist wiederum eine &amp;#039;&amp;#039;&amp;#039;Zusammenstellung von mehreren BufferAttribute&amp;#039;&amp;#039;&amp;#039; Objekten. &lt;br /&gt;
&lt;br /&gt;
Jedes BufferAttribute steht für einen Typ von Daten: &lt;br /&gt;
 positions&lt;br /&gt;
 normals&lt;br /&gt;
 colors&lt;br /&gt;
 uv&lt;br /&gt;
 ... &lt;br /&gt;
Diese Arrays sind alle gleich groß und haben für jeden Vertex ein Set an Daten. Jeder Punkt bekommt also Infos über Position, Normalen etc. Achtung: Ein Würfel hat an einer Ecke 3 Vertices, da er 3 Flächen in unterschiedlicher Richtung hat. Die Normalen sind also Unterschiedlich. Sobald ein Wert sich ändert benötigt man einen neuen Vertex.&lt;br /&gt;
&lt;br /&gt;
 //TODO&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_eigene_Geometrie_erzeugen&amp;diff=25773</id>
		<title>Three.js - eigene Geometrie erzeugen</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_eigene_Geometrie_erzeugen&amp;diff=25773"/>
		<updated>2022-01-04T10:36:09Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: Die Seite wurde neu angelegt: „ https://threejs.org/manual/?q=geometr#en/custom-buffergeometry“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; https://threejs.org/manual/?q=geometr#en/custom-buffergeometry&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25772</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25772"/>
		<updated>2022-01-04T10:35:46Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Create Geometry / Geometry Objekt erzeugen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
 [[Three.js - eigene Geometrie erzeugen]]&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shader_Snippets&amp;diff=25771</id>
		<title>Three.js - Shader Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shader_Snippets&amp;diff=25771"/>
		<updated>2022-01-03T12:33:21Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: Die Seite wurde neu angelegt: „ Three.js - Shaders  TODO“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
TODO&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25770</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25770"/>
		<updated>2022-01-03T12:33:01Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[Three.js - Shader Snippets]]&lt;br /&gt;
&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
=== Bewegungsparameter ===&lt;br /&gt;
Wir nutzen ein weiteres &amp;#039;&amp;#039;&amp;#039;Uniform uTime&amp;#039;&amp;#039;&amp;#039; mit dem wir die elapsedTime übergeben. Diese können wir in der Funktion nutzen und erzeugen so eine Abhängigkeit von der Zeit -&amp;gt; wellenaertige Animation. für mehr Kontrolle erstellen wir noch ein uSpeed und ein uAmplitude. Für diese können wir noch ein gui Element erstellen und nutzen den Wert ebenfalls in unserer Formel. So können wir die Bewegung gut testen.&lt;br /&gt;
&lt;br /&gt;
=== Mesh skalieren ===&lt;br /&gt;
Damit das quadratische Mesh mehr nach Flagge ausschaut skalieren wir es außerdem noch. Das können wir direkt im Mesh machen ohne dass wir im Shader etwas tun müssen.&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1}&lt;br /&gt;
    }&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3 // auf 3:2 skalieren indem wir in y-Richtung verkleinern&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
//..&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
//...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  //...&lt;br /&gt;
  modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Texture und Color im eigenen Shader ===&lt;br /&gt;
&lt;br /&gt;
==== Farbe ====&lt;br /&gt;
Farben lassen sich sehr einfach an den Fragment Shader übermitteln.&lt;br /&gt;
Im Script fügen wir ein weiteres Uniform hinzu:&lt;br /&gt;
 uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)}&lt;br /&gt;
Da Three.js intern ein Vector3 Objekt können wir das direkt zum Shader schicken. Dort steht es dann als vec3 Objekt zur Verfügung:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Die Werte in vec3 Objekten kann man über x,y,z aber auch r,g,b auslesen. Das ist in diesem Fall naheliegender.&lt;br /&gt;
&lt;br /&gt;
==== Texture ====&lt;br /&gt;
Um eine &amp;#039;&amp;#039;&amp;#039;Textur im Fragment Shader&amp;#039;&amp;#039;&amp;#039; zu nutzen gibt es eine eigene Funktion: &amp;#039;&amp;#039;&amp;#039;texture2D&amp;#039;&amp;#039;&amp;#039;. Diese Funktion benötigt die &amp;#039;&amp;#039;&amp;#039;Textur&amp;#039;&amp;#039;&amp;#039; und zusätzlich die &amp;#039;&amp;#039;&amp;#039;uv Koordinaten&amp;#039;&amp;#039;&amp;#039; als Anweisung wie die Textur aufgebracht werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Textur laden&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Mit dem &amp;#039;&amp;#039;&amp;#039;TextureLoader -&amp;gt; Textur&amp;#039;&amp;#039;&amp;#039; laden. Und &amp;#039;&amp;#039;&amp;#039;neues Uniform&amp;#039;&amp;#039;&amp;#039; erstellen mit dem wir die &amp;#039;&amp;#039;&amp;#039;Textur senden&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
Im FragmentShader die Textur als &amp;#039;&amp;#039;&amp;#039;2DSampler&amp;#039;&amp;#039;&amp;#039; empfangen&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2 UV-Koordinaten senden&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Die uv-Koordinaten finden wir in der Geometrie. In unserem &amp;#039;&amp;#039;&amp;#039;Plane&amp;#039;&amp;#039;&amp;#039; hat Three.js das &amp;#039;&amp;#039;&amp;#039;uv Property&amp;#039;&amp;#039;&amp;#039; erstellt. Dieses holen wir uns direkt im Vertex Shader ab und senden es an den Fragment Shader. Dafür erstellen wir ein Varying vUv und füllen es in main mit den jeweils anfallenden Werten.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        //...&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
}) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
attribute vec2 uv; // get uv property from plane&lt;br /&gt;
varying vec2 vUv; // create new varying to store uv values&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vUv = uv; // fill vUv with uv values&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
    &lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv);&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Schatten simulieren&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Wir können die Höhe der Vertices nutzen umd Schatten zu simulieren. Das reicht für viele Zwecke aus. Dazu übergeben wir die Höhe vom vertex and den fragment shader und nutzen diesen Wert um tiefe Stellen abzudunkeln:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
// ...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
// ... in main loop ...&lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Fragment Shader&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
// in main loop ...&lt;br /&gt;
  vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
  fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
import &amp;#039;./style.css&amp;#039;&lt;br /&gt;
import * as THREE from &amp;#039;three&amp;#039;&lt;br /&gt;
import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
import * as dat from &amp;#039;lil-gui&amp;#039;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Base&lt;br /&gt;
 */&lt;br /&gt;
// Debug&lt;br /&gt;
const gui = new dat.GUI()&lt;br /&gt;
&lt;br /&gt;
// Canvas&lt;br /&gt;
const canvas = document.querySelector(&amp;#039;canvas.webgl&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Scene&lt;br /&gt;
const scene = new THREE.Scene()&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Test mesh&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
&lt;br /&gt;
const count = geometry.attributes.position.count&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1},&lt;br /&gt;
        uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)},&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Helpers&lt;br /&gt;
 */&lt;br /&gt;
const axesHelper = new THREE.AxesHelper()&lt;br /&gt;
scene.add(axesHelper)&lt;br /&gt;
/**&lt;br /&gt;
 * Sizes&lt;br /&gt;
 */&lt;br /&gt;
const sizes = {&lt;br /&gt;
    width: window.innerWidth,&lt;br /&gt;
    height: window.innerHeight&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Update sizes&lt;br /&gt;
    sizes.width = window.innerWidth&lt;br /&gt;
    sizes.height = window.innerHeight&lt;br /&gt;
&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.aspect = sizes.width / sizes.height&lt;br /&gt;
    camera.updateProjectionMatrix()&lt;br /&gt;
&lt;br /&gt;
    // Update renderer&lt;br /&gt;
    renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Camera&lt;br /&gt;
 */&lt;br /&gt;
// Base camera&lt;br /&gt;
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)&lt;br /&gt;
camera.position.set(0.25, - 0.25, 1)&lt;br /&gt;
scene.add(camera)&lt;br /&gt;
&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform mat4 projectionMatrix;&lt;br /&gt;
uniform mat4 viewMatrix;&lt;br /&gt;
uniform mat4 modelMatrix;&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
attribute vec3 position; &lt;br /&gt;
attribute float aRandom; // our own attribute set in geometry&lt;br /&gt;
attribute vec2 uv;&lt;br /&gt;
&lt;br /&gt;
varying float vRandom; // our varying to send to fragment shader&lt;br /&gt;
varying vec2 vUv; // stores uv coordinates to send to fragment shader&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  vRandom = aRandom;&lt;br /&gt;
  vUv = uv;&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  &lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
  //modelPosition.z += 0.05*sin(floor(10.0 * modelPosition.x)*4321.0); // cornered sin &lt;br /&gt;
  modelPosition.z += aRandom * 0.01; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying float vRandom;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
        varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            //gl_FragColor = vec4(0.5, 0.0, 1.0, 1.0); // purple&lt;br /&gt;
            //gl_FragColor = vec4(0.3, vRandom, 1.0, 1.0); // blue based on random varying&lt;br /&gt;
            //gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0); // color from color object&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
            fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ShaderMaterial statt RawShaderMaterial ===&lt;br /&gt;
Das ShaderMaterial übermittelt automatisch einige Parameter. Daher kann man folgende in den Shadern weglassen, diese stehen automatisch zur Verfügung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    uniform mat4 projectionMatrix;&lt;br /&gt;
    uniform mat4 viewMatrix;&lt;br /&gt;
    uniform mat4 modelMatrix;&lt;br /&gt;
    attribute vec3 position;&lt;br /&gt;
    attribute vec2 uv;&lt;br /&gt;
    precision mediump float;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Es werden noch einige weitere übergeben die wir bisher aber nicht benutzt haben.&lt;br /&gt;
=== Shader Debugging ===&lt;br /&gt;
Ist nicht so einfach. Man kann z.B. Werte direkt als Farbwerte nutzen, dann bekommt man einen visuelle Repräsentation der Werte und kann eher Einschätzen was passiert.&lt;br /&gt;
 gl_FragColor = vec4(vUv, 1.0, 1.0);&lt;br /&gt;
Ansonsten bei Fehlern in der Konsole schauen was passiert.&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25769</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25769"/>
		<updated>2022-01-03T12:32:31Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 Three.js - Shader Snippets&lt;br /&gt;
&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
=== Bewegungsparameter ===&lt;br /&gt;
Wir nutzen ein weiteres &amp;#039;&amp;#039;&amp;#039;Uniform uTime&amp;#039;&amp;#039;&amp;#039; mit dem wir die elapsedTime übergeben. Diese können wir in der Funktion nutzen und erzeugen so eine Abhängigkeit von der Zeit -&amp;gt; wellenaertige Animation. für mehr Kontrolle erstellen wir noch ein uSpeed und ein uAmplitude. Für diese können wir noch ein gui Element erstellen und nutzen den Wert ebenfalls in unserer Formel. So können wir die Bewegung gut testen.&lt;br /&gt;
&lt;br /&gt;
=== Mesh skalieren ===&lt;br /&gt;
Damit das quadratische Mesh mehr nach Flagge ausschaut skalieren wir es außerdem noch. Das können wir direkt im Mesh machen ohne dass wir im Shader etwas tun müssen.&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1}&lt;br /&gt;
    }&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3 // auf 3:2 skalieren indem wir in y-Richtung verkleinern&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
//..&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
//...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  //...&lt;br /&gt;
  modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Texture und Color im eigenen Shader ===&lt;br /&gt;
&lt;br /&gt;
==== Farbe ====&lt;br /&gt;
Farben lassen sich sehr einfach an den Fragment Shader übermitteln.&lt;br /&gt;
Im Script fügen wir ein weiteres Uniform hinzu:&lt;br /&gt;
 uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)}&lt;br /&gt;
Da Three.js intern ein Vector3 Objekt können wir das direkt zum Shader schicken. Dort steht es dann als vec3 Objekt zur Verfügung:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Die Werte in vec3 Objekten kann man über x,y,z aber auch r,g,b auslesen. Das ist in diesem Fall naheliegender.&lt;br /&gt;
&lt;br /&gt;
==== Texture ====&lt;br /&gt;
Um eine &amp;#039;&amp;#039;&amp;#039;Textur im Fragment Shader&amp;#039;&amp;#039;&amp;#039; zu nutzen gibt es eine eigene Funktion: &amp;#039;&amp;#039;&amp;#039;texture2D&amp;#039;&amp;#039;&amp;#039;. Diese Funktion benötigt die &amp;#039;&amp;#039;&amp;#039;Textur&amp;#039;&amp;#039;&amp;#039; und zusätzlich die &amp;#039;&amp;#039;&amp;#039;uv Koordinaten&amp;#039;&amp;#039;&amp;#039; als Anweisung wie die Textur aufgebracht werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Textur laden&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Mit dem &amp;#039;&amp;#039;&amp;#039;TextureLoader -&amp;gt; Textur&amp;#039;&amp;#039;&amp;#039; laden. Und &amp;#039;&amp;#039;&amp;#039;neues Uniform&amp;#039;&amp;#039;&amp;#039; erstellen mit dem wir die &amp;#039;&amp;#039;&amp;#039;Textur senden&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
Im FragmentShader die Textur als &amp;#039;&amp;#039;&amp;#039;2DSampler&amp;#039;&amp;#039;&amp;#039; empfangen&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2 UV-Koordinaten senden&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Die uv-Koordinaten finden wir in der Geometrie. In unserem &amp;#039;&amp;#039;&amp;#039;Plane&amp;#039;&amp;#039;&amp;#039; hat Three.js das &amp;#039;&amp;#039;&amp;#039;uv Property&amp;#039;&amp;#039;&amp;#039; erstellt. Dieses holen wir uns direkt im Vertex Shader ab und senden es an den Fragment Shader. Dafür erstellen wir ein Varying vUv und füllen es in main mit den jeweils anfallenden Werten.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        //...&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
}) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
attribute vec2 uv; // get uv property from plane&lt;br /&gt;
varying vec2 vUv; // create new varying to store uv values&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vUv = uv; // fill vUv with uv values&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
    &lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv);&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Schatten simulieren&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Wir können die Höhe der Vertices nutzen umd Schatten zu simulieren. Das reicht für viele Zwecke aus. Dazu übergeben wir die Höhe vom vertex and den fragment shader und nutzen diesen Wert um tiefe Stellen abzudunkeln:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
// ...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
// ... in main loop ...&lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Fragment Shader&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
// in main loop ...&lt;br /&gt;
  vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
  fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
import &amp;#039;./style.css&amp;#039;&lt;br /&gt;
import * as THREE from &amp;#039;three&amp;#039;&lt;br /&gt;
import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
import * as dat from &amp;#039;lil-gui&amp;#039;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Base&lt;br /&gt;
 */&lt;br /&gt;
// Debug&lt;br /&gt;
const gui = new dat.GUI()&lt;br /&gt;
&lt;br /&gt;
// Canvas&lt;br /&gt;
const canvas = document.querySelector(&amp;#039;canvas.webgl&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Scene&lt;br /&gt;
const scene = new THREE.Scene()&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Test mesh&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
&lt;br /&gt;
const count = geometry.attributes.position.count&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1},&lt;br /&gt;
        uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)},&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Helpers&lt;br /&gt;
 */&lt;br /&gt;
const axesHelper = new THREE.AxesHelper()&lt;br /&gt;
scene.add(axesHelper)&lt;br /&gt;
/**&lt;br /&gt;
 * Sizes&lt;br /&gt;
 */&lt;br /&gt;
const sizes = {&lt;br /&gt;
    width: window.innerWidth,&lt;br /&gt;
    height: window.innerHeight&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Update sizes&lt;br /&gt;
    sizes.width = window.innerWidth&lt;br /&gt;
    sizes.height = window.innerHeight&lt;br /&gt;
&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.aspect = sizes.width / sizes.height&lt;br /&gt;
    camera.updateProjectionMatrix()&lt;br /&gt;
&lt;br /&gt;
    // Update renderer&lt;br /&gt;
    renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Camera&lt;br /&gt;
 */&lt;br /&gt;
// Base camera&lt;br /&gt;
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)&lt;br /&gt;
camera.position.set(0.25, - 0.25, 1)&lt;br /&gt;
scene.add(camera)&lt;br /&gt;
&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform mat4 projectionMatrix;&lt;br /&gt;
uniform mat4 viewMatrix;&lt;br /&gt;
uniform mat4 modelMatrix;&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
attribute vec3 position; &lt;br /&gt;
attribute float aRandom; // our own attribute set in geometry&lt;br /&gt;
attribute vec2 uv;&lt;br /&gt;
&lt;br /&gt;
varying float vRandom; // our varying to send to fragment shader&lt;br /&gt;
varying vec2 vUv; // stores uv coordinates to send to fragment shader&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  vRandom = aRandom;&lt;br /&gt;
  vUv = uv;&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  &lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
  //modelPosition.z += 0.05*sin(floor(10.0 * modelPosition.x)*4321.0); // cornered sin &lt;br /&gt;
  modelPosition.z += aRandom * 0.01; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying float vRandom;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
        varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            //gl_FragColor = vec4(0.5, 0.0, 1.0, 1.0); // purple&lt;br /&gt;
            //gl_FragColor = vec4(0.3, vRandom, 1.0, 1.0); // blue based on random varying&lt;br /&gt;
            //gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0); // color from color object&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
            fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ShaderMaterial statt RawShaderMaterial ===&lt;br /&gt;
Das ShaderMaterial übermittelt automatisch einige Parameter. Daher kann man folgende in den Shadern weglassen, diese stehen automatisch zur Verfügung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    uniform mat4 projectionMatrix;&lt;br /&gt;
    uniform mat4 viewMatrix;&lt;br /&gt;
    uniform mat4 modelMatrix;&lt;br /&gt;
    attribute vec3 position;&lt;br /&gt;
    attribute vec2 uv;&lt;br /&gt;
    precision mediump float;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Es werden noch einige weitere übergeben die wir bisher aber nicht benutzt haben.&lt;br /&gt;
=== Shader Debugging ===&lt;br /&gt;
Ist nicht so einfach. Man kann z.B. Werte direkt als Farbwerte nutzen, dann bekommt man einen visuelle Repräsentation der Werte und kann eher Einschätzen was passiert.&lt;br /&gt;
 gl_FragColor = vec4(vUv, 1.0, 1.0);&lt;br /&gt;
Ansonsten bei Fehlern in der Konsole schauen was passiert.&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25768</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25768"/>
		<updated>2022-01-03T12:32:02Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Komplettes Beispiel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
=== Bewegungsparameter ===&lt;br /&gt;
Wir nutzen ein weiteres &amp;#039;&amp;#039;&amp;#039;Uniform uTime&amp;#039;&amp;#039;&amp;#039; mit dem wir die elapsedTime übergeben. Diese können wir in der Funktion nutzen und erzeugen so eine Abhängigkeit von der Zeit -&amp;gt; wellenaertige Animation. für mehr Kontrolle erstellen wir noch ein uSpeed und ein uAmplitude. Für diese können wir noch ein gui Element erstellen und nutzen den Wert ebenfalls in unserer Formel. So können wir die Bewegung gut testen.&lt;br /&gt;
&lt;br /&gt;
=== Mesh skalieren ===&lt;br /&gt;
Damit das quadratische Mesh mehr nach Flagge ausschaut skalieren wir es außerdem noch. Das können wir direkt im Mesh machen ohne dass wir im Shader etwas tun müssen.&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1}&lt;br /&gt;
    }&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3 // auf 3:2 skalieren indem wir in y-Richtung verkleinern&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
//..&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
//...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  //...&lt;br /&gt;
  modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Texture und Color im eigenen Shader ===&lt;br /&gt;
&lt;br /&gt;
==== Farbe ====&lt;br /&gt;
Farben lassen sich sehr einfach an den Fragment Shader übermitteln.&lt;br /&gt;
Im Script fügen wir ein weiteres Uniform hinzu:&lt;br /&gt;
 uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)}&lt;br /&gt;
Da Three.js intern ein Vector3 Objekt können wir das direkt zum Shader schicken. Dort steht es dann als vec3 Objekt zur Verfügung:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Die Werte in vec3 Objekten kann man über x,y,z aber auch r,g,b auslesen. Das ist in diesem Fall naheliegender.&lt;br /&gt;
&lt;br /&gt;
==== Texture ====&lt;br /&gt;
Um eine &amp;#039;&amp;#039;&amp;#039;Textur im Fragment Shader&amp;#039;&amp;#039;&amp;#039; zu nutzen gibt es eine eigene Funktion: &amp;#039;&amp;#039;&amp;#039;texture2D&amp;#039;&amp;#039;&amp;#039;. Diese Funktion benötigt die &amp;#039;&amp;#039;&amp;#039;Textur&amp;#039;&amp;#039;&amp;#039; und zusätzlich die &amp;#039;&amp;#039;&amp;#039;uv Koordinaten&amp;#039;&amp;#039;&amp;#039; als Anweisung wie die Textur aufgebracht werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Textur laden&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Mit dem &amp;#039;&amp;#039;&amp;#039;TextureLoader -&amp;gt; Textur&amp;#039;&amp;#039;&amp;#039; laden. Und &amp;#039;&amp;#039;&amp;#039;neues Uniform&amp;#039;&amp;#039;&amp;#039; erstellen mit dem wir die &amp;#039;&amp;#039;&amp;#039;Textur senden&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
Im FragmentShader die Textur als &amp;#039;&amp;#039;&amp;#039;2DSampler&amp;#039;&amp;#039;&amp;#039; empfangen&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2 UV-Koordinaten senden&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Die uv-Koordinaten finden wir in der Geometrie. In unserem &amp;#039;&amp;#039;&amp;#039;Plane&amp;#039;&amp;#039;&amp;#039; hat Three.js das &amp;#039;&amp;#039;&amp;#039;uv Property&amp;#039;&amp;#039;&amp;#039; erstellt. Dieses holen wir uns direkt im Vertex Shader ab und senden es an den Fragment Shader. Dafür erstellen wir ein Varying vUv und füllen es in main mit den jeweils anfallenden Werten.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        //...&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
}) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
attribute vec2 uv; // get uv property from plane&lt;br /&gt;
varying vec2 vUv; // create new varying to store uv values&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vUv = uv; // fill vUv with uv values&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
    &lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv);&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Schatten simulieren&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Wir können die Höhe der Vertices nutzen umd Schatten zu simulieren. Das reicht für viele Zwecke aus. Dazu übergeben wir die Höhe vom vertex and den fragment shader und nutzen diesen Wert um tiefe Stellen abzudunkeln:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
// ...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
// ... in main loop ...&lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Fragment Shader&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
// in main loop ...&lt;br /&gt;
  vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
  fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
import &amp;#039;./style.css&amp;#039;&lt;br /&gt;
import * as THREE from &amp;#039;three&amp;#039;&lt;br /&gt;
import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
import * as dat from &amp;#039;lil-gui&amp;#039;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Base&lt;br /&gt;
 */&lt;br /&gt;
// Debug&lt;br /&gt;
const gui = new dat.GUI()&lt;br /&gt;
&lt;br /&gt;
// Canvas&lt;br /&gt;
const canvas = document.querySelector(&amp;#039;canvas.webgl&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Scene&lt;br /&gt;
const scene = new THREE.Scene()&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Test mesh&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
&lt;br /&gt;
const count = geometry.attributes.position.count&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1},&lt;br /&gt;
        uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)},&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Helpers&lt;br /&gt;
 */&lt;br /&gt;
const axesHelper = new THREE.AxesHelper()&lt;br /&gt;
scene.add(axesHelper)&lt;br /&gt;
/**&lt;br /&gt;
 * Sizes&lt;br /&gt;
 */&lt;br /&gt;
const sizes = {&lt;br /&gt;
    width: window.innerWidth,&lt;br /&gt;
    height: window.innerHeight&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Update sizes&lt;br /&gt;
    sizes.width = window.innerWidth&lt;br /&gt;
    sizes.height = window.innerHeight&lt;br /&gt;
&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.aspect = sizes.width / sizes.height&lt;br /&gt;
    camera.updateProjectionMatrix()&lt;br /&gt;
&lt;br /&gt;
    // Update renderer&lt;br /&gt;
    renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Camera&lt;br /&gt;
 */&lt;br /&gt;
// Base camera&lt;br /&gt;
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)&lt;br /&gt;
camera.position.set(0.25, - 0.25, 1)&lt;br /&gt;
scene.add(camera)&lt;br /&gt;
&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform mat4 projectionMatrix;&lt;br /&gt;
uniform mat4 viewMatrix;&lt;br /&gt;
uniform mat4 modelMatrix;&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
attribute vec3 position; &lt;br /&gt;
attribute float aRandom; // our own attribute set in geometry&lt;br /&gt;
attribute vec2 uv;&lt;br /&gt;
&lt;br /&gt;
varying float vRandom; // our varying to send to fragment shader&lt;br /&gt;
varying vec2 vUv; // stores uv coordinates to send to fragment shader&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  vRandom = aRandom;&lt;br /&gt;
  vUv = uv;&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  &lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
  //modelPosition.z += 0.05*sin(floor(10.0 * modelPosition.x)*4321.0); // cornered sin &lt;br /&gt;
  modelPosition.z += aRandom * 0.01; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying float vRandom;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
        varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            //gl_FragColor = vec4(0.5, 0.0, 1.0, 1.0); // purple&lt;br /&gt;
            //gl_FragColor = vec4(0.3, vRandom, 1.0, 1.0); // blue based on random varying&lt;br /&gt;
            //gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0); // color from color object&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
            fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ShaderMaterial statt RawShaderMaterial ===&lt;br /&gt;
Das ShaderMaterial übermittelt automatisch einige Parameter. Daher kann man folgende in den Shadern weglassen, diese stehen automatisch zur Verfügung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    uniform mat4 projectionMatrix;&lt;br /&gt;
    uniform mat4 viewMatrix;&lt;br /&gt;
    uniform mat4 modelMatrix;&lt;br /&gt;
    attribute vec3 position;&lt;br /&gt;
    attribute vec2 uv;&lt;br /&gt;
    precision mediump float;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Es werden noch einige weitere übergeben die wir bisher aber nicht benutzt haben.&lt;br /&gt;
=== Shader Debugging ===&lt;br /&gt;
Ist nicht so einfach. Man kann z.B. Werte direkt als Farbwerte nutzen, dann bekommt man einen visuelle Repräsentation der Werte und kann eher Einschätzen was passiert.&lt;br /&gt;
 gl_FragColor = vec4(vUv, 1.0, 1.0);&lt;br /&gt;
Ansonsten bei Fehlern in der Konsole schauen was passiert.&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25767</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25767"/>
		<updated>2022-01-03T12:30:20Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Texture und Color im eigenen Shader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
=== Bewegungsparameter ===&lt;br /&gt;
Wir nutzen ein weiteres &amp;#039;&amp;#039;&amp;#039;Uniform uTime&amp;#039;&amp;#039;&amp;#039; mit dem wir die elapsedTime übergeben. Diese können wir in der Funktion nutzen und erzeugen so eine Abhängigkeit von der Zeit -&amp;gt; wellenaertige Animation. für mehr Kontrolle erstellen wir noch ein uSpeed und ein uAmplitude. Für diese können wir noch ein gui Element erstellen und nutzen den Wert ebenfalls in unserer Formel. So können wir die Bewegung gut testen.&lt;br /&gt;
&lt;br /&gt;
=== Mesh skalieren ===&lt;br /&gt;
Damit das quadratische Mesh mehr nach Flagge ausschaut skalieren wir es außerdem noch. Das können wir direkt im Mesh machen ohne dass wir im Shader etwas tun müssen.&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1}&lt;br /&gt;
    }&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3 // auf 3:2 skalieren indem wir in y-Richtung verkleinern&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
//..&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
//...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  //...&lt;br /&gt;
  modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Texture und Color im eigenen Shader ===&lt;br /&gt;
&lt;br /&gt;
==== Farbe ====&lt;br /&gt;
Farben lassen sich sehr einfach an den Fragment Shader übermitteln.&lt;br /&gt;
Im Script fügen wir ein weiteres Uniform hinzu:&lt;br /&gt;
 uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)}&lt;br /&gt;
Da Three.js intern ein Vector3 Objekt können wir das direkt zum Shader schicken. Dort steht es dann als vec3 Objekt zur Verfügung:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Die Werte in vec3 Objekten kann man über x,y,z aber auch r,g,b auslesen. Das ist in diesem Fall naheliegender.&lt;br /&gt;
&lt;br /&gt;
==== Texture ====&lt;br /&gt;
Um eine &amp;#039;&amp;#039;&amp;#039;Textur im Fragment Shader&amp;#039;&amp;#039;&amp;#039; zu nutzen gibt es eine eigene Funktion: &amp;#039;&amp;#039;&amp;#039;texture2D&amp;#039;&amp;#039;&amp;#039;. Diese Funktion benötigt die &amp;#039;&amp;#039;&amp;#039;Textur&amp;#039;&amp;#039;&amp;#039; und zusätzlich die &amp;#039;&amp;#039;&amp;#039;uv Koordinaten&amp;#039;&amp;#039;&amp;#039; als Anweisung wie die Textur aufgebracht werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;1. Textur laden&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Mit dem &amp;#039;&amp;#039;&amp;#039;TextureLoader -&amp;gt; Textur&amp;#039;&amp;#039;&amp;#039; laden. Und &amp;#039;&amp;#039;&amp;#039;neues Uniform&amp;#039;&amp;#039;&amp;#039; erstellen mit dem wir die &amp;#039;&amp;#039;&amp;#039;Textur senden&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
Im FragmentShader die Textur als &amp;#039;&amp;#039;&amp;#039;2DSampler&amp;#039;&amp;#039;&amp;#039; empfangen&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;2 UV-Koordinaten senden&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Die uv-Koordinaten finden wir in der Geometrie. In unserem &amp;#039;&amp;#039;&amp;#039;Plane&amp;#039;&amp;#039;&amp;#039; hat Three.js das &amp;#039;&amp;#039;&amp;#039;uv Property&amp;#039;&amp;#039;&amp;#039; erstellt. Dieses holen wir uns direkt im Vertex Shader ab und senden es an den Fragment Shader. Dafür erstellen wir ein Varying vUv und füllen es in main mit den jeweils anfallenden Werten.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const flagTexture = textureLoader.load(&amp;#039;/textures/flag-germany-sq.png&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        //...&lt;br /&gt;
        uTexture: {value: flagTexture}&lt;br /&gt;
    },&lt;br /&gt;
}) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
attribute vec2 uv; // get uv property from plane&lt;br /&gt;
varying vec2 vUv; // create new varying to store uv values&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vUv = uv; // fill vUv with uv values&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
    &lt;br /&gt;
        uniform sampler2D uTexture;&lt;br /&gt;
        varying vec2 vUv;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            vec4 fragTexture = texture2D(uTexture, vUv);&lt;br /&gt;
            gl_FragColor = fragTexture; &lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Schatten simulieren&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Wir können die Höhe der Vertices nutzen umd Schatten zu simulieren. Das reicht für viele Zwecke aus. Dazu übergeben wir die Höhe vom vertex and den fragment shader und nutzen diesen Wert um tiefe Stellen abzudunkeln:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float elevation = 0.0;&lt;br /&gt;
// ...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
&lt;br /&gt;
// ... in main loop ...&lt;br /&gt;
  elevation += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  elevation += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
  modelPosition.z += elevation;&lt;br /&gt;
  vElevation = elevation;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Fragment Shader&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
varying float vElevation;&lt;br /&gt;
// in main loop ...&lt;br /&gt;
  vec4 fragTexture = texture2D(uTexture, vUv); // add texture&lt;br /&gt;
  fragTexture.rgb *= vElevation * 2.0 + 0.5; // simulate shadow / since -0.5 to 0.5 add 0.5 / * 2 to spread values&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== ShaderMaterial statt RawShaderMaterial ===&lt;br /&gt;
Das ShaderMaterial übermittelt automatisch einige Parameter. Daher kann man folgende in den Shadern weglassen, diese stehen automatisch zur Verfügung.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    uniform mat4 projectionMatrix;&lt;br /&gt;
    uniform mat4 viewMatrix;&lt;br /&gt;
    uniform mat4 modelMatrix;&lt;br /&gt;
    attribute vec3 position;&lt;br /&gt;
    attribute vec2 uv;&lt;br /&gt;
    precision mediump float;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Es werden noch einige weitere übergeben die wir bisher aber nicht benutzt haben.&lt;br /&gt;
=== Shader Debugging ===&lt;br /&gt;
Ist nicht so einfach. Man kann z.B. Werte direkt als Farbwerte nutzen, dann bekommt man einen visuelle Repräsentation der Werte und kann eher Einschätzen was passiert.&lt;br /&gt;
 gl_FragColor = vec4(vUv, 1.0, 1.0);&lt;br /&gt;
Ansonsten bei Fehlern in der Konsole schauen was passiert.&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25766</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25766"/>
		<updated>2022-01-03T11:58:29Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Helpers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Nützliche Animation Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material (used for own Shader only)&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    // Update controls (used for orbit controls only)&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Orbit Controls ===&lt;br /&gt;
Don&amp;#039;t forget to update in tick function, when animating&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Controls&lt;br /&gt;
const controls = new OrbitControls(camera, canvas)&lt;br /&gt;
controls.enableDamping = true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25765</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25765"/>
		<updated>2022-01-03T11:54:10Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Nützliche Renderer Settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25764</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25764"/>
		<updated>2022-01-03T11:53:39Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Nützliche Renderer Settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas,&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25763</id>
		<title>ThreeJS - Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=ThreeJS_-_Snippets&amp;diff=25763"/>
		<updated>2022-01-03T11:51:30Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Helpers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 [[ThreeJS]]&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
 [[Three.js - Shaders]]&lt;br /&gt;
&lt;br /&gt;
== Helfer ==&lt;br /&gt;
=== Axes Helper ===&lt;br /&gt;
Koordinatenachsen anzeigen&lt;br /&gt;
 const axesHelper = new THREE.AxesHelper( 5 );&lt;br /&gt;
 scene.add( axesHelper );&lt;br /&gt;
&lt;br /&gt;
== Viewport Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Handle Viewport Resizing ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener(&amp;#039;resize&amp;#039;, () =&amp;gt;{&lt;br /&gt;
  console.log(&amp;#039;window resized&amp;#039;)&lt;br /&gt;
  // Update sizes&lt;br /&gt;
  sizes.width = window.innerWidth&lt;br /&gt;
  sizes.height = window.innerHeight&lt;br /&gt;
  // Update camera&lt;br /&gt;
  camera.aspect = sizes.width/sizes.height&lt;br /&gt;
  camera.updateProjectionMatrix()&lt;br /&gt;
  // Update renderer&lt;br /&gt;
  renderer.setSize(sizes.width,sizes.height)&lt;br /&gt;
  renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ) // in case monitor changed in double monitor settings&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Pixel Ratio Setting (Retina Displays) ===&lt;br /&gt;
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen &amp;quot;Software&amp;quot;Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal &amp;#039;&amp;#039;&amp;#039;schärfer&amp;#039;&amp;#039;&amp;#039; darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun. &lt;br /&gt;
&lt;br /&gt;
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber &amp;#039;&amp;#039;&amp;#039;nicht höher als 2&amp;#039;&amp;#039;&amp;#039; um die Performance zu erhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handle Fullscreen Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Handle Fullscreen &lt;br /&gt;
// including safari (needs webkit prefix)&lt;br /&gt;
window.addEventListener(&amp;#039;dblclick&amp;#039;, () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement&lt;br /&gt;
&lt;br /&gt;
    if(!fullscreenElement)&lt;br /&gt;
    {&lt;br /&gt;
        if(canvas.requestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.requestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(canvas.webkitRequestFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            canvas.webkitRequestFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if(document.exitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.exitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
        else if(document.webkitExitFullscreen)&lt;br /&gt;
        {&lt;br /&gt;
            document.webkitExitFullscreen()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Animation Basics ==&lt;br /&gt;
 [[Three.js - Animation]]&lt;br /&gt;
=== Timebased Tick / Loop Function ===&lt;br /&gt;
==== ThreeJS Clock Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
    //console.log(elapsedTime)&lt;br /&gt;
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s&lt;br /&gt;
    camera.lookAt(mesh.position)&lt;br /&gt;
    camera.position.z = Math.sin(elapsedTime) // back and forth&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GSAP Animation ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// GSAP has it&amp;#039;s own requestAnimationFrame, thus no time calculation needed&lt;br /&gt;
// we just let gsap update our values and tick does render each frame&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })&lt;br /&gt;
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    // Render on each frame&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
    window.requestAnimationFrame(tick) &lt;br /&gt;
}&lt;br /&gt;
// GO...&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nützliche Snippets für Animationen ==&lt;br /&gt;
&lt;br /&gt;
=== Kreisbewegung / Circular Movement ===&lt;br /&gt;
 myObject.position.y = Math.sin(elapsedTime) //(-1 -&amp;gt; 1 -&amp;gt; -1 -&amp;gt; ...)&lt;br /&gt;
 myObject.position.x = Math.cos(elapsedTime)&lt;br /&gt;
&lt;br /&gt;
=== Cursor auswerten ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Sizes&lt;br /&gt;
const sizes = { width: 800,  height: 600}&lt;br /&gt;
// Cursor&lt;br /&gt;
const cursor = {&lt;br /&gt;
    x: 0,&lt;br /&gt;
    y: 0&lt;br /&gt;
}&lt;br /&gt;
window.addEventListener(&amp;#039;mousemove&amp;#039;, (event) =&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
    //cursor.x = event.clientX / sizes.width // 0 &amp;lt;= x &amp;lt;= 1&lt;br /&gt;
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 &amp;lt;= x &amp;lt;= +0.5&lt;br /&gt;
    console.log(&amp;#039;x: &amp;#039; + cursor.x)&lt;br /&gt;
    console.log(&amp;#039;y: &amp;#039; + cursor.y)&lt;br /&gt;
})&lt;br /&gt;
// ...&lt;br /&gt;
// Update camera with position&lt;br /&gt;
    camera.position.x = cursor.x * 10&lt;br /&gt;
    camera.position.y = cursor.y * 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kamera auf einer Kreisbahn ===&lt;br /&gt;
Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine &amp;#039;&amp;#039;&amp;#039;Kreisbahn um den Mittelpunkt&amp;#039;&amp;#039;&amp;#039; auf der Ebene dieser beiden Achsen. Eine &amp;#039;&amp;#039;&amp;#039;volle Umdrehung&amp;#039;&amp;#039;&amp;#039; bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update camera&lt;br /&gt;
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3&lt;br /&gt;
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können&lt;br /&gt;
    camera.lookAt(mesh.position) // look at center&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.&lt;br /&gt;
&lt;br /&gt;
=== Bouncing Sphere + Shadow ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Orbit Controls ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls&lt;br /&gt;
ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML&lt;br /&gt;
 &amp;lt;script src=&amp;quot;/javascripts/OrbitControls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Oder z.B. in Webpack:&lt;br /&gt;
 import { OrbitControls } from &amp;#039;three/examples/jsm/controls/OrbitControls.js&amp;#039;&lt;br /&gt;
Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).&lt;br /&gt;
 const controls = new OrbitControls(camera,canvas)&lt;br /&gt;
&lt;br /&gt;
== Geometry Snippets ==&lt;br /&gt;
=== Create Geometry / Geometry Objekt erzeugen ===&lt;br /&gt;
Beispiel: viele zufällige Dreiecke erzeugen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Object&lt;br /&gt;
// const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)&lt;br /&gt;
const geometry = new THREE.BufferGeometry()&lt;br /&gt;
const count = 50&lt;br /&gt;
const positionsArray = new Float32Array(count * 3 * 3)&lt;br /&gt;
for (let i = 0; i &amp;lt; positionsArray.length; i++) {&lt;br /&gt;
    positionsArray[i] = Math.random() - 0.5 //-0.5 &amp;lt; x &amp;lt; 0.5&lt;br /&gt;
}&lt;br /&gt;
const positionsAttribute = new THREE.BufferAttribute(positionsArray,3) // use vals 3 by 3&lt;br /&gt;
geometry.setAttribute(&amp;#039;position&amp;#039;,positionsAttribute) // position is the attribute name in shaders&lt;br /&gt;
&lt;br /&gt;
// Example Array&lt;br /&gt;
// const positionsArray = new Float32Array([&lt;br /&gt;
//     0,0,0,&lt;br /&gt;
//     0,1,0,&lt;br /&gt;
//     1,0,0&lt;br /&gt;
// ])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
=== lil-gui ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// https://lil-gui.georgealways.com/#&lt;br /&gt;
import GUI from &amp;#039;lil-gui&amp;#039;; &lt;br /&gt;
/**&lt;br /&gt;
 * Debug&lt;br /&gt;
 */&lt;br /&gt;
const gui = new GUI({&lt;br /&gt;
    width:400&lt;br /&gt;
})&lt;br /&gt;
gui.close()&lt;br /&gt;
//...&lt;br /&gt;
// Debug&lt;br /&gt;
//gui.add(mesh.position,&amp;#039;y&amp;#039;,-2,2,0.1) // OR&lt;br /&gt;
gui.add(mesh.position,&amp;#039;y&amp;#039;)&lt;br /&gt;
  .min(-2)&lt;br /&gt;
  .max(3)&lt;br /&gt;
  .step(0.1)&lt;br /&gt;
  .name(&amp;#039;elevation&amp;#039;) // chain version&lt;br /&gt;
gui.add(mesh,&amp;#039;visible&amp;#039;)&lt;br /&gt;
gui.add(material,&amp;#039;wireframe&amp;#039;)&lt;br /&gt;
// we can not use material.color as it&amp;#039;s not an object&lt;br /&gt;
// thus we use a separately created object...&lt;br /&gt;
// ... and update material when this param changed:&lt;br /&gt;
gui.addColor(params,&amp;#039;color&amp;#039;)&lt;br /&gt;
.onChange( ()=&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    material.color.set(params.color)&lt;br /&gt;
})&lt;br /&gt;
gui.add(params, &amp;#039;spin&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
 https://threejs.org/docs/index.html?q=texture#api/en/constants/Textures&lt;br /&gt;
 [[three.js - Textures]] - ausführliche Infos zu TextureLoader Callbacks, LoadingManager...&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;/textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;/textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;/textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;/textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;/textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;/textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;/textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// HOW TO REPEAT TILES - uv wrapping&lt;br /&gt;
const repeat = 10;&lt;br /&gt;
&lt;br /&gt;
const grassColorTexture = textureLoader.load(&amp;#039;/textures/grass/color.jpg&amp;#039;)&lt;br /&gt;
const grassNormalTexture = textureLoader.load(&amp;#039;/textures/grass/normal.jpg&amp;#039;)&lt;br /&gt;
const grassRoughnessTexture = textureLoader.load(&amp;#039;/textures/grass/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassNormalTexture.repeat.set(repeat,repeat)&lt;br /&gt;
grassRoughnessTexture.repeat.set(repeat,repeat)&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapS = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
grassColorTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassNormalTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
grassRoughnessTexture.wrapT = THREE.RepeatWrapping&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/** &lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// Door&lt;br /&gt;
const door = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(2,2,100,100),// HEIGHTMAP NEEDS SOME SUBDIVISIONS&lt;br /&gt;
    new THREE.MeshStandardMaterial({&lt;br /&gt;
        map: doorColorTexture,&lt;br /&gt;
        transparent: true, // NEEDED FOR ALPHA TO WORK&lt;br /&gt;
        alphaMap: doorAlphaTexture,&lt;br /&gt;
        aoMap: doorAmbientOcclusionTexture,&lt;br /&gt;
        displacementMap: doorHeightTexture,&lt;br /&gt;
        displacementScale: 0.05,&lt;br /&gt;
        normalMap: doorNormalTexture,&lt;br /&gt;
        metalnessMap: doorMetalnessTexture,&lt;br /&gt;
        roughnessMap: doorRoughnessTexture,&lt;br /&gt;
        //wireframe: true&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// AOMAP NEEDS HIS OWN UV ATTRIBUTE (here we copy from geometry)&lt;br /&gt;
door.geometry.setAttribute(&amp;#039;uv2&amp;#039;, new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2))&lt;br /&gt;
&lt;br /&gt;
house.add(door)&lt;br /&gt;
&lt;br /&gt;
// Floor&lt;br /&gt;
const floor = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(20, 20),&lt;br /&gt;
    new THREE.MeshStandardMaterial({ &lt;br /&gt;
        //color: &amp;#039;#a9c388&amp;#039;,&lt;br /&gt;
        map: grassColorTexture,&lt;br /&gt;
        normalMap: grassNormalTexture,&lt;br /&gt;
        roughnessMap: grassRoughnessTexture    &lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
floor.rotation.x = - Math.PI * 0.5&lt;br /&gt;
floor.position.y = 0&lt;br /&gt;
&lt;br /&gt;
scene.add(floor)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Materials ==&lt;br /&gt;
 [[three.js - materials]] - Mehr Info und weitere Materialien.&lt;br /&gt;
&lt;br /&gt;
=== MeshBasicMaterial ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.MeshBasicMaterial()&lt;br /&gt;
material.color.set(0xaabb00)&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.wireframe = true&lt;br /&gt;
material.transparent = true&lt;br /&gt;
material.opacity = 0.5&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshMatcapMaterial ===&lt;br /&gt;
 https://github.com/nidorx/matcaps - gute Quelle&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// MATCAP - simulate lights / good for modelling&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const matcapTexture = textureLoader.load(&amp;#039;textures/matcaps/1.jpg&amp;#039;)&lt;br /&gt;
const material = new THREE.MeshMatcapMaterial()&lt;br /&gt;
material.matcap = matcapTexture&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MeshStandardMaterial ===&lt;br /&gt;
Standard Physical Based Rendering Material&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// TEXTURES&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const doorColorTexture = textureLoader.load(&amp;#039;textures/door/color.jpg&amp;#039;)&lt;br /&gt;
const doorAlphaTexture = textureLoader.load(&amp;#039;textures/door/alpha.jpg&amp;#039;)&lt;br /&gt;
const doorAmbientOcclusionTexture = textureLoader.load(&amp;#039;textures/door/ambientOcclusion.jpg&amp;#039;)&lt;br /&gt;
const doorHeightTexture = textureLoader.load(&amp;#039;textures/door/height.jpg&amp;#039;)&lt;br /&gt;
const doorMetalnessTexture = textureLoader.load(&amp;#039;textures/door/metalness.jpg&amp;#039;)&lt;br /&gt;
const doorNormalTexture = textureLoader.load(&amp;#039;textures/door/normal.jpg&amp;#039;)&lt;br /&gt;
const doorRoughnessTexture = textureLoader.load(&amp;#039;textures/door/roughness.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// STANDARD MATERIAL&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.side = DoubleSide&lt;br /&gt;
material.map = doorColorTexture&lt;br /&gt;
&lt;br /&gt;
material.roughness = 1 // default&lt;br /&gt;
material.roughnessMap = doorRoughnessTexture&lt;br /&gt;
&lt;br /&gt;
material.metalness = 0 // default&lt;br /&gt;
material.metalnessMap = doorMetalnessTexture&lt;br /&gt;
&lt;br /&gt;
material.aoMap = doorAmbientOcclusionTexture&lt;br /&gt;
material.aoMapIntensity = 1.1&lt;br /&gt;
&lt;br /&gt;
material.displacementMap = doorHeightTexture&lt;br /&gt;
material.displacementScale = 0.03&lt;br /&gt;
&lt;br /&gt;
material.normalMap = doorNormalTexture&lt;br /&gt;
material.normalScale.set(0.5,0.5)&lt;br /&gt;
&lt;br /&gt;
material.transparent = true // needed for alpha to work&lt;br /&gt;
material.alphaMap = doorAlphaTexture&lt;br /&gt;
&lt;br /&gt;
// OBJECTS&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1,1,100,100), // subdivisions needed for height map&lt;br /&gt;
    material&lt;br /&gt;
)&lt;br /&gt;
// copy uv coordinates to uv2 attribute needed by aomap&lt;br /&gt;
plane.geometry.setAttribute(&lt;br /&gt;
    &amp;#039;uv2&amp;#039;, &lt;br /&gt;
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array,2)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Environment Map ===&lt;br /&gt;
 [[Three.js - Environment Map (Panorama)]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// ENVIRONMENTAL MAP&lt;br /&gt;
const cubeTextureLoader = new THREE.CubeTextureLoader()&lt;br /&gt;
// load cube-images in the right order...&lt;br /&gt;
const environmentMapTexture = cubeTextureLoader.load([&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/px.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nx.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/py.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/ny.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/pz.png&amp;#039;,&lt;br /&gt;
    &amp;#039;/textures/environmentMaps/4/nz.png&amp;#039;,&lt;br /&gt;
])&lt;br /&gt;
const material = new THREE.MeshStandardMaterial()&lt;br /&gt;
material.envMap = environmentMapTexture&lt;br /&gt;
material.metalness = 0.7&lt;br /&gt;
material.roughness = 0.2&lt;br /&gt;
&lt;br /&gt;
gui.add(material, &amp;#039;metalness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
gui.add(material, &amp;#039;roughness&amp;#039;).min(0).max(1).step(0.0001)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hinweise ===&lt;br /&gt;
Eigenschaften kann man als Konstruktor Objekt übergeben oder direkt setzen oder über set (manchmal praktischer, wenn als Eigenschaftswert ein Objekt erwartet wird (z.B. bei der Farbe ein Farbobjekt)&lt;br /&gt;
&lt;br /&gt;
== 3D Text ==&lt;br /&gt;
 [[Three.js - 3D Text]]&lt;br /&gt;
 http://gero3.github.io/facetype.js/ - Konvertieren von Fonts nach Facetype&lt;br /&gt;
=== Fontloader ===&lt;br /&gt;
Hinweis: Seit three.js 133 muss der Fontloader und die Fontgeometry importiert werden.&lt;br /&gt;
 https://threejs.org/docs/index.html?q=fontloa#examples/en/loaders/FontLoader&lt;br /&gt;
====Basic Example====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import { FontLoader } from &amp;#039;three/examples/jsm/loaders/FontLoader.js&amp;#039;&lt;br /&gt;
import { TextGeometry } from &amp;#039;three/examples/jsm/geometries/TextGeometry.js&amp;#039;//i.e. with webpack&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Fonts&lt;br /&gt;
 */&lt;br /&gt;
const fontLoader = new FontLoader()&lt;br /&gt;
&lt;br /&gt;
fontLoader.load(&lt;br /&gt;
    //&amp;#039;/fonts/helvetiker_regular.typeface.json&amp;#039;,&lt;br /&gt;
    &amp;#039;/fonts/BebasNeueBook_Regular.json&amp;#039;,&lt;br /&gt;
    (font) =&amp;gt;&lt;br /&gt;
    {&lt;br /&gt;
        console.log(&amp;#039;font loaded&amp;#039;)&lt;br /&gt;
        const textGeometry = new TextGeometry(&lt;br /&gt;
            &amp;#039;KHOLJA&amp;#039;,&lt;br /&gt;
            {&lt;br /&gt;
                font: font,&lt;br /&gt;
                size: 0.5,&lt;br /&gt;
                height: 0.2, // more like extrusion depth&lt;br /&gt;
                curveSegments: 8,&lt;br /&gt;
                bevelEnabled: true,&lt;br /&gt;
                bevelThickness: 0.03,&lt;br /&gt;
                bevelSize: 0.01,&lt;br /&gt;
                bevelOffset: 0,&lt;br /&gt;
                bevelSegments: 4&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
        textGeometry.center() // easy method to center the text&lt;br /&gt;
        const textMaterial = new THREE.MeshBasicMaterial()&lt;br /&gt;
        textMaterial.wireframe = true&lt;br /&gt;
        const text = new THREE.Mesh(textGeometry,textMaterial)&lt;br /&gt;
        scene.add(text)&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lights ==&lt;br /&gt;
 [[Three.js - Lights]]&lt;br /&gt;
=== Light Starters ===&lt;br /&gt;
==== Neutral Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(&amp;#039;#ffffff&amp;#039;, 0.5)&lt;br /&gt;
directionalLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Moonlight Starter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const moonLight = new THREE.DirectionalLight(&amp;#039;#b9d5ff&amp;#039;, 0.5)&lt;br /&gt;
moonLight.position.set(4, 5, - 2)&lt;br /&gt;
gui.add(moonLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(moonLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
scene.add(moonLight)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Shadows / Schatten ==&lt;br /&gt;
[[Three.js - Shadows]] - Ausführliche Infos zu Schatten&lt;br /&gt;
&lt;br /&gt;
=== Komplettes Beispiel ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/**&lt;br /&gt;
 * Lights&lt;br /&gt;
 */&lt;br /&gt;
// Ambient light&lt;br /&gt;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)&lt;br /&gt;
gui.add(ambientLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
scene.add(ambientLight)&lt;br /&gt;
&lt;br /&gt;
// Directional light&lt;br /&gt;
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)&lt;br /&gt;
directionalLight.position.set(2, 2, - 1)&lt;br /&gt;
gui.add(directionalLight, &amp;#039;intensity&amp;#039;).min(0).max(1).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;x&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;y&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
gui.add(directionalLight.position, &amp;#039;z&amp;#039;).min(- 5).max(5).step(0.001)&lt;br /&gt;
&lt;br /&gt;
// Add Shadow and mapsize&lt;br /&gt;
directionalLight.castShadow = true&lt;br /&gt;
directionalLight.shadow.mapSize.x = 1024&lt;br /&gt;
directionalLight.shadow.mapSize.y = 1024&lt;br /&gt;
// Shadow camera settings...&lt;br /&gt;
directionalLight.shadow.camera.near = 1&lt;br /&gt;
directionalLight.shadow.camera.far = 6&lt;br /&gt;
// ...important for quality&lt;br /&gt;
directionalLight.shadow.camera.left = -2&lt;br /&gt;
directionalLight.shadow.camera.right = 2&lt;br /&gt;
directionalLight.shadow.camera.top = 2&lt;br /&gt;
directionalLight.shadow.camera.bottom = -2&lt;br /&gt;
// adding a bit of a cheap blur&lt;br /&gt;
// directionalLight.shadow.radius = 4&lt;br /&gt;
&lt;br /&gt;
scene.add(directionalLight)&lt;br /&gt;
&lt;br /&gt;
// Shadow camera helper&lt;br /&gt;
const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)&lt;br /&gt;
scene.add(directionalLightCameraHelper)&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Objects&lt;br /&gt;
 */&lt;br /&gt;
sphere.castShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
plane.receiveShadow = true&lt;br /&gt;
// ...&lt;br /&gt;
scene.add(sphere, plane)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderer&lt;br /&gt;
 */&lt;br /&gt;
const renderer = new THREE.WebGLRenderer({&lt;br /&gt;
    canvas: canvas&lt;br /&gt;
})&lt;br /&gt;
renderer.setSize(sizes.width, sizes.height)&lt;br /&gt;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))&lt;br /&gt;
&lt;br /&gt;
// Renderer Shadowmap settings&lt;br /&gt;
renderer.shadowMap.enabled = true &lt;br /&gt;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Shadow Baking ====&lt;br /&gt;
Wie Texturen kann man auch Schatten baken. Nachteil. Bei Bewegung des Objekts bewegt sich der&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Textures&lt;br /&gt;
 */&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const bakedShadow = textureLoader.load(&amp;#039;/textures/bakedShadow.jpg&amp;#039;)&lt;br /&gt;
//...&lt;br /&gt;
const plane = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(5, 5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        map: bakedShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
// we don&amp;#039;t need the rendered shadows in this case&lt;br /&gt;
renderer.shadowMap.enabled = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Dynamic Shadow Baking ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Beispiel Kugel mit animiertem Fake-Schatten&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const textureLoader = new THREE.TextureLoader()&lt;br /&gt;
const simpleShadow = textureLoader.load(&amp;#039;/textures/simpleShadow.jpg&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
// Sphere Shadow&lt;br /&gt;
const sphereShadow = new THREE.Mesh(&lt;br /&gt;
    new THREE.PlaneGeometry(1.5, 1.5),&lt;br /&gt;
    new THREE.MeshBasicMaterial({&lt;br /&gt;
        color: 0x000000,&lt;br /&gt;
        transparent: true,&lt;br /&gt;
        alphaMap: simpleShadow&lt;br /&gt;
    })&lt;br /&gt;
)&lt;br /&gt;
sphereShadow.rotation.x = - Math.PI * 0.5&lt;br /&gt;
sphereShadow.position.y = plane.position.y + 0.01&lt;br /&gt;
&lt;br /&gt;
scene.add(sphere, sphereShadow, plane)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Animate&lt;br /&gt;
 */&lt;br /&gt;
const clock = new THREE.Clock()&lt;br /&gt;
&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update the sphere&lt;br /&gt;
    sphere.position.x = Math.cos(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.z = Math.sin(elapsedTime) * 1.5&lt;br /&gt;
    sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))&lt;br /&gt;
&lt;br /&gt;
    // Update the shadow accordingly&lt;br /&gt;
    sphereShadow.position.x = sphere.position.x&lt;br /&gt;
    sphereShadow.position.z = sphere.position.z&lt;br /&gt;
    sphereShadow.material.opacity = (1 - sphere.position.y) * 0.3&lt;br /&gt;
&lt;br /&gt;
    // Update controls&lt;br /&gt;
    controls.update()&lt;br /&gt;
&lt;br /&gt;
    // Render&lt;br /&gt;
    renderer.render(scene, camera)&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fog ==&lt;br /&gt;
 [[Three.js - Fog]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
// Fog&lt;br /&gt;
const fog = new THREE.Fog(&amp;#039;#262837&amp;#039;, 1, 15)&lt;br /&gt;
scene.fog = fog &lt;br /&gt;
//...&lt;br /&gt;
renderer.setClearColor(&amp;#039;#262837&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Particles ==&lt;br /&gt;
Benötigen eine Geometry, ein Material, ein Points Objekt (statt wie sonst ein Mesh)&lt;br /&gt;
 [[Three.js - Particles]]&lt;br /&gt;
Starter Example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Particles&lt;br /&gt;
 */&lt;br /&gt;
// Geometry&lt;br /&gt;
const particlesGeometry = new THREE.SphereBufferGeometry(1,32,32)&lt;br /&gt;
// Material&lt;br /&gt;
const particlesMaterial = new THREE.PointsMaterial({&lt;br /&gt;
    size: 0.02,&lt;br /&gt;
    sizeAttenuation: true, //perspective smaller if far&lt;br /&gt;
})&lt;br /&gt;
// Points&lt;br /&gt;
const particles = new THREE.Points(particlesGeometry, particlesMaterial)&lt;br /&gt;
scene.add(particles)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Starters ==&lt;br /&gt;
 [[Three.js - Starters]]&lt;br /&gt;
&lt;br /&gt;
== Helpers ==&lt;br /&gt;
=== Nützliche Renderer Settings ===&lt;br /&gt;
 renderer.setClearColor(&amp;#039;#262837&amp;#039;) // Background&lt;br /&gt;
=== Optimizations ===&lt;br /&gt;
==== Materialien und Geometrien wiederverwenden ====&lt;br /&gt;
Das Erstellen von komplexen Objekten kann zeit- und speicherintensiv sein.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Zwei Zeilen umgestellt aber weit &amp;#039;&amp;#039;&amp;#039;über 100mal schneller !&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
console.time(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)&lt;br /&gt;
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })&lt;br /&gt;
for(let i = 0; i &amp;lt; 100; i++)&lt;br /&gt;
{&lt;br /&gt;
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)&lt;br /&gt;
    scene.add(donut)&lt;br /&gt;
}&lt;br /&gt;
console.timeend(&amp;#039;donuts&amp;#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Schnipsel ===&lt;br /&gt;
==== Objekte auf Ringbahn positionieren ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Graveyard&lt;br /&gt;
const graves = new THREE.Group()&lt;br /&gt;
scene.add(graves)&lt;br /&gt;
const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)&lt;br /&gt;
const graveMaterial = new THREE.MeshStandardMaterial({color: &amp;#039;#b2b6b1&amp;#039;})&lt;br /&gt;
&lt;br /&gt;
for (let i = 0; i  &amp;lt; 50; i++) {&lt;br /&gt;
    const min = 4 // minimaler Radius&lt;br /&gt;
    const max = 8.5 // maximaler Radius&lt;br /&gt;
    const radius = min + Math.random() * (max-min)// Radius zwischen min und max&lt;br /&gt;
    const angle = Math.random() * 2*Math.PI // 0 &amp;lt; angle &amp;lt; 2PI (voller Kreis im Bogenmaß)&lt;br /&gt;
    // (Bogen)Winkel in x,z Koordinaten umrechnen. Ohne * radius wäre Abstand 1&lt;br /&gt;
    const x = Math.sin(angle) * radius&lt;br /&gt;
    const z = Math.cos(angle) * radius&lt;br /&gt;
    const y = 0.35&lt;br /&gt;
    &lt;br /&gt;
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)&lt;br /&gt;
    grave.position.set(x,y,z)&lt;br /&gt;
    // Setze Grabsteine leicht schief und verdreht&lt;br /&gt;
    grave.rotation.y = (Math.random() - 0.5) * 0.4&lt;br /&gt;
    grave.rotation.z = (Math.random() - 0.5) * 0.3 &lt;br /&gt;
    &lt;br /&gt;
    graves.add(grave)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cool Colors ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ac8e82 - brown walls&lt;br /&gt;
#a9c388 - green night grass&lt;br /&gt;
#89c854 - green bush&lt;br /&gt;
#b35f45 - greek roof red&lt;br /&gt;
#b2b6b1 - grey tombstone&lt;br /&gt;
#b9d5ff - blue moonlight&lt;br /&gt;
#ff7d49 - orange warm light&lt;br /&gt;
#262837 - blueish fog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25762</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25762"/>
		<updated>2022-01-03T11:09:15Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Animation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
=== Bewegungsparameter ===&lt;br /&gt;
Wir nutzen ein weiteres &amp;#039;&amp;#039;&amp;#039;Uniform uTime&amp;#039;&amp;#039;&amp;#039; mit dem wir die elapsedTime übergeben. Diese können wir in der Funktion nutzen und erzeugen so eine Abhängigkeit von der Zeit -&amp;gt; wellenaertige Animation. für mehr Kontrolle erstellen wir noch ein uSpeed und ein uAmplitude. Für diese können wir noch ein gui Element erstellen und nutzen den Wert ebenfalls in unserer Formel. So können wir die Bewegung gut testen.&lt;br /&gt;
&lt;br /&gt;
=== Mesh skalieren ===&lt;br /&gt;
Damit das quadratische Mesh mehr nach Flagge ausschaut skalieren wir es außerdem noch. Das können wir direkt im Mesh machen ohne dass wir im Shader etwas tun müssen.&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0},&lt;br /&gt;
        uSpeed: {value: 1},&lt;br /&gt;
        uAmplitude: {value: 0.1}&lt;br /&gt;
    }&lt;br /&gt;
})  &lt;br /&gt;
&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
mesh.scale.y = 2/3 // auf 3:2 skalieren indem wir in y-Richtung verkleinern&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uSpeed, &amp;#039;value&amp;#039;).min(0).max(10).step(0.1).name(&amp;#039;speed&amp;#039;)&lt;br /&gt;
gui.add(material.uniforms.uAmplitude, &amp;#039;value&amp;#039;).min(0).max(0.2).step(0.01).name(&amp;#039;amplitude&amp;#039;)&lt;br /&gt;
//..&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
uniform float uSpeed;&lt;br /&gt;
uniform float uAmplitude;&lt;br /&gt;
//...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  //...&lt;br /&gt;
  modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime * uSpeed ) * uAmplitude; &lt;br /&gt;
  modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime * uSpeed) * uAmplitude; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Texture und Color im eigenen Shader ===&lt;br /&gt;
&lt;br /&gt;
==== Farbe ====&lt;br /&gt;
Farben lassen sich sehr einfach an den Fragment Shader übermitteln.&lt;br /&gt;
Im Script fügen wir ein weiteres Uniform hinzu:&lt;br /&gt;
 uColor: {value: new THREE.Color(&amp;#039;#ff99dd&amp;#039;)}&lt;br /&gt;
Da Three.js intern ein Vector3 Objekt können wir das direkt zum Shader schicken. Dort steht es dann als vec3 Objekt zur Verfügung:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
        &lt;br /&gt;
        uniform vec3 uColor;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            gl_FragColor = vec4(uColor.r, uColor.g, uColor.b, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Hinweis: Die Werte in vec3 Objekten kann man über x,y,z aber auch r,g,b auslesen. Das ist in diesem Fall naheliegender.&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25761</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25761"/>
		<updated>2022-01-03T10:35:52Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
Wir nutzen ein weiteres Uniform mit dem wir die elapsedTime übergeben. Diese können wir in der Funktion nutzen und erzeugen so eine Abhängigkeit von der Zeit -&amp;gt; Wellenaertige Animation.&lt;br /&gt;
&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:{&lt;br /&gt;
        uFrequency: { value: new THREE.Vector2(10, 5) },&lt;br /&gt;
        uTime: {value: 0}&lt;br /&gt;
    }&lt;br /&gt;
}) &lt;br /&gt;
//..&lt;br /&gt;
const tick = () =&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    const elapsedTime = clock.getElapsedTime()&lt;br /&gt;
&lt;br /&gt;
    // Update material&lt;br /&gt;
    material.uniforms.uTime.value = elapsedTime&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Call tick again on the next frame&lt;br /&gt;
    window.requestAnimationFrame(tick)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tick()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
uniform vec2 uFrequency; // our uniform set in material&lt;br /&gt;
uniform float uTime;&lt;br /&gt;
//...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
  //...&lt;br /&gt;
  modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime ) * 0.1; &lt;br /&gt;
  modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime ) * 0.1; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25760</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25760"/>
		<updated>2022-01-03T10:06:52Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
* Attributes -  nur an Vertex, zum Ändern von einzelnen Vertices&lt;br /&gt;
* Varying - Senden von Vertex zu Fragment Shader&lt;br /&gt;
* Uniform - Senden von Settings aus JavaScript an Vertex und Fragment Shader&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25759</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25759"/>
		<updated>2022-01-01T13:43:20Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Variying */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Uniform ===&lt;br /&gt;
Mit Uniforms kann man &amp;#039;&amp;#039;&amp;#039;Parameter von JavaScript&amp;#039;&amp;#039;&amp;#039; aus sowohl an den Vertex, als auch an den Fragment Shader &amp;#039;&amp;#039;&amp;#039;senden&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Parameter ist für jeden Vertex&amp;#039;&amp;#039;&amp;#039; der Selbe (im Gegensatz zu Attributes, bei denen der Vertexshader für jeden Vertex einen eigenen Wert bekommen hat).&lt;br /&gt;
&lt;br /&gt;
Uniforms werden im direkt im Material und nicht wie die Attribute in der Geometrie gesetzt. Logisch - Attribute werden ja auch nur auf die Geometrie angewandt.&lt;br /&gt;
&lt;br /&gt;
Die Variablen &amp;#039;&amp;#039;&amp;#039;projectionMatrix, viewMatrix, und modelMatrix sind Uniforms&amp;#039;&amp;#039;&amp;#039;, die Three.js für uns bereits erstellt hat.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel möchten wir den Frequenzparameter unserer Welle von JavaScript aus setzen. Wir definieren im Shader Material&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    uniforms:&lt;br /&gt;
    {&lt;br /&gt;
        uFrequency: { value: 10 }&lt;br /&gt;
    }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Der Name des Uniforms kann frei gewählt werden. Hier ist es uFrequency. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Hinweis:&amp;#039;&amp;#039;&amp;#039; In älteren Beispielen sieht man auch andere Varianten die früher in Three.js genutzt werden mußte z.b. in dieser Art:&lt;br /&gt;
 uFrequency: { value: 10, type: &amp;#039;float&amp;#039; }. &lt;br /&gt;
&lt;br /&gt;
Im Vertex Shader können wir jetzt den Parameter uFrequency nutzen. Z.b so&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
// ...&lt;br /&gt;
uniform vec2 uFrequency;&lt;br /&gt;
// ...&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    modelPosition.z += sin(modelPosition.x * uFrequency.x) * 0.1;&lt;br /&gt;
    modelPosition.z += sin(modelPosition.y * uFrequency.y) * 0.1;&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cool - jetzt kann man auch über die gui Werte setzen:&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;x&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyX&amp;#039;)&lt;br /&gt;
 gui.add(material.uniforms.uFrequency.value, &amp;#039;y&amp;#039;).min(0).max(20).step(0.01).name(&amp;#039;frequencyY&amp;#039;)&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25758</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25758"/>
		<updated>2022-01-01T12:58:42Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Attribute */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variying ===&lt;br /&gt;
Attribute können nicht im Fragment Shader verwendet werden. Aber wir können ein Varying erzeugen und damit das Attribut weitergeben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel nutzen wir das Zufalls-Attribut von oben und leiten es als Varying an den Fragmentshader weiter. Der nutzt es dann um die Farbe des Vertex anzupassen. Farben dazwischen werden automatisch interpoliert.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Farbe abhängig von Zufallswert ändern.&lt;br /&gt;
&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
varying float vRandom; // create new varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    vRandom = aRandom; // copy &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fragment.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float vRandom; // get varying&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // use as blue value&lt;br /&gt;
    gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25757</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25757"/>
		<updated>2022-01-01T12:48:50Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Beispiel Attribut setzen und nutzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// count vertices&lt;br /&gt;
const count = geometry.attributes.position.count &lt;br /&gt;
// create random for each vertex&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
vertex.glsl - use submitted value for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25756</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25756"/>
		<updated>2022-01-01T12:47:03Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Beispiel Attribut setzen und nutzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js - set Attribute with a random numbers for each vertex&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// create random&lt;br /&gt;
const count = geometry.attributes.position.count&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
// set attribute and tell buffer to use one value per vertex&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
vertex.glsl - use array for z-shift&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom; // make attribute accessible&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
	<entry>
		<id>https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25755</id>
		<title>Three.js - Shaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.stephanschlegel.de/index.php?title=Three.js_-_Shaders&amp;diff=25755"/>
		<updated>2022-01-01T12:44:13Z</updated>

		<summary type="html">&lt;p&gt;134.3.241.3: /* Beispiel Attribut setzen und nutzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links ==&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Überblick über Funktionen&lt;br /&gt;
 https://thebookofshaders.com/ - Gutes Tutorial und guter Überblick&lt;br /&gt;
 http://localhost/www/LEARNING/ThreeJS/Graphtoy/Graphtoy.html&lt;br /&gt;
 https://iquilezles.org/www/index.htm - useful math&lt;br /&gt;
 https://www.youtube.com/watch?v=NQ-g6v7GtoI&amp;amp;list=PL4neAtv21WOmIrTrkNO3xCyrxg4LKkrF7&amp;amp;index=4 - Shader Liniting in VSC und Shader Tutorial&lt;br /&gt;
 https://www.shadertoy.com/&lt;br /&gt;
 https://learnopengl.com/Getting-started/Coordinate-Systems&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Shader sind ein komplexes Thema und du benötigst viel Zeit zum Üben. Man kann aber auch ohne ein Mathegenie zu sein tolle Shader schreiben und es stehen dir ganz neue grafische Möglichkeiten zur Verfügung, die sich sonst nicht realisieren lassen würden.&lt;br /&gt;
&lt;br /&gt;
 Quelle zu großen Teilen: https://threejs-journey.com/lessons/27 (Zeichnungen und englischsprachige Abschnitte)&lt;br /&gt;
=== Was ist ein Shader? ===&lt;br /&gt;
&lt;br /&gt;
Ein Shader ist ein Programm der in der &amp;#039;&amp;#039;&amp;#039;Programmiersprache GLSL&amp;#039;&amp;#039;&amp;#039; (OpenGL ES Shading Language) GLSL Programme werden direkt &amp;#039;&amp;#039;&amp;#039;an die GPU&amp;#039;&amp;#039;&amp;#039; gesendet werden und können rasend schnell verarbeitet werden. Dies ist die Basis von &amp;#039;&amp;#039;&amp;#039;WebGL&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe des Shaders ist &amp;#039;&amp;#039;&amp;#039;jeden Vertex einer Geometrie zu positionieren&amp;#039;&amp;#039;&amp;#039; und &amp;#039;&amp;#039;&amp;#039;jedes sichtbares Fragment dieser Geometrie einzufärben&amp;#039;&amp;#039;&amp;#039;. Das Ergebnis ist ein fertiges Rendering das wir im Browser über das Canvas Element darstellen können. Die Pixel auf dem Monitor können sich von den Pixeln in einem Rendering unterscheiden. Deshalt nutzt man den Terminus &amp;#039;&amp;#039;&amp;#039;Fragment&amp;#039;&amp;#039;&amp;#039; statt Pixel. Die Fragments beziehen sich auf die kleinste Einheit beim Rendering und bilden quasi das Pendant zu Pixeln in der Renderwelt.&lt;br /&gt;
&lt;br /&gt;
Shader sind nicht auf den Browser beschränkt. Auch native Programme oder Apps können Shader nutzen, hier geht es aber um den Einsatz von Shadern mit Three.js im Browser.&lt;br /&gt;
&lt;br /&gt;
=== Vertex und Fragment Shader ===&lt;br /&gt;
Der Renderprozess nutzt &amp;#039;&amp;#039;&amp;#039;2 Arten von Shadern&amp;#039;&amp;#039;&amp;#039;. &lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Vertex Shader verarbeitet alle Geometriedaten&amp;#039;&amp;#039;&amp;#039; (Objekte, Kamera,...) und projiziert sie auf die 2D-Ebene des fertigen Renderbilds.&lt;br /&gt;
&lt;br /&gt;
Der &amp;#039;&amp;#039;&amp;#039;Fragment Shader färbt anschließend jedes sichtbare Fragment&amp;#039;&amp;#039;&amp;#039; des Shaders ein.&lt;br /&gt;
&lt;br /&gt;
=== Wie funktioniert der Shader? ===&lt;br /&gt;
Es ist wichtig die Arbeitsweise zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Der Vertex Shader wird für &amp;#039;&amp;#039;&amp;#039;jeden Vertex&amp;#039;&amp;#039;&amp;#039; ausgeführt. Dabei bekommt er Daten, wie z.b. die Position, die sich bei jedem Vertex ändern. Diese nennt man &amp;#039;&amp;#039;&amp;#039;Attributes&amp;#039;&amp;#039;&amp;#039;. Daten die für jeden Vertex gleich bleiben nennt man &amp;#039;&amp;#039;&amp;#039;Uniform&amp;#039;&amp;#039;&amp;#039;. Attribute kann man nur an den Vertex Shader senden. Wenn sie im Fragment Shader benötigt werden, muss der Vertex Shader als &amp;#039;&amp;#039;&amp;#039;Varying&amp;#039;&amp;#039;&amp;#039; weitersenden.  Uniforms stehen auch direkt im Fragment Shader zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Wenn der Vertex Shader die Positionierung der Vertices erledigt hat. Färbt der Fragment Shader &amp;#039;&amp;#039;&amp;#039;jedes Fragment&amp;#039;&amp;#039;&amp;#039; ein. Er färbt also nicht nur die Vertices sondern auch die Bereiche dazwischen. Dabei interpoliert er automatisch die Farbe auf Basis der vorhandenen Information (z.B.Farbe der umgebenden Vertices, Faces, Texturen...)&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
[[File:WebGl-Shader.png|600px]]&lt;br /&gt;
* Der Vertex Shader positioniert Vertices auf dem Rendering.&lt;br /&gt;
* Der Fragment Shader färbt jedes sichtbare Fragment (quasi Pixel) der Geometrie.&lt;br /&gt;
* Der Fragment Shader wird nach dem Vertex Shader ausgeführt.&lt;br /&gt;
* Daten die sich von Vertex zu Vertex unterscheiden nennt man Attribute und können nur an den Vertex Shader gesendet werden.&lt;br /&gt;
* Daten die sich nicht zwischen den Vertices unterscheiden nennt man Uniform.&lt;br /&gt;
* Auf Uniforms kann man im Vertex und im Fragment Shader zugreifen.&lt;br /&gt;
* Wir können mit einem Varying Daten vom Vertex zum Fragmentshader senden.&lt;br /&gt;
&lt;br /&gt;
== Eigene Shader in Three.js ==&lt;br /&gt;
=== ShaderMaterial / RawShaderMaterial ===&lt;br /&gt;
Eigene Shader kann man in Three.js über besondere Materialien realisieren: &amp;#039;&amp;#039;&amp;#039;ShaderMaterial&amp;#039;&amp;#039;&amp;#039; oder &amp;#039;&amp;#039;&amp;#039;RawShaderMaterial&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Bei einem ShaderMaterial kann man etwas Code sparen, da dieses automatisch Code voranstellt, den man (zumindest teilweise) sonst selbst einfügen müßte.&lt;br /&gt;
&lt;br /&gt;
GLSF Code kann man direkt in die Objekte vertexShader und fragmentShader schreiben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: `// vertex shader code goes here`,&lt;br /&gt;
    fragmentShader: `// fragment shader code goes here`&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den Code zwischen die Backticks schreiben ist allerdings nicht besonders sinnvoll. Besser geht es über separate Dateien. wir legen zwei Dateien an. Den Code müssen wir noch nicht verstehen. &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/vertex.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
        uniform mat4 projectionMatrix;&lt;br /&gt;
        uniform mat4 viewMatrix;&lt;br /&gt;
        uniform mat4 modelMatrix;&lt;br /&gt;
&lt;br /&gt;
        attribute vec3 position;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/shaders/test/fragment.glsl&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
        precision mediump float;&lt;br /&gt;
&lt;br /&gt;
        void main()&lt;br /&gt;
        {&lt;br /&gt;
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Jetzt können wir die Dateien als Variable importieren (wir gehen hier von einem Wepack Projekt aus) und in unseren Shader einfügen.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;/script.js&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import testVertexShader from &amp;#039;./shaders/test/vertex.glsl&amp;#039;&lt;br /&gt;
import testFragmentShader from &amp;#039;./shaders/test/fragment.glsl&amp;#039;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
// Material&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader&lt;br /&gt;
})&lt;br /&gt;
// Mesh&lt;br /&gt;
const mesh = new THREE.Mesh(geometry, material)&lt;br /&gt;
&lt;br /&gt;
scene.add(mesh)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn alles passt können wir den ersten Shader in Aktion sehen.&lt;br /&gt;
&lt;br /&gt;
Eventuell gibt es ein paar Probleme mit unserem Setup. Die gehen wir im folgenden Exkurs an...&lt;br /&gt;
&lt;br /&gt;
=== Exkurs: VisualStudioCode und Webpack für glsl Dateien einrichten ===&lt;br /&gt;
====Extension für Syntaxhighlight in VSC====&lt;br /&gt;
 Shader languages support for VS Code von slevesque&lt;br /&gt;
 Syntax highlighter for shader language (hlsl, glsl, cg)&lt;br /&gt;
&lt;br /&gt;
====Webpack anpassen====&lt;br /&gt;
Wir müssen Webpack beibringen, wie es mit .glsl files umgehen soll. Dafür müssen wir das rules array anpassen. Das kann in unterschiedlichen Files liegen. Einfach mal von package.json ausgehend über die scripts Property schauen wo die Konfigurationsdateien liegen.&lt;br /&gt;
&lt;br /&gt;
Folgende Regel anlegen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
module.exports = {&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    module:&lt;br /&gt;
    {&lt;br /&gt;
        rules:&lt;br /&gt;
        [&lt;br /&gt;
            // ...&lt;br /&gt;
&lt;br /&gt;
            // Shaders&lt;br /&gt;
            {&lt;br /&gt;
                test: /\.(glsl|vs|fs|vert|frag)$/,&lt;br /&gt;
                type: &amp;#039;asset/source&amp;#039;,&lt;br /&gt;
                generator:&lt;br /&gt;
                {&lt;br /&gt;
                    filename: &amp;#039;assets/images/[hash][ext]&amp;#039;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This rule solely tells Webpack to provide the raw content of the files having .glsl, .vs, .fs, .vert or .frag as extension.&lt;br /&gt;
&lt;br /&gt;
Re-launch the server with npm run dev and the Webpack error will disappear.&lt;br /&gt;
&lt;br /&gt;
If you log testVertexShader and testFragmentShader, you&amp;#039;ll get the shader code as a plain string. We can use these two variables in our RawShaderMaterial.&lt;br /&gt;
&lt;br /&gt;
=== Shader programmieren ===&lt;br /&gt;
==== Properties ====&lt;br /&gt;
&lt;br /&gt;
Most of the common properties we&amp;#039;ve covered with other materials such as &amp;#039;&amp;#039;&amp;#039;wireframe, side, transparent or flatShading are still available&amp;#039;&amp;#039;&amp;#039; for the RawShaderMaterial:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
const material = new THREE.RawShaderMaterial({&lt;br /&gt;
    vertexShader: testVertexShader,&lt;br /&gt;
    fragmentShader: testFragmentShader,&lt;br /&gt;
    wireframe: true&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
But properties like &amp;#039;&amp;#039;&amp;#039;map, alphaMap, opacity, color, etc. won&amp;#039;t work anymore&amp;#039;&amp;#039;&amp;#039; because we need to write these features in the shaders ourselves.&lt;br /&gt;
&lt;br /&gt;
GLSL ähnelt sehr stark C. Es ist eine typisierte Sprache. Entsprechend müssen auch Variablen und Funktionen deklariert werden. Es gibt auch ein paar neue Typen. Wir gehen hier nicht in die Tiefe, aber hier ein paar interessante Beispiele für den Einstieg.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float a = 1.0;&lt;br /&gt;
int b = 2;&lt;br /&gt;
float c = a * float(b); // we have to cast&lt;br /&gt;
&lt;br /&gt;
// functions need return value declared (or void if no return value)&lt;br /&gt;
float loremIpsum()&lt;br /&gt;
{&lt;br /&gt;
    float a = 1.0;&lt;br /&gt;
    float b = 2.0;&lt;br /&gt;
&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vec2 foo = vec2(1.0, 2.0); // vector types&lt;br /&gt;
foo.x = 1.0; // changing values in vector&lt;br /&gt;
foo *= 2.0; // changes both values&lt;br /&gt;
&lt;br /&gt;
vec3 bar = vec3(1.0, 2.0, 3.0); // vec3 is like vec2 with 3 vals&lt;br /&gt;
vec3 foo = vec3(0.0); // sets all three vals&lt;br /&gt;
&lt;br /&gt;
vec3 purpleColor = vec3(0.0);&lt;br /&gt;
purpleColor.r = 0.5; // use r,g,b or x,y,z to access vals. Both is possible&lt;br /&gt;
purpleColor.b = 1.0;&lt;br /&gt;
&lt;br /&gt;
vec3 foo = vec3(1.0, 2.0, 3.0);&lt;br /&gt;
vec2 bar = foo.xy; // use xy of foo to setz vec2 (all combinations work)&lt;br /&gt;
&lt;br /&gt;
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // vec4 has xyzw alias rgba&lt;br /&gt;
vec4 bar = vec4(foo.zw, vec2(5.0, 6.0)); // you can fill with the smaller vecs&lt;br /&gt;
&lt;br /&gt;
// other types are mat2, mat3, mat4, sampler2d&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== GLSL - Native functions ====&lt;br /&gt;
&lt;br /&gt;
GLSL has many built-in classic functions such as &amp;#039;&amp;#039;&amp;#039;sin, cos, max, min, pow, exp, mod, clamp&amp;#039;&amp;#039;&amp;#039;, but also very practical functions like &amp;#039;&amp;#039;&amp;#039;cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Documentation&lt;br /&gt;
 https://www.shaderific.com/glsl-functions - Meant for Shaderific iOS application but documentation isn&amp;#039;t too bad.&lt;br /&gt;
 https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/indexflat.php - Deals with OpenGL, but most of the standard functions compatible with WebGL. Let&amp;#039;s not forget that WebGL is just a JavaScript API to access OpenGL.&lt;br /&gt;
Book of shaders documentation&lt;br /&gt;
 https://thebookofshaders.com/ - Focused on fragment shaders, great resource to learn and it has its own glossary.&lt;br /&gt;
&lt;br /&gt;
== Vertex Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
&lt;br /&gt;
Remember: The vertex shader will convert the 3D vertices coordinates to our 2D canvas coordinates.&lt;br /&gt;
* Die main() Funktion wird für jeden Vertex ausgeführt&lt;br /&gt;
* Der Vertex Shader benötigt Daten über das Objekt aber auch über die Kamera bzw. die Projektion, den Renderausschnitt und das Model. Aus diesen Informationen berechnet er, wo ein Vertex im 2D Raum gesetzt wird.&lt;br /&gt;
* Zur Berechnung nutzt der Shader 3 Matrizen die er nacheinander abarbeitet, bis die Endkoordinaten feststehen:&lt;br /&gt;
 uniform mat4 modelMatrix; //apply all transformations relative to the Mesh (scale, rotate... in mesh)&lt;br /&gt;
 uniform mat4 viewMatrix; //apply transformations relative to the camera&lt;br /&gt;
 uniform mat4 projectionMatrix; //apply clip space transformation&lt;br /&gt;
Dies spiegelt sich in der erste Zeile im Beispielcode oben wieder.&lt;br /&gt;
* Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Man &amp;quot;wendet eine Matrix auf einen Vektor&amp;quot; an. &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;main function&amp;#039;&amp;#039;&amp;#039; will be called automatically. As you can see, it doesn&amp;#039;t return anything (void). &lt;br /&gt;
* The &amp;#039;&amp;#039;&amp;#039;gl_Position&amp;#039;&amp;#039;&amp;#039; variable already exists. This variable will contain the position of the vertex on the screen. The goal of the instructions in the main function is to set this variable properly with a vec4.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;clip space&amp;#039;&amp;#039;&amp;#039; is a space that goes in all 3 directions (x, y , and z) in a range from -1 to +1. It&amp;#039;s like positioning everything in a 3D box. Anything out of this range will be &amp;quot;clipped&amp;quot; and disappear. The fourth value (w) is responsible for the perspective.&lt;br /&gt;
&lt;br /&gt;
==== Beispiele ====&lt;br /&gt;
Um eine vec4 Position zu projizieren multipliziert man ihn einfach mit einer mat4 Matrix. Das kann man sich zunutze machen. Wenn man den Code oben umschreibt, bekommt man einfachen Zugriff auf die Position des Models.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
 //modelPosition.z -= 0.1; // komplettes Modell verschieben&lt;br /&gt;
 modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;// sinus(x-position des vertex) &amp;gt; auf y position anwenden&lt;br /&gt;
 vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
 vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
 gl_Position = projectedPosition;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fragment Shader Quickstart ==&lt;br /&gt;
=== Das Wichtigste in Kürze ===&lt;br /&gt;
* The fragment shader code will be applied to every visible fragment of the geometry. That is why the fragment shader comes after the vertex shader.&lt;br /&gt;
* Die main() Funktion wird für jedes Fragment ausgeführt&lt;br /&gt;
* Man kann die Präzision für Float Werte einstellen: precision mediump float; (highp, mediump,lowp)sollte das aber auf dem mittleren Wert belassen.&lt;br /&gt;
* Ziel der main Funktion ist es die &amp;#039;&amp;#039;&amp;#039;gl_FragColor&amp;#039;&amp;#039;&amp;#039; zu setzen. &lt;br /&gt;
* Jeder Wert von gl_FragColor liegt zwischen 0.0 und 1.0. Werden die Werte überschritten gibt es keinen Fehler aber auch keine Wirkung.&lt;br /&gt;
* Die Werte stehen für rgba (rot, grün, blau, alpha) Damit die Transparenz funktioniert muss im RawShaderMaterial / ShaderMaterial transparent = true gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Attributes können sich für jeden Vertex ändern. Das position Attribut enthält z.B. für jeden Vertex ein eigenes vec3.&lt;br /&gt;
&lt;br /&gt;
Wir können eigene Attribute erstellen und direkt an die Geometrie übergeben.&lt;br /&gt;
&lt;br /&gt;
We will add a random value for each vertex and move that vertex on the z axis according to that value for this lesson.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Attribut setzen und nutzen ===&lt;br /&gt;
&lt;br /&gt;
script.js&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Geometry&lt;br /&gt;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32)&lt;br /&gt;
&lt;br /&gt;
const count = geometry.attributes.position.count&lt;br /&gt;
const randoms = new Float32Array(count)&lt;br /&gt;
for(let i = 0; i &amp;lt; count; i++)&lt;br /&gt;
{&lt;br /&gt;
    randoms[i] = Math.random()&lt;br /&gt;
}&lt;br /&gt;
geometry.setAttribute(&amp;#039;aRandom&amp;#039;, new THREE.BufferAttribute(randoms, 1))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
vertex.glsl&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute float aRandom;&lt;br /&gt;
//...&lt;br /&gt;
void main(){&lt;br /&gt;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);&lt;br /&gt;
  modelPosition.z += aRandom * 0.1; // change via attribute&lt;br /&gt;
  vec4 viewPosition = viewMatrix * modelPosition;&lt;br /&gt;
  vec4 projectedPosition = projectionMatrix * viewPosition;&lt;br /&gt;
  gl_Position = projectedPosition;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>134.3.241.3</name></author>
	</entry>
</feed>