A Pen by Faked Weiss on CodePen.
Created
December 19, 2023 15:10
-
-
Save FadedWeiss/071681f3a036fc168c16c6c6909d47d2 to your computer and use it in GitHub Desktop.
Terrain coloring without a shader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script async src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js" crossorigin="anonymous"></script> | |
<script type="importmap"> | |
{ | |
"imports": { | |
"three": "https://unpkg.com/[email protected]/build/three.module.js", | |
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/" | |
} | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://discourse.threejs.org/t/... | |
import * as THREE from "three"; | |
import { OrbitControls } from "three/addons/controls/OrbitControls.js"; | |
import { SimplexNoise } from "three/addons/math/SimplexNoise.js"; | |
// general setup, boring, skip to the next comment | |
console.clear( ); | |
var scene = new THREE.Scene(); | |
scene.background = new THREE.Color( 'gainsboro' ); | |
var camera = new THREE.PerspectiveCamera( 30, innerWidth/innerHeight ); | |
camera.position.set( 0, 5, 8 ); | |
camera.lookAt( scene.position ); | |
var renderer = new THREE.WebGLRenderer( {antialias: true} ); | |
renderer.setSize( innerWidth, innerHeight ); | |
renderer.setAnimationLoop( animationLoop ); | |
document.body.appendChild( renderer.domElement ); | |
window.addEventListener( "resize", (event) => { | |
camera.aspect = innerWidth/innerHeight; | |
camera.updateProjectionMatrix( ); | |
renderer.setSize( innerWidth, innerHeight ); | |
}); | |
var controls = new OrbitControls( camera, renderer.domElement ); | |
controls.enableDamping = true; | |
controls.autoRotate = true; | |
var light = new THREE.DirectionalLight( 'white', 3 ); | |
light.position.set( 0, 1, 0 ); | |
scene.add( light ); | |
// next comment | |
// create an elevation texture | |
var canvas = document.createElement( 'CANVAS' ); | |
canvas.width = 16; | |
canvas.height = 128; | |
var context = canvas.getContext( '2d' ), | |
gradient = context.createLinearGradient( 0, 0, 0, canvas.height ); | |
gradient.addColorStop( 0.200, 'black' ); | |
gradient.addColorStop( 0.330, 'blue' ); | |
gradient.addColorStop( 0.345, 'royalblue' ); | |
gradient.addColorStop( 0.350, 'yellow' ); | |
gradient.addColorStop( 0.351, 'forestgreen' ); | |
gradient.addColorStop( 0.700, 'seagreen' ); | |
gradient.addColorStop( 0.800, 'darkseagreen' ); | |
gradient.addColorStop( 0.900, 'white' ); | |
context.fillStyle = gradient; | |
context.fillRect( 0, 0, canvas.width, canvas.height ); | |
var elevationTexture = new THREE.CanvasTexture( canvas ); | |
// some terrain with overlapping simlpex noise | |
const NX = 300, // granularity | |
NY = 200; | |
var geometry = new THREE.PlaneGeometry( 6, 4, NX, NY ), | |
pos = geometry.getAttribute( 'position' ), | |
nor = geometry.getAttribute( 'normal' ), | |
uv = geometry.getAttribute( 'uv' ); | |
var terrain = new THREE.Mesh( | |
geometry, | |
new THREE.MeshPhysicalMaterial( { | |
roughness: 1, | |
metalness: 0, | |
side: THREE.DoubleSide, | |
map: elevationTexture, | |
} ) | |
); | |
terrain.rotation.x = -Math.PI/2; | |
scene.add( terrain ); | |
function randomTerrain( ) | |
{ | |
var simplex = new SimplexNoise( ); | |
// updat all vertices - Z coordinate and texture coordinate | |
for( var i=0; i<pos.count; i++ ) | |
{ | |
// vertex coordinates | |
var x = pos.getX( i ), | |
y = pos.getY( i ); | |
// calculate elevation | |
var z = 0.4*simplex.noise( 0.2*x, 0.2*y ) + | |
0.2*simplex.noise( 0.5*x, 0.5*y ) + | |
0.1*simplex.noise( 1.5*x, 1.5*y ); | |
// make mountains more spiky, undwewater more smooth | |
if( z>0 ) z = 4*z**2; else z = -(Math.abs(z)**2); | |
// add tiny shallow water effect | |
z = z + 0.003*simplex.noise( 50*x, 50*y ); | |
// shape vertical borders | |
if( Math.abs(x)==3 || Math.abs(y)==2 ) | |
z = -0.5; | |
else | |
if( Math.abs(x)>=3*(1-2/NX) || Math.abs(y)>=2*(1-2/NY) ) | |
z = 0; | |
pos.setZ( i, z ); | |
uv.setXY( i, 0, THREE.MathUtils.mapLinear( z, -0.5,1,1,0) ); | |
} // for i | |
// make sides black | |
geometry.computeVertexNormals( ); | |
for( var i=0; i<nor.count; i++ ) | |
{ | |
var x = pos.getX( i ), | |
y = pos.getY( i ); | |
if( Math.abs(x)>=3*(1-2/NX) || Math.abs(y)>=2*(1-2/NY) ) | |
nor.setXYZ( i, 0, 0, 0 ); | |
} | |
// register all updates | |
pos.needsUpdate = true; | |
nor.needsUpdate = true; | |
uv.needsUpdate = true; | |
} // randomTerrain | |
// that's all folks | |
// now generate some terrain | |
randomTerrain( ); | |
// and keep regenerating it ... | |
setInterval( randomTerrain, 2000 ); | |
function animationLoop( t ) | |
{ | |
controls.update( ); | |
renderer.render( scene, camera ); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
overflow: hidden; | |
margin: 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment