2 034 Codepen

Абстракция в пространстве

Абстракция на three.js и шейдерах


HTML & Shaders

<script type="x-shader/x-vertex" id="vertexshader">
    
    precision highp float;
    
    attribute float size;
    uniform vec4 planet1;
    uniform vec4 planet2;
    
    varying float vDisplay;
    varying float vColor;
    
    vec4 distanceTo(vec3 p1, vec4 p2){ // simple function that returns a vec4 of the distance between 3d points.  each position being that axis' distance.  the 4th position being the overall distance
        vec3 d = vec3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
        
        return vec4(abs(d.x),
                  abs(d.y),
                  abs(d.z),
                  sqrt(d.x*d.x + d.y*d.y + d.z*d.z));
    }
    
    void main() {
        vec3 p = position;
        
        float g = 5000.; // constant rate of gravity, I treat it sort of like a scaler

        vec4 distP1 = distanceTo(p, planet1); // get distance from point to planet
        //vec4 distP2 = distanceTo(p, planet2);

        vec3 vp1 = vec3(p.x - planet1.x, p.y - planet1.y, p.z - planet1.z); // find vector between point and planet (kind of like the angle between the two points)
        //vec3 vp2 = vec3(p.x - planet2.x, p.y - planet2.y, p.z - planet2.z);

        float pull = (g*planet1.w) / (distP1.w * distP1.w); // find the amount gravity is effecting this point
        vec3 newp = p.xyz + (-pull * vp1.xyz); // push the point towards the planet with the "angle" vector we made above, with the amount set in the pull variable
        
        //pull = (g*planet2.w) / (distP2.w * distP2.w);
        //newp = newp.xyz + (-pull * vp2.xyz);


        gl_PointSize = 1.;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(newp, 1.0);
        
        vDisplay = 0.;
        if(pull < 1.){ vDisplay = 1.; } // hide overly-pulled vertex's
        
        vColor = clamp(pull, 0.133333333, 1.);
    }
</script>

<script type="x-shader/x-fragment" id="fragmentshader">
    uniform sampler2D texture;
    uniform vec2 resolution;
    
    varying float vDisplay;
    varying float vColor;
    
    void main() {
        vec2 st = gl_FragCoord.xy/resolution.xy;
        st.x *= resolution.x/resolution.y;


        float c = clamp(vColor, 0.0, 0.4);
        
        gl_FragColor = vec4(c, c, c, vDisplay );
    }
</script>

CSS

html, body { 
    margin: 0; 
    overflow: hidden; 
    background-color: #222;
    display: flex;
    height: 100%;
    width: 100%;
}

canvas { 
    width: 100%; 
    height: 100%;
}

JS

Библиотека three.js
https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js
и скрипт абстракции
/*

    The main logic in this app is in the HTML tab
    within the Vertex Shader code

*/

var container = document.body;


var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, container.offsetWidth / container.offsetHeight, 0.1, 1000000 );

var uScale = container.offsetWidth / 178960000*80000;

var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( container.offsetWidth, container.offsetHeight );
container.appendChild( renderer.domElement );

var startTime = new Date().getTime();
var currentTime = 0;

var planetGeom = new THREE.SphereGeometry( Math.floor(6371*uScale), 32, 32 );
var planetMaterial = new THREE.MeshBasicMaterial( {color: 0xffffff} );
var planet1 = new THREE.Mesh( planetGeom, planetMaterial );

//planet1.mass = 0;

planet1.mass = 59720*uScale;
scene.add( planet1 );


var planetGeom = new THREE.SphereGeometry( Math.floor(1737*uScale), 32, 32 );
var planetMaterial = new THREE.MeshBasicMaterial( {color: 0xcccccc} );
var planet2 = new THREE.Mesh( planetGeom, planetMaterial );
planet2.dist = 384400*uScale;
planet2.mass = 735*uScale;
//scene.add( planet2 );

//    adding in multi-planet support (almost there)



var geometry = new THREE.BufferGeometry();

var uniforms = {
    time: { value: 1.0 },
    resolution: { value: new THREE.Vector2(container.offsetWidth, container.offsetHeight) },
    planet1: { value: new THREE.Vector4(planet1.position.x, planet1.position.y, planet1.position.z, planet1.mass) },
    planet2: { value: new THREE.Vector4(planet2.position.x, planet2.position.y, planet2.position.z, planet2.mass) }
}

var shaderMaterial = new THREE.ShaderMaterial( {
    uniforms:       uniforms,
    vertexShader:   document.getElementById('vertexshader').textContent,
    fragmentShader: document.getElementById('fragmentshader').textContent,
    blending:       THREE.AdditiveBlending,
    depthTest:      false,
    transparent:    true,
    vertexColors:   true
});

var pointDist = 1;
var lineScale = 50;
var scale = Math.floor(64*8);
var radius = Math.floor(196);
var geometry = new THREE.BufferGeometry();
var positions = [];
var sizes = [];

function mod(x,y){
    return x % y;
}

for ( var x = 0; x + pointDist < scale; x += pointDist) {
    for ( var y = 0; y + pointDist < scale; y += pointDist) {
        for ( var z = 0; z + pointDist < scale; z += pointDist) {
            if((mod(x, lineScale) < 1. && mod(y, lineScale) < 1.) || (mod(y, lineScale) < 1. && mod(z, lineScale) < 1.) || (mod(x, lineScale) < 1. && mod(z, lineScale) < 1.)){
                positions.push( (x - (scale/2)) * radius );
                positions.push( (y - (scale/2)) * radius );
                positions.push( (z - (scale/2)) * radius );
                sizes.push( 1 );
            }
        }
    }
}

geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
//geometry.addAttribute( 'sPosition', new THREE.Float32BufferAttribute( positions, 3 ) );
geometry.addAttribute( 'size', new THREE.Float32BufferAttribute( sizes, 1 ).setDynamic( true ) );
var spacetime = new THREE.Points( geometry, shaderMaterial );
spacetime.position.x = 0;
spacetime.position.y = 0;
spacetime.position.z = 0;
scene.add( spacetime );


camera.position.y = 0;
camera.position.x = 0;
camera.position.z = 20000;

function animate() {
    var now = new Date().getTime();
    currentTime = (now - startTime) / 1000;
    uniforms.time.value = currentTime;
    
    planet1.position.x = Math.cos(currentTime)*2000;
    planet1.position.y = Math.sin(-currentTime)*2000;
    
    
    planet2.position.x = planet1.position.x + Math.cos(currentTime)*planet2.dist * uScale;
    planet2.position.y = planet1.position.y + Math.sin(currentTime)*planet2.dist * uScale;
    
    uniforms.planet1.value = new THREE.Vector4(planet1.position.x, planet1.position.y, planet1.position.z, planet1.mass);
    uniforms.planet2.value = new THREE.Vector4(planet2.position.x, planet2.position.y, planet2.position.z, planet2.mass);

    scene.rotation.z += 0.0002;
    scene.rotation.y += 0.001;
    
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
}
animate();

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи