├── screenshot01.png ├── screenshot02.png ├── screenshot03.png ├── screenshot04.png ├── screenshot05.png ├── screenshot06.png ├── src ├── textures │ ├── water │ │ ├── Water_002_OCC.jpg │ │ ├── Water_002_COLOR.jpg │ │ ├── Water_002_DISP.png │ │ ├── Water_002_NORM.jpg │ │ └── Water_002_ROUGH.jpg │ ├── slime │ │ ├── alien-slime1-ao.png │ │ ├── alien-slime1-albedo.png │ │ ├── alien-slime1-height.png │ │ ├── alien-slime1-metallic.png │ │ ├── alien-slime1-normal-ogl.png │ │ └── alien-slime1-roughness.png │ └── soil │ │ ├── Rock_Moss_001_height.png │ │ ├── Rock_Moss_001_normal.jpg │ │ ├── Rock_Moss_001_basecolor.jpg │ │ ├── Rock_Moss_001_roughness.jpg │ │ └── Rock_Moss_001_ambientOcclusion.jpg ├── index.html ├── index.ts ├── sine_wave_plane.ts ├── sine_cos_wave_plane.ts ├── sine_cos_slime_wave_plane.ts ├── sine_cos_water_wave_plane.ts ├── sphere_with_waves.ts └── terrain_editor.ts ├── .gitignore ├── tsconfig.json ├── webpack.config.js ├── package.json ├── LICENSE └── README.md /screenshot01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/screenshot01.png -------------------------------------------------------------------------------- /screenshot02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/screenshot02.png -------------------------------------------------------------------------------- /screenshot03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/screenshot03.png -------------------------------------------------------------------------------- /screenshot04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/screenshot04.png -------------------------------------------------------------------------------- /screenshot05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/screenshot05.png -------------------------------------------------------------------------------- /screenshot06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/screenshot06.png -------------------------------------------------------------------------------- /src/textures/water/Water_002_OCC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/water/Water_002_OCC.jpg -------------------------------------------------------------------------------- /src/textures/slime/alien-slime1-ao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/slime/alien-slime1-ao.png -------------------------------------------------------------------------------- /src/textures/water/Water_002_COLOR.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/water/Water_002_COLOR.jpg -------------------------------------------------------------------------------- /src/textures/water/Water_002_DISP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/water/Water_002_DISP.png -------------------------------------------------------------------------------- /src/textures/water/Water_002_NORM.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/water/Water_002_NORM.jpg -------------------------------------------------------------------------------- /src/textures/water/Water_002_ROUGH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/water/Water_002_ROUGH.jpg -------------------------------------------------------------------------------- /src/textures/slime/alien-slime1-albedo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/slime/alien-slime1-albedo.png -------------------------------------------------------------------------------- /src/textures/slime/alien-slime1-height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/slime/alien-slime1-height.png -------------------------------------------------------------------------------- /src/textures/soil/Rock_Moss_001_height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/soil/Rock_Moss_001_height.png -------------------------------------------------------------------------------- /src/textures/soil/Rock_Moss_001_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/soil/Rock_Moss_001_normal.jpg -------------------------------------------------------------------------------- /src/textures/slime/alien-slime1-metallic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/slime/alien-slime1-metallic.png -------------------------------------------------------------------------------- /src/textures/slime/alien-slime1-normal-ogl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/slime/alien-slime1-normal-ogl.png -------------------------------------------------------------------------------- /src/textures/slime/alien-slime1-roughness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/slime/alien-slime1-roughness.png -------------------------------------------------------------------------------- /src/textures/soil/Rock_Moss_001_basecolor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/soil/Rock_Moss_001_basecolor.jpg -------------------------------------------------------------------------------- /src/textures/soil/Rock_Moss_001_roughness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/soil/Rock_Moss_001_roughness.jpg -------------------------------------------------------------------------------- /src/textures/soil/Rock_Moss_001_ambientOcclusion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tamani-coding/threejs-buffergeometry-examples/HEAD/src/textures/soil/Rock_Moss_001_ambientOcclusion.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .cache/ 3 | coverage/ 4 | dist/* 5 | !dist/index.html 6 | node_modules/ 7 | *.log 8 | 9 | # OS generated files 10 | .DS_Store 11 | .DS_Store? 12 | ._* 13 | .Spotlight-V100 14 | .Trashes 15 | ehthumbs.db 16 | Thumbs.db 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "noImplicitAny": true, 6 | "module": "CommonJS", 7 | "target": "es5", 8 | "allowJs": true 9 | } 10 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | three.js example 6 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { sine_cos_slime_wave_plane } from "./sine_cos_slime_wave_plane"; 2 | import { sine_cos_water_wave_plane } from "./sine_cos_water_wave_plane"; 3 | import { sine_cos_wave_plane } from "./sine_cos_wave_plane"; 4 | import { sine_wave_plane } from "./sine_wave_plane"; 5 | import { sphere_with_waves } from "./sphere_with_waves"; 6 | import { terrain_editor } from "./terrain_editor"; 7 | 8 | // sine_wave_plane(); 9 | // sine_cos_wave_plane(); 10 | // sine_cos_slime_wave_plane(); 11 | // sine_cos_water_wave_plane(); 12 | // sphere_with_waves(); 13 | terrain_editor(); -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const src = path.resolve(__dirname, 'src'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/index.ts', 8 | devtool: 'inline-source-map', 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.tsx?$/, 13 | use: 'ts-loader', 14 | exclude: /node_modules/ 15 | } 16 | ] 17 | }, 18 | resolve: { 19 | extensions: ['.tsx', '.ts', '.js'] 20 | }, 21 | output: { 22 | filename: 'index.js', 23 | path: src 24 | }, 25 | devServer: { 26 | static: src, 27 | }, 28 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "threejs-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npm run build && npm run serve", 8 | "build": "webpack", 9 | "serve": "webpack serve" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "npm-run-all": "^4.1.5", 16 | "ts-loader": "^8.1.0", 17 | "typescript": "^4.2.3", 18 | "webpack": "^5.89.0", 19 | "webpack-cli": "^5.1.4", 20 | "webpack-dev-server": "^4.15.1" 21 | }, 22 | "dependencies": { 23 | "@types/three": "^0.131.0", 24 | "three": "^0.132.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 tamani-coding 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # threejs-buffergeometry-examples 2 | threejs-buffergeometry-examples 3 | 4 | `npm install` and `npm run start` 5 | 6 | Try the [Stackblitz](https://stackblitz.com/github/tamani-coding/threejs-buffergeometry-examples) 7 | 8 | Go to index.ts and uncomment the example which you want to run. 9 | 10 | ## textures 11 | 12 | https://freepbr.com/c/organic/ 13 | 14 | https://3dtextures.me/ 15 | 16 | ## screenshots 17 | 18 | ![Screenshot](https://github.com/tamani-coding/threejs-buffergeometry-examples/blob/main/screenshot01.png?raw=true) 19 | ![Screenshot](https://github.com/tamani-coding/threejs-buffergeometry-examples/blob/main/screenshot02.png?raw=true) 20 | ![Screenshot](https://github.com/tamani-coding/threejs-buffergeometry-examples/blob/main/screenshot03.png?raw=true) 21 | ![Screenshot](https://github.com/tamani-coding/threejs-buffergeometry-examples/blob/main/screenshot04.png?raw=true) 22 | ![Screenshot](https://github.com/tamani-coding/threejs-buffergeometry-examples/blob/main/screenshot05.png?raw=true) 23 | ![Screenshot](https://github.com/tamani-coding/threejs-buffergeometry-examples/blob/main/screenshot06.png?raw=true) 24 | -------------------------------------------------------------------------------- /src/sine_wave_plane.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | export function sine_wave_plane() { 5 | // SCENE 6 | const scene = new THREE.Scene(); 7 | scene.background = new THREE.Color(0xa8def0); 8 | 9 | // CAMERA 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 11 | camera.position.y = 5; 12 | 13 | // RENDERER 14 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 15 | renderer.setSize(window.innerWidth, window.innerHeight); 16 | renderer.setPixelRatio(window.devicePixelRatio); 17 | renderer.shadowMap.enabled = true 18 | 19 | // CONTROLS 20 | const controls = new OrbitControls(camera, renderer.domElement); 21 | controls.target = new THREE.Vector3(0, 0, -40); 22 | controls.update(); 23 | 24 | // AMBIENT LIGHT 25 | scene.add(new THREE.AmbientLight(0xffffff, 0.5)); 26 | // DIRECTIONAL LIGHT 27 | const dirLight = new THREE.DirectionalLight(0xffffff, 1.0) 28 | dirLight.position.x += 20 29 | dirLight.position.y += 20 30 | dirLight.position.z += 20 31 | dirLight.castShadow = true 32 | dirLight.shadow.mapSize.width = 4096; 33 | dirLight.shadow.mapSize.height = 4096; 34 | const d = 25; 35 | dirLight.shadow.camera.left = - d; 36 | dirLight.shadow.camera.right = d; 37 | dirLight.shadow.camera.top = d; 38 | dirLight.shadow.camera.bottom = - d; 39 | dirLight.position.z = -30; 40 | 41 | let target = new THREE.Object3D(); 42 | target.position.z = -30; 43 | dirLight.target = target; 44 | dirLight.target.updateMatrixWorld(); 45 | 46 | dirLight.shadow.camera.lookAt(0, 0, -30); 47 | scene.add(dirLight); 48 | // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) ); 49 | 50 | const geometry = new THREE.PlaneBufferGeometry(30, 30, 200, 200); 51 | const plane = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({ color: 0xf2a23a })); 52 | plane.receiveShadow = true; 53 | plane.castShadow = true; 54 | plane.rotation.x = - Math.PI / 2; 55 | plane.position.z = - 30; 56 | scene.add(plane); 57 | 58 | const count: number = geometry.attributes.position.count; 59 | 60 | // ANIMATE 61 | function animate() { 62 | 63 | // SINE WAVE 64 | const now = Date.now() / 300; 65 | for (let i = 0; i < count; i++) { 66 | const x = geometry.attributes.position.getX(i); 67 | 68 | // SINE WAVE 69 | const xangle = x + now 70 | const xsin = Math.sin(xangle) 71 | geometry.attributes.position.setZ(i, xsin); 72 | } 73 | geometry.computeVertexNormals(); 74 | geometry.attributes.position.needsUpdate = true; 75 | 76 | renderer.render(scene, camera); 77 | requestAnimationFrame(animate); 78 | } 79 | document.body.appendChild(renderer.domElement); 80 | animate(); 81 | 82 | // RESIZE HANDLER 83 | function onWindowResize() { 84 | camera.aspect = window.innerWidth / window.innerHeight; 85 | camera.updateProjectionMatrix(); 86 | renderer.setSize(window.innerWidth, window.innerHeight); 87 | } 88 | window.addEventListener('resize', onWindowResize); 89 | } -------------------------------------------------------------------------------- /src/sine_cos_wave_plane.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | export function sine_cos_wave_plane() { 5 | // SCENE 6 | const scene = new THREE.Scene(); 7 | scene.background = new THREE.Color(0xa8def0); 8 | 9 | // CAMERA 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 11 | camera.position.y = 5; 12 | 13 | // RENDERER 14 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 15 | renderer.setSize(window.innerWidth, window.innerHeight); 16 | renderer.setPixelRatio(window.devicePixelRatio); 17 | renderer.shadowMap.enabled = true 18 | 19 | // CONTROLS 20 | const controls = new OrbitControls(camera, renderer.domElement); 21 | controls.target = new THREE.Vector3(0, 0, -40); 22 | controls.update(); 23 | 24 | // AMBIENT LIGHT 25 | scene.add(new THREE.AmbientLight(0xffffff, 0.5)); 26 | // DIRECTIONAL LIGHT 27 | const dirLight = new THREE.DirectionalLight(0xffffff, 1.0) 28 | dirLight.position.x += 20 29 | dirLight.position.y += 20 30 | dirLight.position.z += 20 31 | dirLight.castShadow = true 32 | dirLight.shadow.mapSize.width = 4096; 33 | dirLight.shadow.mapSize.height = 4096; 34 | const d = 25; 35 | dirLight.shadow.camera.left = - d; 36 | dirLight.shadow.camera.right = d; 37 | dirLight.shadow.camera.top = d; 38 | dirLight.shadow.camera.bottom = - d; 39 | dirLight.position.z = -30; 40 | 41 | let target = new THREE.Object3D(); 42 | target.position.z = -20; 43 | dirLight.target = target; 44 | dirLight.target.updateMatrixWorld(); 45 | 46 | dirLight.shadow.camera.lookAt(0, 0, -30); 47 | scene.add(dirLight); 48 | // scene.add(new THREE.CameraHelper(dirLight.shadow.camera)); 49 | 50 | const geometry = new THREE.PlaneBufferGeometry(30, 30, 200, 200); 51 | const plane = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({ color: 0xf2a23a })); 52 | plane.receiveShadow = true; 53 | plane.castShadow = true; 54 | plane.rotation.x = - Math.PI / 2; 55 | plane.position.z = - 30; 56 | scene.add(plane); 57 | 58 | const count: number = geometry.attributes.position.count; 59 | 60 | // ANIMATE 61 | function animate() { 62 | 63 | // SINE WAVE 64 | const now = Date.now() / 300; 65 | for (let i = 0; i < count; i++) { 66 | const x = geometry.attributes.position.getX(i) 67 | const y = geometry.attributes.position.getY(i) 68 | 69 | const xangle = x + now 70 | const xsin = Math.sin(xangle) 71 | const yangle = y + now 72 | const ycos = Math.cos(yangle) 73 | 74 | geometry.attributes.position.setZ(i, xsin + ycos) 75 | } 76 | geometry.computeVertexNormals() 77 | geometry.attributes.position.needsUpdate = true; 78 | 79 | renderer.render(scene, camera); 80 | requestAnimationFrame(animate); 81 | } 82 | document.body.appendChild(renderer.domElement); 83 | animate(); 84 | 85 | // RESIZE HANDLER 86 | function onWindowResize() { 87 | camera.aspect = window.innerWidth / window.innerHeight; 88 | camera.updateProjectionMatrix(); 89 | renderer.setSize(window.innerWidth, window.innerHeight); 90 | } 91 | window.addEventListener('resize', onWindowResize); 92 | } -------------------------------------------------------------------------------- /src/sine_cos_slime_wave_plane.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | export function sine_cos_slime_wave_plane() { 5 | // SCENE 6 | const scene = new THREE.Scene(); 7 | scene.background = new THREE.Color(0xa8def0); 8 | 9 | // CAMERA 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 11 | camera.position.y = 5; 12 | 13 | // RENDERER 14 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 15 | renderer.setSize(window.innerWidth, window.innerHeight); 16 | renderer.setPixelRatio(window.devicePixelRatio); 17 | renderer.shadowMap.enabled = true 18 | 19 | // CONTROLS 20 | const controls = new OrbitControls(camera, renderer.domElement); 21 | controls.target = new THREE.Vector3(0, 0, -40); 22 | controls.update(); 23 | 24 | // AMBIENT LIGHT 25 | scene.add(new THREE.AmbientLight(0xffffff, 0.5)); 26 | // DIRECTIONAL LIGHT 27 | const dirLight = new THREE.DirectionalLight(0xffffff, 1.0) 28 | dirLight.position.x += 20 29 | dirLight.position.y += 20 30 | dirLight.position.z += 20 31 | dirLight.castShadow = true 32 | dirLight.shadow.mapSize.width = 4096; 33 | dirLight.shadow.mapSize.height = 4096; 34 | const d = 25; 35 | dirLight.shadow.camera.left = - d; 36 | dirLight.shadow.camera.right = d; 37 | dirLight.shadow.camera.top = d; 38 | dirLight.shadow.camera.bottom = - d; 39 | dirLight.position.z = -30; 40 | 41 | let target = new THREE.Object3D(); 42 | target.position.z = -20; 43 | dirLight.target = target; 44 | dirLight.target.updateMatrixWorld(); 45 | 46 | dirLight.shadow.camera.lookAt(0, 0, -30); 47 | scene.add(dirLight); 48 | // scene.add(new THREE.CameraHelper(dirLight.shadow.camera)); 49 | 50 | // TEXTURES 51 | const textureLoader = new THREE.TextureLoader(); 52 | 53 | const slimeBaseColor = textureLoader.load("./textures/slime/alien-slime1-albedo.png"); 54 | const slimeNormalMap = textureLoader.load("./textures/slime/alien-slime1-normal-ogl.png"); 55 | const slimeHeightMap = textureLoader.load("./textures/slime/alien-slime1-height.png"); 56 | const slimeRoughness = textureLoader.load("./textures/slime/alien-slime1-roughness.png"); 57 | const slimeAmbientOcclusion = textureLoader.load("./textures/slime/alien-slime1-ao.png"); 58 | 59 | // PLANE 60 | const geometry = new THREE.PlaneBufferGeometry(30, 30, 200, 200); 61 | const plane = new THREE.Mesh(geometry, 62 | new THREE.MeshStandardMaterial({ 63 | map: slimeBaseColor, 64 | normalMap: slimeNormalMap, 65 | displacementMap: slimeHeightMap, displacementScale: 0.01, 66 | roughnessMap: slimeRoughness, roughness: 0, 67 | aoMap: slimeAmbientOcclusion })); 68 | plane.receiveShadow = true; 69 | plane.castShadow = true; 70 | plane.rotation.x = - Math.PI / 2; 71 | plane.position.z = - 30; 72 | scene.add(plane); 73 | 74 | const count: number = geometry.attributes.position.count; 75 | const damping = 0.75; 76 | 77 | // ANIMATE 78 | function animate() { 79 | 80 | // SINE WAVE 81 | const now = Date.now() / 400; 82 | for (let i = 0; i < count; i++) { 83 | const x = geometry.attributes.position.getX(i) 84 | const y = geometry.attributes.position.getY(i) 85 | 86 | const xangle = x + now 87 | const xsin = Math.sin(xangle) * damping 88 | const yangle = y + now 89 | const ycos = Math.cos(yangle) * damping 90 | 91 | geometry.attributes.position.setZ(i, xsin + ycos) 92 | } 93 | geometry.computeVertexNormals(); 94 | geometry.attributes.position.needsUpdate = true; 95 | 96 | renderer.render(scene, camera); 97 | requestAnimationFrame(animate); 98 | } 99 | document.body.appendChild(renderer.domElement); 100 | animate(); 101 | 102 | // RESIZE HANDLER 103 | function onWindowResize() { 104 | camera.aspect = window.innerWidth / window.innerHeight; 105 | camera.updateProjectionMatrix(); 106 | renderer.setSize(window.innerWidth, window.innerHeight); 107 | } 108 | window.addEventListener('resize', onWindowResize); 109 | } -------------------------------------------------------------------------------- /src/sine_cos_water_wave_plane.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | export function sine_cos_water_wave_plane() { 5 | // SCENE 6 | const scene = new THREE.Scene(); 7 | scene.background = new THREE.Color(0xa8def0); 8 | 9 | // CAMERA 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 11 | camera.position.y = 5; 12 | 13 | // RENDERER 14 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 15 | renderer.setSize(window.innerWidth, window.innerHeight); 16 | renderer.setPixelRatio(window.devicePixelRatio); 17 | renderer.shadowMap.enabled = true 18 | 19 | // CONTROLS 20 | const controls = new OrbitControls(camera, renderer.domElement); 21 | controls.target = new THREE.Vector3(0, 0, -40); 22 | controls.update(); 23 | 24 | // AMBIENT LIGHT 25 | scene.add(new THREE.AmbientLight(0xffffff, 0.5)); 26 | // DIRECTIONAL LIGHT 27 | const dirLight = new THREE.DirectionalLight(0xffffff, 1.0) 28 | dirLight.position.x += 20 29 | dirLight.position.y += 20 30 | dirLight.position.z += 20 31 | dirLight.castShadow = true 32 | dirLight.shadow.mapSize.width = 4096; 33 | dirLight.shadow.mapSize.height = 4096; 34 | const d = 25; 35 | dirLight.shadow.camera.left = - d; 36 | dirLight.shadow.camera.right = d; 37 | dirLight.shadow.camera.top = d; 38 | dirLight.shadow.camera.bottom = - d; 39 | dirLight.position.z = -30; 40 | 41 | let target = new THREE.Object3D(); 42 | target.position.z = -20; 43 | dirLight.target = target; 44 | dirLight.target.updateMatrixWorld(); 45 | 46 | dirLight.shadow.camera.lookAt(0, 0, -30); 47 | scene.add(dirLight); 48 | // scene.add(new THREE.CameraHelper(dirLight.shadow.camera)); 49 | 50 | 51 | // TEXTURES 52 | const textureLoader = new THREE.TextureLoader(); 53 | 54 | const waterBaseColor = textureLoader.load("./textures/water/Water_002_COLOR.jpg"); 55 | const waterNormalMap = textureLoader.load("./textures/water/Water_002_NORM.jpg"); 56 | const waterHeightMap = textureLoader.load("./textures/water/Water_002_DISP.png"); 57 | const waterRoughness = textureLoader.load("./textures/water/Water_002_ROUGH.jpg"); 58 | const waterAmbientOcclusion = textureLoader.load("./textures/water/Water_002_OCC.jpg"); 59 | 60 | // PLANE 61 | const WIDTH = 30; 62 | const HEIGHT = 30; 63 | const geometry = new THREE.PlaneBufferGeometry(WIDTH, HEIGHT, 200, 200); 64 | const plane = new THREE.Mesh(geometry, 65 | new THREE.MeshStandardMaterial({ 66 | map: waterBaseColor, 67 | normalMap: waterNormalMap, 68 | displacementMap: waterHeightMap, displacementScale: 0.01, 69 | roughnessMap: waterRoughness, roughness: 0, 70 | aoMap: waterAmbientOcclusion })); 71 | plane.receiveShadow = true; 72 | plane.castShadow = true; 73 | plane.rotation.x = - Math.PI / 2; 74 | plane.position.z = - 30; 75 | scene.add(plane); 76 | 77 | const count: number = geometry.attributes.position.count; 78 | const damping = 0.25; 79 | // ANIMATE 80 | function animate() { 81 | 82 | // SINE WAVE 83 | const now_slow = Date.now() / 400; 84 | for (let i = 0; i < count; i++) { 85 | const x = geometry.attributes.position.getX(i) 86 | const y = geometry.attributes.position.getY(i) 87 | 88 | const xangle = x + now_slow 89 | const xsin = Math.sin(xangle) * damping 90 | const yangle = y + now_slow 91 | const ycos = Math.cos(yangle) * damping 92 | 93 | geometry.attributes.position.setZ(i, xsin + ycos) 94 | } 95 | geometry.computeVertexNormals(); 96 | geometry.attributes.position.needsUpdate = true; 97 | 98 | renderer.render(scene, camera); 99 | requestAnimationFrame(animate); 100 | } 101 | document.body.appendChild(renderer.domElement); 102 | animate(); 103 | 104 | // RESIZE HANDLER 105 | function onWindowResize() { 106 | camera.aspect = window.innerWidth / window.innerHeight; 107 | camera.updateProjectionMatrix(); 108 | renderer.setSize(window.innerWidth, window.innerHeight); 109 | } 110 | window.addEventListener('resize', onWindowResize); 111 | } -------------------------------------------------------------------------------- /src/sphere_with_waves.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | export function sphere_with_waves() { 5 | // SCENE 6 | const scene = new THREE.Scene(); 7 | scene.background = new THREE.Color(0xa8def0); 8 | 9 | // CAMERA 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 11 | camera.position.y = 5; 12 | 13 | // RENDERER 14 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 15 | renderer.setSize(window.innerWidth, window.innerHeight); 16 | renderer.setPixelRatio(window.devicePixelRatio); 17 | renderer.shadowMap.enabled = true 18 | 19 | // CONTROLS 20 | const controls = new OrbitControls(camera, renderer.domElement); 21 | controls.target = new THREE.Vector3(0, 0, -40); 22 | controls.update(); 23 | 24 | // AMBIENT LIGHT 25 | scene.add(new THREE.AmbientLight(0xffffff, 0.5)); 26 | // DIRECTIONAL LIGHT 27 | const dirLight = new THREE.DirectionalLight(0xffffff, 1.0) 28 | dirLight.position.x += 20 29 | dirLight.position.y += 20 30 | dirLight.position.z += 20 31 | dirLight.castShadow = true 32 | dirLight.shadow.mapSize.width = 4096; 33 | dirLight.shadow.mapSize.height = 4096; 34 | const d = 10; 35 | dirLight.shadow.camera.left = - d; 36 | dirLight.shadow.camera.right = d; 37 | dirLight.shadow.camera.top = d; 38 | dirLight.shadow.camera.bottom = - d; 39 | dirLight.position.z = -25; 40 | 41 | let target = new THREE.Object3D(); 42 | target.position.z = -30; 43 | dirLight.target = target; 44 | dirLight.target.updateMatrixWorld(); 45 | 46 | dirLight.shadow.camera.lookAt(0, 0, -30); 47 | scene.add(dirLight); 48 | // scene.add(new THREE.CameraHelper(dirLight.shadow.camera)); 49 | 50 | 51 | // TEXTURES 52 | const textureLoader = new THREE.TextureLoader(); 53 | 54 | const waterBaseColor = textureLoader.load("./textures/water/Water_002_COLOR.jpg"); 55 | const waterNormalMap = textureLoader.load("./textures/water/Water_002_NORM.jpg"); 56 | const waterHeightMap = textureLoader.load("./textures/water/Water_002_DISP.png"); 57 | const waterRoughness = textureLoader.load("./textures/water/Water_002_ROUGH.jpg"); 58 | const waterAmbientOcclusion = textureLoader.load("./textures/water/Water_002_OCC.jpg"); 59 | 60 | // PLANE 61 | const geometry = new THREE.SphereBufferGeometry(6, 128, 128); 62 | const sphere = new THREE.Mesh(geometry, 63 | new THREE.MeshStandardMaterial({ 64 | map: waterBaseColor, 65 | normalMap: waterNormalMap, 66 | displacementMap: waterHeightMap, displacementScale: 0.01, 67 | roughnessMap: waterRoughness, roughness: 0, 68 | aoMap: waterAmbientOcclusion 69 | })); 70 | sphere.receiveShadow = true; 71 | sphere.castShadow = true; 72 | sphere.rotation.x = - Math.PI / 4; 73 | sphere.position.z = - 30; 74 | scene.add(sphere); 75 | 76 | const count: number = geometry.attributes.position.count; 77 | 78 | const position_clone = JSON.parse(JSON.stringify(geometry.attributes.position.array)) as Float32Array; 79 | const normals_clone = JSON.parse(JSON.stringify(geometry.attributes.normal.array)) as Float32Array; 80 | const damping = 0.2; 81 | 82 | // ANIMATE 83 | function animate() { 84 | const now = Date.now() / 200; 85 | 86 | // iterate all vertices 87 | for (let i = 0; i < count; i++) { 88 | // indices 89 | const ix = i * 3 90 | const iy = i * 3 + 1 91 | const iz = i * 3 + 2 92 | 93 | // use uvs to calculate wave 94 | const uX = geometry.attributes.uv.getX(i) * Math.PI * 16 95 | const uY = geometry.attributes.uv.getY(i) * Math.PI * 16 96 | 97 | // calculate current vertex wave height 98 | const xangle = (uX + now) 99 | const xsin = Math.sin(xangle) * damping 100 | const yangle = (uY + now) 101 | const ycos = Math.cos(yangle) * damping 102 | 103 | // set new position 104 | geometry.attributes.position.setX(i, position_clone[ix] + normals_clone[ix] * (xsin + ycos)) 105 | geometry.attributes.position.setY(i, position_clone[iy] + normals_clone[iy] * (xsin + ycos)) 106 | geometry.attributes.position.setZ(i, position_clone[iz] + normals_clone[iz] * (xsin + ycos)) 107 | } 108 | geometry.computeVertexNormals(); 109 | geometry.attributes.position.needsUpdate = true; 110 | 111 | renderer.render(scene, camera); 112 | requestAnimationFrame(animate); 113 | } 114 | document.body.appendChild(renderer.domElement); 115 | animate(); 116 | 117 | // RESIZE HANDLER 118 | function onWindowResize() { 119 | camera.aspect = window.innerWidth / window.innerHeight; 120 | camera.updateProjectionMatrix(); 121 | renderer.setSize(window.innerWidth, window.innerHeight); 122 | } 123 | window.addEventListener('resize', onWindowResize); 124 | } -------------------------------------------------------------------------------- /src/terrain_editor.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | export function terrain_editor() { 5 | // SCENE 6 | const scene = new THREE.Scene(); 7 | scene.background = new THREE.Color(0xa8def0); 8 | 9 | // CAMERA 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 11 | camera.position.y = 25; 12 | camera.position.z = 50; 13 | camera.position.x = -50; 14 | 15 | // RENDERER 16 | const renderer = new THREE.WebGLRenderer({ antialias: true }); 17 | renderer.setSize(window.innerWidth, window.innerHeight); 18 | renderer.setPixelRatio(window.devicePixelRatio); 19 | renderer.shadowMap.enabled = true 20 | 21 | // CONTROLS 22 | const controls = new OrbitControls(camera, renderer.domElement); 23 | controls.target = new THREE.Vector3(0, 0, -25); 24 | controls.update(); 25 | 26 | // AMBIENT LIGHT 27 | scene.add(new THREE.AmbientLight(0xffffff, 0.5)); 28 | // DIRECTIONAL LIGHT 29 | const dirLight = new THREE.DirectionalLight(0xffffff, 1.0) 30 | dirLight.position.x += 40 31 | dirLight.position.y += 60 32 | dirLight.position.z = -40 33 | dirLight.castShadow = true 34 | dirLight.shadow.mapSize.width = 4096; 35 | dirLight.shadow.mapSize.height = 4096; 36 | const d = 100; 37 | dirLight.shadow.camera.left = - d; 38 | dirLight.shadow.camera.right = d; 39 | dirLight.shadow.camera.top = d; 40 | dirLight.shadow.camera.bottom = - d; 41 | 42 | let target = new THREE.Object3D(); 43 | target.position.z = -20; 44 | dirLight.target = target; 45 | dirLight.target.updateMatrixWorld(); 46 | 47 | dirLight.shadow.camera.lookAt(0, 0, -30); 48 | scene.add(dirLight); 49 | // scene.add(new THREE.CameraHelper(dirLight.shadow.camera)); 50 | 51 | // TEXTURES 52 | const textureLoader = new THREE.TextureLoader(); 53 | 54 | const soilBaseColor = textureLoader.load("./textures/soil/Rock_Moss_001_basecolor.jpg"); 55 | const soilNormalMap = textureLoader.load("./textures/soil/Rock_Moss_001_normal.jpg"); 56 | const soilHeightMap = textureLoader.load("./textures/soil/Rock_Moss_001_height.png"); 57 | const soilRoughness = textureLoader.load("./textures/soil/Rock_Moss_001_roughness.jpg"); 58 | const soilAmbientOcclusion = textureLoader.load("./textures/soil/Rock_Moss_001_ambientOcclusion.jpg"); 59 | 60 | // PLANE 61 | const WIDTH = 100; 62 | const HEIGHT = 100; 63 | const geometry = new THREE.PlaneBufferGeometry(WIDTH, HEIGHT, 300, 300); 64 | const plane = new THREE.Mesh(geometry, 65 | new THREE.MeshStandardMaterial({ 66 | map: soilBaseColor, 67 | normalMap: soilNormalMap, 68 | displacementMap: soilHeightMap, displacementScale: 2, 69 | roughnessMap: soilRoughness, roughness: 0, 70 | aoMap: soilAmbientOcclusion 71 | })); 72 | plane.receiveShadow = true; 73 | plane.castShadow = true; 74 | plane.rotation.x = - Math.PI / 2; 75 | plane.position.z = - 30; 76 | scene.add(plane); 77 | 78 | // CLICK EVENT 79 | const raycaster = new THREE.Raycaster(); // create once 80 | const clickMouse = new THREE.Vector2(); // create once 81 | const vector3 = new THREE.Vector3(); // create once 82 | const MAX_CLICK_DISTANCE = 10 83 | window.addEventListener('click', event => { 84 | 85 | // THREE RAYCASTER 86 | clickMouse.x = (event.clientX / window.innerWidth) * 2 - 1; 87 | clickMouse.y = -(event.clientY / window.innerHeight) * 2 + 1; 88 | 89 | raycaster.setFromCamera(clickMouse, camera); 90 | const found = raycaster.intersectObjects(scene.children); 91 | if (found.length > 0 && (found[0].object as THREE.Mesh).geometry) { 92 | const mesh = found[0].object as THREE.Mesh 93 | const geometry = mesh.geometry 94 | const point = found[0].point 95 | 96 | for (let i = 0; i < geometry.attributes.position.count; i++) { 97 | vector3.setX(geometry.attributes.position.getX(i)) 98 | vector3.setY(geometry.attributes.position.getY(i)) 99 | vector3.setZ(geometry.attributes.position.getZ(i)) 100 | const toWorld = mesh.localToWorld(vector3) 101 | 102 | const distance = point.distanceTo(toWorld) 103 | if (distance < MAX_CLICK_DISTANCE) { 104 | geometry.attributes.position.setZ(i, geometry.attributes.position.getZ(i) + (MAX_CLICK_DISTANCE - distance) / 2) 105 | } 106 | } 107 | geometry.computeVertexNormals() 108 | geometry.attributes.position.needsUpdate = true 109 | } 110 | }) 111 | 112 | // ANIMATE 113 | function animate() { 114 | renderer.render(scene, camera); 115 | requestAnimationFrame(animate); 116 | } 117 | document.body.appendChild(renderer.domElement); 118 | animate(); 119 | 120 | // RESIZE HANDLER 121 | function onWindowResize() { 122 | camera.aspect = window.innerWidth / window.innerHeight; 123 | camera.updateProjectionMatrix(); 124 | renderer.setSize(window.innerWidth, window.innerHeight); 125 | } 126 | window.addEventListener('resize', onWindowResize); 127 | } --------------------------------------------------------------------------------