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);
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值