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