Skip to content

Instantly share code, notes, and snippets.

@ChanMenglin
Created November 13, 2018 01:42
Show Gist options
  • Save ChanMenglin/4abe8b936927ae52ff8a80b903c14ccf to your computer and use it in GitHub Desktop.
Save ChanMenglin/4abe8b936927ae52ff8a80b903c14ccf to your computer and use it in GitHub Desktop.
LAYERSCAPE
<script id="custom-vertex" type="x-shader/x-vertex">
//
// GLSL textureless classic 3D noise "cnoise",
// with an RSL-style periodic variant "pnoise".
// Author: Stefan Gustavson (stefan.gustavson@liu.se)
// Version: 2011-10-11
//
// Many thanks to Ian McEwan of Ashima Arts for the
// ideas for permutation and gradient selection.
//
// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
// Distributed under the MIT license. See LICENSE file.
// https://github.com/stegu/webgl-noise
//
vec3 mod289(vec3 x)
{
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x)
{
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x)
{
return mod289(((x*34.0)+1.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
vec3 fade(vec3 t) {
return t*t*t*(t*(t*6.0-15.0)+10.0);
}
// Classic Perlin noise
float cnoise(vec3 P)
{
vec3 Pi0 = floor(P); // Integer part for indexing
vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
Pi0 = mod289(Pi0);
Pi1 = mod289(Pi1);
vec3 Pf0 = fract(P); // Fractional part for interpolation
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
vec4 iy = vec4(Pi0.yy, Pi1.yy);
vec4 iz0 = Pi0.zzzz;
vec4 iz1 = Pi1.zzzz;
vec4 ixy = permute(permute(ix) + iy);
vec4 ixy0 = permute(ixy + iz0);
vec4 ixy1 = permute(ixy + iz1);
vec4 gx0 = ixy0 * (1.0 / 7.0);
vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
gx0 = fract(gx0);
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
vec4 sz0 = step(gz0, vec4(0.0));
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
vec4 gx1 = ixy1 * (1.0 / 7.0);
vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
gx1 = fract(gx1);
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
vec4 sz1 = step(gz1, vec4(0.0));
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
g000 *= norm0.x;
g010 *= norm0.y;
g100 *= norm0.z;
g110 *= norm0.w;
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
g001 *= norm1.x;
g011 *= norm1.y;
g101 *= norm1.z;
g111 *= norm1.w;
float n000 = dot(g000, Pf0);
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
float n111 = dot(g111, Pf1);
vec3 fade_xyz = fade(Pf0);
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
return 2.2 * n_xyz;
}
// Classic Perlin noise, periodic variant
float pnoise(vec3 P, vec3 rep)
{
vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period
vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period
Pi0 = mod289(Pi0);
Pi1 = mod289(Pi1);
vec3 Pf0 = fract(P); // Fractional part for interpolation
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
vec4 iy = vec4(Pi0.yy, Pi1.yy);
vec4 iz0 = Pi0.zzzz;
vec4 iz1 = Pi1.zzzz;
vec4 ixy = permute(permute(ix) + iy);
vec4 ixy0 = permute(ixy + iz0);
vec4 ixy1 = permute(ixy + iz1);
vec4 gx0 = ixy0 * (1.0 / 7.0);
vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
gx0 = fract(gx0);
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
vec4 sz0 = step(gz0, vec4(0.0));
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
vec4 gx1 = ixy1 * (1.0 / 7.0);
vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
gx1 = fract(gx1);
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
vec4 sz1 = step(gz1, vec4(0.0));
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
g000 *= norm0.x;
g010 *= norm0.y;
g100 *= norm0.z;
g110 *= norm0.w;
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
g001 *= norm1.x;
g011 *= norm1.y;
g101 *= norm1.z;
g111 *= norm1.w;
float n000 = dot(g000, Pf0);
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
float n111 = dot(g111, Pf1);
vec3 fade_xyz = fade(Pf0);
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
return 2.2 * n_xyz;
}
#define PHYSICAL
varying vec3 vViewPosition;
#ifndef FLAT_SHADED
varying vec3 vNormal;
#endif
#include <common>
#include <uv_pars_vertex>
#include <uv2_pars_vertex>
#include <displacementmap_pars_vertex>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <shadowmap_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
uniform float time;
uniform float maxHeight;
uniform float speed;
uniform float distortCenter;
uniform float ticknessOffset;
varying float vDisplace;
varying vec4 color;
void main() {
float t = time * speed;
float wRoad = distortCenter;
float wRoad2 = wRoad * 0.5;
float angleCenter = uv.y * PI*4.0;
angleCenter += t * 0.9;
float centerOff = (
sin(angleCenter) +
sin(angleCenter*0.5)
) * wRoad;
vec3 noiseIn = vec3(uv, 1.0)*20.0;
float noise = cnoise(vec3(noiseIn.x, noiseIn.y + t, noiseIn.z));
noise += 1.0;
float h = noise;
float angle = (uv.x - centerOff) * PI;
float f = abs(cos(angle));
h *= pow(f, 1.5 + ticknessOffset);
// water
/*if(h < 0.02){
float am = 8.0;
h += cnoise(vec3(noiseIn.x*am, noiseIn.y*am + t*4.0, noiseIn.z*am)) * 0.01;
}*/
vDisplace = h;
h*=maxHeight;
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
// #include <beginnormal_vertex>
vec3 objectNormal = vec3( normal.x, normal.y, normal.z );
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
#include <defaultnormal_vertex>
#ifndef FLAT_SHADED
vNormal = normalize( transformedNormal );
#endif
//#include <begin_vertex>
vec3 transformed = vec3( position.x, position.y, position.z + h );
#include <morphtarget_vertex>
#include <skinning_vertex>
#include <displacementmap_vertex>
#include <project_vertex>
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
vViewPosition = - mvPosition.xyz;
#include <worldpos_vertex>
#include <shadowmap_vertex>
#include <fog_vertex>
}
</script>
<script id="custom-fragment" type="x-shader/x-fragment">
#define PHYSICAL
uniform vec3 diffuse;
uniform vec3 emissive;
uniform float roughness;
uniform float metalness;
uniform float opacity;
#ifndef STANDARD
uniform float clearCoat;
uniform float clearCoatRoughness;
#endif
varying vec3 vViewPosition;
#ifndef FLAT_SHADED
varying vec3 vNormal;
#endif
#include <common>
#include <packing>
#include <dithering_pars_fragment>
#include <color_pars_fragment>
#include <uv_pars_fragment>
#include <uv2_pars_fragment>
#include <map_pars_fragment>
#include <alphamap_pars_fragment>
#include <aomap_pars_fragment>
#include <lightmap_pars_fragment>
#include <emissivemap_pars_fragment>
#include <bsdfs>
#include <cube_uv_reflection_fragment>
#include <envmap_pars_fragment>
#include <envmap_physical_pars_fragment>
#include <fog_pars_fragment>
#include <lights_pars_begin>
#include <lights_physical_pars_fragment>
#include <shadowmap_pars_fragment>
#include <bumpmap_pars_fragment>
#include <normalmap_pars_fragment>
#include <roughnessmap_pars_fragment>
#include <metalnessmap_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
}
uniform float time;
uniform sampler2D pallete;
varying float vDisplace;
varying vec4 color;
void main() {
vec2 stripPos = vec2( 0.0, vDisplace );
vec4 stripColor = texture2D( pallete, stripPos );
stripColor *= pow(1.0-vDisplace, 1.0);
// gl_FragColor *= vec4(stripColor.rgb, 1.0);
#include <clipping_planes_fragment>
vec4 diffuseColor = vec4( diffuse * stripColor.rgb, opacity );
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
vec3 totalEmissiveRadiance = emissive;
#include <logdepthbuf_fragment>
#include <map_fragment>
#include <color_fragment>
#include <alphamap_fragment>
#include <alphatest_fragment>
#include <roughnessmap_fragment>
#include <metalnessmap_fragment>
#include <normal_fragment_begin>
#include <normal_fragment_maps>
#include <emissivemap_fragment>
#include <lights_physical_fragment>
#include <lights_fragment_begin>
#include <lights_fragment_maps>
#include <lights_fragment_end>
#include <aomap_fragment>
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
#include <tonemapping_fragment>
#include <encodings_fragment>
#include <fog_fragment>
#include <premultiplied_alpha_fragment>
#include <dithering_fragment>
}
</script>
<h5 class="message">DRAG ME!</h5>
<a class="experiment-url" href="https://lab.ma77os.com/layerscape" target="_blank">source: lab.ma77os.com/layerscape</a>
var isInteractive = true;
var width, height;
var scene, camera, renderer, light;
var controls;
var terrain;
var cubemapRT, cubeRenderTarget;
var composer;
var message = document.querySelector(".message")
var hammer;
var mouse = {x:0, y:0};
var isMobile = typeof window.orientation !== 'undefined'
var palleteBlack = {
colors:[
{ c: "#111111", l:5 },
{ c: "#ed254e", l:1 },
{ c: "#f9dc5c", l:1 },
{ c: "#c2eabd", l:1 },
{ c: "#011936", l:1 },
{ c: "#465362", l:1 },
],
topColor:null,
repeat:10,
shuffle:true,
texture:null,
}
var palleteObj = palleteBlack
function init(){
textureLoader = new THREE.TextureLoader();
palleteObj.texture = textureLoader.load(createPalleteImg(palleteObj))
build()
}
var bl = true
function build(){
setup();
elements();
if(isInteractive){
hammer = new Hammer(document.body)
hammer.get('pinch').set({ enable: true });
hammer.on('pinch', function(ev) {
c.yd = ev.scale
});
message.innerHTML = isMobile ? "DRAG AND PINCH!" : "MOVE!"
message.style.display = "block"
window.addEventListener(isMobile ? "touchstart" : "mousemove", function(){
message.style.display = "none"
})
}
render();
if(isMobile)
window.addEventListener("touchmove", mousemove, {passive:false})
else
window.addEventListener("mousemove", mousemove)
window.addEventListener("resize", resize)
resize()
}
function setup(){
scene = new THREE.Scene();
var fogColor = new THREE.Color( 0xffffff )
scene.background = fogColor;
scene.fog = new THREE.Fog(fogColor, 10, 400);
sky()
camera = new THREE.PerspectiveCamera(60, width / height, .1, 10000);
camera.position.y = 8;
camera.position.z = 4;
ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambientLight)
renderer = new THREE.WebGLRenderer( {antialias:true} );
renderer.setPixelRatio = devicePixelRatio;
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement)
}
function sky(){
sky = new THREE.Sky();
sky.scale.setScalar( 450000 );
sky.material.uniforms.turbidity.value = 20;
sky.material.uniforms.rayleigh.value = 0;
sky.material.uniforms.luminance.value = 1;
sky.material.uniforms.mieCoefficient.value = 0.01;
sky.material.uniforms.mieDirectionalG.value = 0.8;
scene.add( sky );
sunSphere = new THREE.Mesh(
new THREE.SphereBufferGeometry( 20000, 16, 8 ),
new THREE.MeshBasicMaterial( { color: 0xffffff } )
);
sunSphere.visible = false;
scene.add( sunSphere );
var theta = Math.PI * ( -0.02 );
var phi = 2 * Math.PI * ( -.25 );
sunSphere.position.x = 400000 * Math.cos( phi );
sunSphere.position.y = 400000 * Math.sin( phi ) * Math.sin( theta );
sunSphere.position.z = 400000 * Math.sin( phi ) * Math.cos( theta );
sky.material.uniforms.sunPosition.value.copy( sunSphere.position );
}
function elements(){
var w= 100
var h = 400
var geometry = new THREE.PlaneBufferGeometry(w, h,400, 400);
var colorsBuffer = new Float32Array(geometry.attributes.position.count * 3)
for ( var i = 0; i < colorsBuffer.length; i++ ) {
colorsBuffer[ i ] = Math.random()
}
geometry.addAttribute( 'vColor', new THREE.BufferAttribute( colorsBuffer, 3 ) );
var displaceBuffer = new Float32Array( geometry.attributes.position.count );
for ( var i = 0; i < displaceBuffer.length; i++ ) {
displaceBuffer[ i ] = Math.random()
}
geometry.addAttribute( 'vDisplace', new THREE.BufferAttribute( displaceBuffer, 1 ) );
var material = new MeshCustomMaterial(
{
roughness:.7,
metalness:0.1
},
{
time: { type: "f", value: 0.0 },
distortCenter: { type: "f", value: 0.1 },
ticknessOffset: { type: "f", value: 0.0 },
pallete:{ type: "t", value: null},
speed: { type: "f", value: 2.0 },
maxHeight: { type: "f", value: 10.0 },
},
document.getElementById("custom-vertex").textContent,
document.getElementById("custom-fragment").textContent
);
terrain = new THREE.Mesh(geometry, material);
terrain.position.y = h/2;
container = new THREE.Object3D();
container.add(terrain)
container.position.y = 0
container.position.z = 4
container.rotation.x = -Math.PI / 2
scene.add(container)
}
function createPalleteImg(palleteObj){
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var pallete = expandPallete(palleteObj)
var texH = 1024;
var colorH = texH / pallete.length;
canvas.width = 2;
canvas.height = texH
for(var i=0; i < pallete.length; i++){
ctx.fillStyle = pallete[i];
ctx.fillRect(0, colorH * i, canvas.width, colorH)
}
return canvas.toDataURL()
}
function expandPallete(palleteObj){
var pallete = []
for(var x=0; x < palleteObj.repeat; x++){
for(var i=0; i < palleteObj.colors.length; i++){
var colors = palleteObj.shuffle ? shuffle(palleteObj.colors.slice()) : palleteObj.colors;
var c = colors[i];
for(var j=0; j < c.l; j++){
pallete.push(c.c);
}
}
}
if(palleteObj.topColor){
pallete.push(palleteObj.topColor);
}
return pallete
}
function shuffle(o) {
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
var c = {x:0, y:0, xd:0, yd:0};
function render(){
requestAnimationFrame(render)
var time = performance.now() * 0.001
terrain.material.uniforms.pallete.value = palleteObj.texture;
terrain.material.uniforms.time.value = time;
if(isInteractive){
c.xd = (mouse.x)*0.2;
if(!isMobile)
c.yd = mouse.y*5;
if(c.yd < -.5) c.yd = -.5;
c.x += (c.xd - c.x) * 0.08
c.y += (c.yd - c.y) * 0.08
terrain.material.uniforms.distortCenter.value = c.x;
terrain.material.uniforms.ticknessOffset.value = c.y;
}
if(Math.sin(time + Math.PI) > 0.99){
palleteObj.texture = textureLoader.load(createPalleteImg(palleteObj))
}
renderer.render(scene, camera)
}
function mousemove(e){
e.preventDefault();
var x, y
if(e.type == "mousemove"){
x = e.clientX;
y = e.clientY;
}else{
x = e.changedTouches[0].clientX
y = e.changedTouches[0].clientY
}
mouse.x = (x / width) - 0.5
mouse.y = (y / height) - 0.5
}
function resize(){
width = window.innerWidth
height = window.innerHeight
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
function MeshCustomMaterial (parameters, uniforms, vertexShader, fragmentShader) {
THREE.MeshStandardMaterial.call( this );
this.uniforms = THREE.UniformsUtils.merge([
THREE.ShaderLib.standard.uniforms,
uniforms
]);
this.vertexShader = vertexShader;
this.fragmentShader = fragmentShader;
this.type = 'MeshCustomMaterial';
this.setValues(parameters);
}
MeshCustomMaterial.prototype = Object.create( THREE.MeshStandardMaterial.prototype );
MeshCustomMaterial.prototype.constructor = MeshCustomMaterial;
MeshCustomMaterial.prototype.isMeshStandardMaterial = true;
window.onload = init
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.min.js"></script>
<script src="https://threejs.org/examples/js/objects/Sky.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
html, body {
height: 100%;
width: 100%;
overflow: hidden;
margin:0;
font-family:Arial;
color:white;
}
a:link, a:hover, a:visited, a:active{
color:white;
text-decoration: none;
}
.message{
padding:20px;
position:absolute;
display: none;
top:50%;
left:50%;
transform:translate(-50%, -50%);
background:black;
}
.experiment-url{
position:absolute;
bottom:10px;
right:10px;
padding:8px;
z-index: 1;
font-size: 11px;
background:black;
letter-spacing:0.5px;
border: 1px solid white;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment