1. 程式人生 > 其它 >3D物件蠕動

3D物件蠕動

技術標籤:# 幾何圖形3D物件蠕動

3D物件蠕動


更多有趣示例 盡在 知屋安磚社群

示例

在這裡插入圖片描述

HTML

<div id="blob">
    <canvas></canvas>
</div>


<div class="controls">
    <div>
        <label>Speed</label>
        <input type="range" min="10"
max="120" value="13" step="1" name="speed">
</div> <div> <label>Spikes</label> <input type="range" min=".05" max="2" value=".6" step=".05" name="spikes"
>
</div> <div> <label>Processing</label> <input type="range" min=".6" max="2.4" value="1" step=".01" name="processing"> </div> </div>

CSS

#blob {
    position: relative;
    canvas
{ width: 1000px; margin-top: -7%; @media(max-width: 1200px) { margin-top: -10%; width: 800px } @media(max-width: 600px) { width: 800px } } } .controls { background: #3F4656; display: flex; padding: 20px; border-radius: 10px; position: relative; z-index: 3; box-shadow: 0 4px 20px -1px rgba(18, 22, 33, .7); @media(max-width: 1200px) { margin-top: -4%; } @media(max-width: 600px) { flex-direction: column; } label { color: #CDD9ED; font-weight: 500; font-size: 14px; display: block; margin-bottom: 16px; @media(max-width: 600px) { margin-bottom: 12px; } } [type="range"] { width: 160px; @media(max-width: 600px) { width: 280px; } } & > div { &:not(:last-child) { margin-right: 20px; @media(max-width: 600px) { margin: 0 0 24px 0; } } } } .rangeSlider { position: relative; background: none; border: 1px solid #fff; border-radius: 6px; cursor: pointer; &.rangeSlider__horizontal { height: 10px; width: 160px; } .rangeSlider__fill { border-radius: 7px; background: #fff; position: absolute; &:before { content: ''; left: -2px; top: -2px; bottom: -2px; right: -2px; border: 2px solid #3F4656; border-radius: 6px; position: absolute; } } .rangeSlider__fill__horizontal { height: 100%; top: 0; left: 0; } .rangeSlider__handle { border: 2px solid #3F4656; cursor: grab; cursor: -moz-grab; cursor: -webkit-grab; display: inline-block; width: 22px; height: 22px; position: absolute; background: white; border-radius: 50%; } .rangeSlider__handle__horizontal { top: -7px; } } html { box-sizing: border-box; -webkit-font-smoothing: antialiased; } * { box-sizing: inherit; &:before, &:after { box-sizing: inherit; } } html, body { overflow: hidden; } // Center & dribbble body { min-height: 100vh; display: flex; justify-content: center; align-items: center; flex-direction: column; font-family: 'Source Sans Pro', Arial; background: #1c1f29; .dribbble { position: fixed; display: block; right: 20px; bottom: 20px; img { display: block; height: 28px; } } }

JS

for(let i = 0, element; element = document.querySelectorAll('input[type="range"]')[i++];) {
    rangeSlider.create(element, {
        polyfill: true
    });
}


$(document).ready(function() {


    let speedSlider = $('input[name="speed"]'),
        spikesSlider = $('input[name="spikes"]'),
        processingSlider = $('input[name="processing"]');


    let $canvas = $('#blob canvas'),
        canvas = $canvas[0],
        renderer = new THREE.WebGLRenderer({
            canvas: canvas,
            context: canvas.getContext('webgl2'),
            antialias: true,
            alpha: true
        }),
        simplex = new SimplexNoise();


    renderer.setSize($canvas.width(), $canvas.height());
    renderer.setPixelRatio(window.devicePixelRatio || 1);


    let scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(45, $canvas.width() / $canvas.height(), 0.1, 1000);


    camera.position.z = 5;


    let geometry = new THREE.SphereGeometry(.8, 128, 128);


    let material = new THREE.MeshPhongMaterial({
        color: 0xff0000,
        shininess: 100
    });


    let lightTop = new THREE.DirectionalLight(0xFFFFFF, .7);
    lightTop.position.set(0, 500, 200);
    lightTop.castShadow = true;
    scene.add(lightTop);


    let lightBottom = new THREE.DirectionalLight(0xFFFFFF, .25);
    lightBottom.position.set(0, -500, 400);
    lightBottom.castShadow = true;
    scene.add(lightBottom);


    let ambientLight = new THREE.AmbientLight(0x798296);
    scene.add(ambientLight);


    let sphere = new THREE.Mesh(geometry, material);


    scene.add(sphere);


    let update = () => {


        let time = performance.now() * 0.00001 * speedSlider.val() * Math.pow(processingSlider.val(), 3),
            spikes = spikesSlider.val() * processingSlider.val();


        for(let i = 0; i < sphere.geometry.vertices.length; i++) {
            let p = sphere.geometry.vertices[i];
            p.normalize().multiplyScalar(1 + 0.3 * simplex.noise3D(p.x * spikes, p.y * spikes, p.z * spikes + time));
        }


        sphere.geometry.computeVertexNormals();
        sphere.geometry.normalsNeedUpdate = true;
        sphere.geometry.verticesNeedUpdate = true;


    }


    function animate() {
        update();
        renderer.render(scene, camera);
        requestAnimationFrame(animate);
    }
    requestAnimationFrame(animate);
});