Earth (in THREE.js)
by PhilQ
HTML
<script type="x-shader/x-vertex" id="_vertexShader">
uniform vec2 resolution;
varying vec4 vPos;
varying vec3 vNormal;
varying vec2 vUv;
varying mat4 matModel;
varying mat4 matModelView;
varying mat4 matProjection;
varying mat3 matNormal;
void main() {
// Send to fragment shader
vNormal = normal;
vUv = uv;
vPos = vec4(position, 1.0);
matModel = modelMatrix;
matModelView = modelViewMatrix;
matProjection = projectionMatrix;
matNormal = normalMatrix;
// Local space (object)
gl_Position = vPos;
// to World space (scene)
gl_Position = modelMatrix * vPos;
// to View space (camera)
gl_Position = viewMatrix * modelMatrix * vPos;
// to Clip space
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vPos;
// Note: Three.js will convert to NDC space and then to Screen/Viewport space
}
</script>
<script type="x-shader/x-fragment" id="_fragmentShader">
uniform vec2 resolution;
varying vec4 vPos;
varying vec3 vNormal;
varying vec2 vUv;
varying mat4 matModel;
varying mat4 matModelView;
varying mat4 matProjection;
varying mat3 matNormal;
void main() {
vec4 localUv = vec4(vUv, 0.0, 1.0); // Local uv, bottom-left (0,0) to top-right (1,1)
vec4 localPos = vPos;
vec4 worldPos = matModel * vPos;
vec4 viewPos = viewMatrix * matModel * vPos;
vec4 clipPos = matProjection * viewMatrix * matModel * vPos;
vec4 ndcPos = vec4(clipPos.xyz / clipPos.w, clipPos.w); // Added w to be able to back-calculate to clip space
vec2 screenPos = (ndcPos.xy + 1.0) * 0.5; // Screen uv, bottom-left (0,0) to top-right (1,1)
vec2 viewportPos = vec2(screenPos.x, -screenPos.y); // Top-left (0,0) to bottom-right (1,1)
vec2 pixelPos = screenPos * resolution; // Actual pixel coordinates
// gl_FragColor = vec4(screenPos.xy, 0.0, 1.0);
// Basic color + lighting
vec4 color = vec4(1.0, 0.0, 1.0, 1.0);
vec3 light = normalize( vec3( 0.5, 0.2, 1.0 ) ); // Normalized direction (like sunlight)
float...
CSS
body { margin: 0; }
canvas { width: 100%; height: 100% }
#toggle {
position: fixed;
top: 0;
left: 0;
z-index: 10;
}
JavaScript
import * as THREE from 'three';
import { OrbitControls } from 'OrbitControls';
import { ConvexGeometry } from 'ConvexGeometry';
import * as BufferGeometryUtils from 'BufferGeometryUtils';
import { VertexNormalsHelper } from 'VertexNormalsHelper';
// Author: Fyrestar https://mevedia.com (https://github.com/Fyrestar/THREE.BufferGeometry-toIndexed)
THREE.BufferGeometry.prototype.toIndexed = function () {
let list = [], vertices = {};
let _src, attributesKeys, morphKeys;
let prec = 0, precHalf = 0, length = 0;
function floor( array, offset ) {
if ( array instanceof Float32Array ) {
return Math.floor( array[ offset ] * prec );
} else if ( array instanceof Float16Array ) {
return Math.floor( array[ offset ] * precHalf );
} else {
return array[ offset ];
}
}
function createAttribute( src_attribute ) {
const dst_attribute = new THREE.BufferAttribute( new src_attribute.array.constructor( length * src_attribute.itemSize ), src_attribute.itemSize );
const dst_array = dst_attribute.array;
const src_array = src_attribute.array;
switch ( src_attribute.itemSize ) {
case 1:
for ( let i = 0, l = list.length; i < l; i++ ) {
dst_array[ i ] = src_array[ list[ i ] ];
}
break;
case 2:
for ( let i = 0, l = list.length; i < l; i++ ) {
const index = list[ i ] * 2;
const offset = i * 2;
dst_array[ offset ] = src_array[ index ];
dst_array[ offset + 1 ] = src_array[ index + 1 ];
}
break;
case 3:
for ( let i = 0, l = list.length; i < l; i++ ) {
const index = list[ i ] * 3;
const offset = i * 3;
dst_array[ offset ] = src_array[ index ];
dst_array[ offset + 1 ] = src_array[ index + 1 ];
dst_array[ offset + 2 ] = src_array[ index + 2 ];
}
break;
case 4:
for ( let i = 0, l = list.length; i < l; i++ ) {
const index = list[ i ] * 4;
const offset = i * 4;
dst_array[ offset ] = src_array[ index ];
dst_array[...