Skip to content

Instantly share code, notes, and snippets.

@mkeresty
Created July 5, 2022 20:52
Show Gist options
  • Save mkeresty/d1f104a7db7fed3272d82d6bd972d9fd to your computer and use it in GitHub Desktop.
Save mkeresty/d1f104a7db7fed3272d82d6bd972d9fd to your computer and use it in GitHub Desktop.
rotating Earth with animated meshwork around
<canvas id="earth"></canvas>
//(function(){
var AMOUNT=200, d=25, R=200, adjustment=true, adaptive=true,
obliquity=23/180*3.14, roV1=.0022, roV2=-.0005, ro1=0, ro2=0,
canvas='#earth', color='#420236', fogC='#73C8B2', T_earth='https://mapplix.github.io/earth/earth.png';
var camera, scene, renderer;
var positions=[], particles, particle, count = 0, dpr, lastW,
W=window.innerWidth, H=window.innerHeight, aspect=W / H, vMin=Math.min(W,H);
var mouseX = 0, mouseY = 0, x0, y0;
var lookAt=new THREE.Vector3(0, 0, 0), canvas=document.querySelector(canvas);
renderer = new THREE.WebGLRenderer({alpha:true, antialias:true, canvas: canvas});//
renderer.setSize( W, H );
//renderer.context.getExtension('OES_standard_derivatives');
camera = new THREE.PerspectiveCamera( 18, aspect, 1, 10000 );
scene = new THREE.Scene();
var Emap = (new THREE.TextureLoader()).load( T_earth );
Emap.anisotropy=Math.min(8, renderer.capabilities.getMaxAnisotropy())||1;
var Wmaterial = new THREE.MeshStandardMaterial({
onBeforeCompile: function(sh){
sh.vertexShader='\
#define MYSHADER\n\
attribute float center, bright;\n\
varying vec3 vCenter, vPos, vV0, vV1, vV2;\n\
varying float vBright;\n\
' +sh.vertexShader.replace(/}\s*$/, '\
vBright=bright;\n\
int c=int(center);\n\
vCenter = vec3(c==0, c==1, c==2);\n\
vPos=position;\n\
gl_Position = projectionMatrix * modelViewMatrix * vec4(vPos, 1);\n\
vV0=vCenter[0]*vPos;\n\
vV1=vCenter[1]*vPos;\n\
vV2=vCenter[2]*vPos;\n\
}\ ');
sh.fragmentShader='\
#define MYSHADER\n\
varying vec3 vCenter, vPos, vV0, vV1, vV2;\n\
varying float vBright;\n\
' +sh.fragmentShader.replace('#include <alphamap_fragment>', '\
#include <alphamap_fragment>\n\
vec3 d = fwidth( vCenter );\n\
vec3 a3 = smoothstep( vec3(0.0), d * 1.4, vCenter+0.4*d-1.0/fogDepth );\n\
float scale = dot(normalize(vViewPosition), vNormal);\n\
scale = 1.0-scale*scale;\n\
float dist = distance(vPos, vV0.xyz/vCenter.x);\n\
dist = min(dist, distance(vPos, vV1.xyz/vCenter.y));\n\
dist = min(dist, distance(vPos, vV2.xyz/vCenter.z));\n\
float b3 = smoothstep(1.5, 1.8, dist-1.5*scale*scale );\n\
float edgeFactorTri=min(b3,min( min( a3.x, a3.y ), a3.z ));\n\
diffuseColor.a *= mix( 1.0, 0.0, edgeFactorTri );\n\
float dissipation='+(posZ+.5*R+.01)+';\n\
diffuseColor.a *= smoothstep( 20.0, 0.0, fogDepth-dissipation );\n\
\ ').replace(' #include <fog_fragment>', '\
float lVc=length(vCenter);\n\
gl_FragColor.rgb *= smoothstep( '+R*.8888+', '+R*1.201+', fogDepth );\n\
gl_FragColor.rgb = mix( gl_FragColor.rgb, vec3(3), (.1*lVc+pow(lVc,8.0))*vBright );\n\
#include <fog_fragment>\
\ ');
//console.log(sh, sh.vertexShader, sh.fragmentShader);
},
roughness: .5,
metalness: .964,
envMapIntensity:5,
emissive: 0,
// refractionRatio: -0.12,
transparent: true, alphaTest: 0.05
});//, opacity: 0
Wmaterial.color.set(fogC);
Wmaterial.side=2;
Wmaterial.extensions={derivatives: 1};
var geometry = new THREE.IcosahedronGeometry(R,3);//OctahedronGeometry
for ( var i = 0; i < geometry.vertices.length; i ++ ) {
geometry.vertices[i].applyEuler(new THREE.Euler(Math.random()*.06,Math.random()*.06,Math.random()*.06))
}
var bGeometry=(new THREE.BufferGeometry).fromGeometry(geometry);
var position = bGeometry.attributes.position;
var centers = new Int8Array( position.count );
var brights = new Float32Array ( position.count );
var points=[], activePoints=[], vCount=geometry.vertices.length, dCount=0, dMid=0;
for ( var i = 0, l = position.count; i < l; i ++ ) {
var c =centers[i]= i % 3, j=(i-c)/3;
brights[i]=0;
if (i<vCount) points[i]={siblings:[], distances:[], indexes:[], brightness:0, v:0, a:0, f:0, dr:0, r:1};
}
function addSiblings(a,b,one){
if (points[a].siblings.indexOf(points[b])<0) {
points[a].pos=geometry.vertices[a].clone();
points[a].siblings.push(points[b]);
var d=geometry.vertices[a].distanceTo(geometry.vertices[b]);
points[a].distances.push(d);
dMid+=d; dCount++;
}
if (!one) addSiblings(b,a,1)
}
geometry.faces.forEach(function(face, i){
addSiblings(face.a,face.b);
addSiblings(face.a,face.c);
addSiblings(face.c,face.b);
points[face.a].indexes.push(i*3);
points[face.b].indexes.push(i*3+1);
points[face.c].indexes.push(i*3+2);
});
dMid/=dCount;
var ttl=10;
(function setActive(n){
if (!n) return
var i=parseInt(Math.random()*vCount)
if (geometry.vertices[i].z<-100) setActive()
else points[i].isActive=ttl, activePoints.push(points[i]);
setActive(n-1)
})(10);
bGeometry.addAttribute( 'center', new THREE.BufferAttribute( centers, 1 ) );
bGeometry.addAttribute( 'bright', new THREE.BufferAttribute( brights, 1 ) );
var Ematerial = Wmaterial.clone();
Ematerial.alphaMap=Emap; Ematerial.transparent=false; Ematerial.side=0;
var cubeCamera = new THREE.CubeCamera( 1, 2*R, 256 );
cubeCamera.position.z=.47*R
Ematerial.envMap=cubeCamera.renderTarget.texture;
Ematerial.envMap.minFilter = THREE.LinearMipMapLinearFilter;
Ematerial.envMap.mapping=THREE.CubeReflectionMapping;
var Earth = new THREE.Mesh(new THREE.IcosahedronGeometry(R*.77, 3), Ematerial)
var wGeometry=geometry.clone();
particles = new THREE.Group();
world = new THREE.Group();
var Net=new THREE.Mesh(bGeometry, Wmaterial);
particles.add(Net, Earth);//new THREE.Points(geometry, Pmaterial),
//particles.rotation.order='YXZ'
world.add(particles);
scene.add(world);
// POSITIONS :
var posZ = 1700; //distance to camera
//scene.position.set(-12,54,0);
//camera.position.y=camera.position.z=2000
scene.fog=new THREE.Fog(fogC, posZ-R/2, posZ+R);
hLight=new THREE.HemisphereLight('#fff', 0, 23)
world.add(hLight);
hLight.position.set(0,0,1)
// interactions
var dx, dy=dx=x0=y0=0, active, abc=['a', 'b', 'c'], movedPoints=[], activeF=[], ready,
raycaster=new THREE.Raycaster(),
mouse = new THREE.Vector2();
window.getWpos=function(){
return [scene.position, scene.rotation, camera]
}
function interact() {
mouse.x = ( x0 / W ) * 2 - 1;
mouse.y = - ( y0 / H ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
movedPoints.forEach(function(point, i){point.f=0});
activeF=[];
if (!active) return;
var inters=raycaster.intersectObject(Net)[0], ind, vert;
if (!inters) return;
point=Net.worldToLocal(inters.point.clone());
for (var i = 0; i < 3; i++) {
ind=inters.face[abc[i]];
if ( !points.some(function(p, i){return p.indexes.indexOf(ind)>=0 && (vert=i+'') }) ) return;
activeF[vert]=Math.max(1-point.distanceTo(points[vert].pos)/dMid, 0)*100
}
// console.log(activeF, points[vert]);
}
canvas.onpointerdown=canvas.onmousedown=canvas.ontouchstart=function(e){
active=e.changedTouches?e.changedTouches[0]:e;
x0=active.clientX;
y0=active.clientY;
e.preventDefault();
interact();
};
onpointermove=onmousemove=ontouchmove=function(e){
if (!active || !ready) return
if (!e.buttons) {
active=false;
return;
}
var touches=e.changedTouches;
if (active.identifier!==undefined && e.type!='touchmove') return;
if (touches) {
if (touches[0].identifier==active.identifier) e=touches[0]
else return
}
else {e.preventDefault()};
//if (e.type==mousemove && !e.which) return
dx=(5*dx+x0-(x0=e.clientX))/6;
dy=(5*dy+y0-(y0=e.clientY))/6;
//console.log(e.type, active.identifier, dx, x0)
interact();
ready=0;
};
onmouseup=onpointerup=ontouchup=ontouchcancel=onpointercancel=onblur=function(e){
active=false;
//console.log()
interact();
}
var t0=new Date()*1, dMax=80, dMin=1000/33, dT=1000/50, af, Pactive=[], m=3000000, k=400, k0=1, f0=.01, fv=1000,
posArr=bGeometry.attributes.position.array,
pUp=0, pDn=[], flTimer=[], vecTest=new THREE.Vector3(), transStart, pLast, transactions=[];
requestAnimationFrame(function animate() {
requestAnimationFrame( animate );
var t=new Date()*1, dt=t-t0;
if (dt<dMin) return; // !Eh ||
dt=Math.min(dt, dMax);
t0=t;
var dd=dt/dT;
var pos=canvas.getBoundingClientRect(), dY=window.innerHeight-document.documentElement.getBoundingClientRect().bottom;
if (pos.bottom<=0 || pos.top>=window.innerHeight) return;
if (dpr!=(dpr=window.devicePixelRatio) || W!=(W=window.innerWidth) || H!=(H=window.innerHeight)) {
vMin=Math.min(W,H);
renderer.setSize(W, H);
renderer.setPixelRatio( dpr );
camera.aspect=W/H;
camera.updateProjectionMatrix();
}
var addPoints=[];
activePoints.forEach(function(point, i){
var b=point.brightness;
if (point.isActive && (b+=(point.speed||.3)*(b+.05)*dd) >1) {//
point.siblings.forEach(function(s, j){
if ( activePoints.indexOf(s)>-1) return //console.log(11);
s.speed=3.7/point.distances[j];
//s.from=point;
if (s.isActive=(Math.random()>.6)) activePoints.push(s);
})
point.isActive=0;
} else if (!point.isActive && (b-=b*.056*dd) < 0.005) {
b=0;//point.from=
activePoints.splice(i,1)
}
point.brightness=b;
point.indexes.forEach(function(i){
brights[i]=b;
});
});
points.forEach(function(point, i){
var d=0;
point.siblings.forEach(function(s,j){d+=s.dr;});
d=d/point.siblings.length-point.dr;
point.f=-(activeF[i]||0)*.4+d*k-point.dr*k0*(1+Math.abs(1-point.r))-point.v*fv;
point.v+=point.f*dt/m;
point.r=1+point.dr;
point.indexes.forEach(function(j){
//brights[i]+=point.f; return;
posArr[j*=3]=point.r*point.pos.x;
posArr[j+1]=point.r*point.pos.y;
posArr[j+2]=point.r*point.pos.z;
});
});
points.forEach(function(point, i){
if (!point.v) return;
var dd=point.v*dt;
point.dr+=dd;
});
bGeometry.attributes.bright.needsUpdate=true;
bGeometry.attributes.position.needsUpdate=true;
camera.position.z += (posZ - camera.position.z ) * .085*dd;
ro1+=roV1*dd; ro2+=roV2*dd;
particles.rotation.set(0,0,0);
particles.rotateY(ro2).rotateX(obliquity).rotateY(ro1);
particles.rotation.y-=.0009
dx*=(1-.03*dd);
dy*=(1-.03*dd);
ro2-=dx*.002;//+(W/2-y0)*(W/2-x0)*dy/vMin*.00004;
world.rotation.x-=dy*.002;
var sro=world.rotation.x*=.92;
Net.applyMatrix(new THREE.Matrix4().getInverse(particles.matrixWorld).multiply(
new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(-dy*.003, -dx*.002,0))
).multiply(particles.matrixWorld)//new THREE.Matrix4()
);
Earth.visible=!1;
scene.scale.set(.33,.33, .65)//.applyEuler(new THREE.Euler(-sro,0,0))
cubeCamera.update( renderer, scene );
Earth.visible=!0;
scene.scale.set(1,1,1)
particles.matrixWorldNeedsUpdate=true;
renderer.render( scene, camera );
ready=1;
})
//})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.min.js"></script>
html, body {
margin: 0px;
width: 100%; height: 100%;
}
a {
color:#73C8B2;
}
#earth {
position: fixed;
width: 100%; height:100%;
touch-action: manipulation;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment