欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3D波动点网

程序员文章站 2022-04-02 10:03:30
...

3D波动点网

更多有趣示例 尽在小红砖社区

示例

3D波动点网

HTML

<a href="https://github.com/gnauhca/F3.js" target="_blank">view code on github</a>
<div class="controls">
  <div class="functions btn-group"></div>
  <div class="rotate btn-group">
    <div class="btn rotatex" data-rotate="x">rotatex</div>
    <div class="btn rotatey" data-rotate="y">rotatey</div>
    <div class="btn rotatez" data-rotate="z">rotatez</div>
  </div>
</div>
<canvas width="2560" height="1000" style="min-width: 1000px; width: 100%; position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%)"></canvas>

CSS

* {
    margin: 0;
    padding: 0;
}
body, html {
    width: 100%;
    height: 100%;
    position: relative;
}
body {
    background: radial-gradient(circle, rgb(109, 39, 23), #1E90FF);
}
canvas {
    pointer-events: none;
}
a,a:focus {
  position: fixed;
  top: 0;
  left: 0;
  margin: 25px;
  color : #ddd;
}
.controls {
    width: 500px;
    display: inline-block;
    position: absolute;
    top: 20px;
    left: 50%;
    transform: translate(-50%, 0);
}
.btn-group {
    display: inline-block;
}
.btn {
    display: inline-block;
    margin-bottom: 0;
    font-weight: 500;
    text-align: center;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    background-image: none;
    border: 1px solid transparent;
    white-space: nowrap;
    line-height: 1.5;
    padding: 4px 15px;
    font-size: 12px;
    border-radius: 0px;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-transition: all .3s cubic-bezier(.645,.045,.355,1);
    transition: all .3s cubic-bezier(.645,.045,.355,1);
    position: relative;
    color: rgba(0,0,0,.65);
    background-color: #fff;
    border-color: #d9d9d9;
}
.btn:first-child {
    border-radius: 4px 0 0 4px;
}
.btn:last-child {
    border-radius: 0 4px 4px 0;
}
.btn.active {
    color: #fff;
    background-color: #dc7953;
    border-color: #dc7953;
}

.rotate {
  margin-left: 20px;
}
.rotate .btn {
    border: none;
    border-radius: 20px;
}

JS

class Point extends F3.Obj {
    constructor(radius=5) {
        super();
        this.radius = radius;
        this.color = 'rgba('+[Math.random()*255|0,Math.random()*255|0,Math.random()*255|0, Math.random()].join(',')+')';
        this.prevCrood = null;
    }
    render(ctx) {

        ctx.fillStyle = '#fff';
        ctx.fillRect(
            this.croods2D.position.x, 
            this.croods2D.position.y,
            this.radius * this.croods2D.scale * this.yScale, 
            this.radius * this.croods2D.scale * this.yScale
        );
    }
}

let planeFunctions = {
    'sin(sqrt(x^2+z^2))': function(x, z, offset) {
        return Math.sin(Math.sqrt(Math.pow(x/2, 2)+Math.pow(z/2, 2)) - offset);
    },
  'cos(x)*sin(z)': function(x, z, offset) {
        return Math.cos(x/4 + offset)*Math.sin(z/4 + offset) * 1;
    },
};

class Effect extends F3.Time {
    constructor(renderer, scene, camera,  cvs) {
        super();
        this.renderer = renderer;
        this.scene = scene;
        this.camera = camera;
        this.cvs = cvs;
        
        this.xOffset = 0;
        this.waveHeight = 0.4; // 波高
        this.waveWidth = 8; // 波长

        this.col = 33;
        this.colPointNum = 33;
        
        this.flyTime = 2000;
        this.timePass = 0;

        this.scale = 1;
        this.scaleStep = 0.01;

        this.planeFunction = function() {return 0};
        this.rotate = {x: false, y: false, z:false}

        this.pointGroup = new F3.Obj();
        this.scene.add(this.pointGroup);

        this.resize(cvs.width, cvs.height);
        this.init();
    }
    resize(width, height) {
        this.cvs.width = width;
        this.cvs.height = height;
        // this.pointGroup.position.set(this.cvs.width/2, this.cvs.height, 0);
        this.stepWidth = width * 1.8 / this.col;
        this.pointGroup.setPosition(this.cvs.width/2, this.cvs.height * 1.2, -this.col * this.stepWidth/2);
        this.pointGroup.setRotation(0.1, 0, 0);
        // this.waveHeight = height/2;
        // this.waveWidth = this.waveHeight * 4;
        // console.log(this.stepWidth);
    }
    init() {
        // create point
        var point;
        for (let x = -(this.col - 1) / 2, count = 0; x <= (this.col - 1) / 2; x++) {
            for (let z = -(this.colPointNum-1) / 2; z <= (this.colPointNum-1) / 2 ; z++ ) {    
                point = new Point(10);
                this.pointGroup.add(point);
                /*point.initPos = new F3.Vector3(
                     x + Math.random() * -2 + 1,
                     -30 + -10 * Math.random(),
                     z + Math.random() * -2 + 1
                );*/
                point.initPos = new F3.Vector3(0,0,0);
                point.flyDelay = 0//Math.random() * 1000 | 0;
            }
        }
    }
    update(delta) {
        this.timePass += delta;
        this.xOffset = this.timePass / 500;

        let point;
        let flyPecent;
        let x,y,z;
        let count = 0;
        
        // if (this.timePass < 100)
        for (x = -(this.col - 1) / 2; x <= (this.col - 1) / 2; x++) {
            for (z = -(this.colPointNum-1) / 2; z <= (this.colPointNum-1) / 2 ; z++ ) {    

                // let y = Math.cos(x*Math.PI/this.waveWidth + this.xOffset)*Math.sin(z*Math.PI/this.waveWidth + this.xOffset) * this.waveHeight;
                
                y = this.planeFunction(x,z,this.xOffset);
                // let y = Math.sin(Math.sqrt(Math.pow(x/v, 2)+Math.pow(z/v, 2)) - this.xOffset) * 1
                // console.log(y);

                point = this.pointGroup.children[count]
                point.yScale = 1;//(-y + 0.6)/(this.waveHeight) * 1.5;

                flyPecent = (this.timePass-point.flyDelay) / this.flyTime;
                flyPecent = flyPecent > 1 ? 1: (flyPecent < 0? 0: flyPecent);

                point.setPosition(
                    x * this.stepWidth,
                    y * this.stepWidth,
                    z * this.stepWidth
                );
                count++;
            }
        }
        if (this.rotate.x || this.rotate.y || this.rotate.z) {
            this.pointGroup.setRotation(
                (this.rotate.x ? this.pointGroup.rotation.x + 0.001: 0),
                (this.rotate.y ? this.pointGroup.rotation.y + 0.001: 0),
                (this.rotate.z ? this.pointGroup.rotation.z + 0.001: 0)
            );
        }
    }
    setFunction(fun) {
        this.planeFunction = fun;
    }
    toggleRotate(r) {
        this.rotate[r] = !this.rotate[r];
        if (!this.rotate[r]) {
            this.pointGroup.rotation[r] = 0;
        }
    }
    animate() {
        this.addTick((delta)=>{
            this.update(delta);
            this.renderer.render(this.scene, this.camera);
        });
    }
}

function init(cvs) {
    let ctx = cvs.getContext('2d');

    let scene = new F3.Scene();
    let camera = new F3.Camera();
    camera.origin = new F3.Vector3(cvs.width/2, cvs.height/3);
    camera.p = 1200;

    let renderer = new F3.Renderer(ctx, cvs);
    let effect = new Effect(renderer, scene, camera, cvs);
    effect.animate();



    let functions = document.querySelector('.functions');
    let btnHTML = '';
    for (let name in planeFunctions) {
        btnHTML += `<div class="btn" data-function="${name}">${name}</div>`
    }
    functions.innerHTML = btnHTML;

    let btns = functions.querySelectorAll('.btn');
    function selectFunction(funName) {
        btns.forEach(function(btn) {
            let dataFunction = btn.dataset.function;
            if (dataFunction === funName) {
                btn.classList.add('active');
                effect.setFunction(planeFunctions[funName]);
            } else {
                btn.classList.remove('active');
            }
        });
    }
    selectFunction(btns[0].dataset.function)
    functions.addEventListener('click', function(e) {
        if (e.target.dataset.function) {
            selectFunction(e.target.dataset.function);
        }
    });

    let rotate = document.querySelector('.rotate');
    let rotateBtns = rotate.querySelectorAll('.btn');
    function toggleRotate(_r) {
        rotateBtns.forEach(function(rotateBtn) {
            let r = rotateBtn.dataset.rotate;
            if (r === _r) {
                rotateBtn.classList.toggle('active'); 
                effect.toggleRotate(r);
            } 
        });
    }
    toggleRotate('y')
    rotate.addEventListener('click', function(e) {
        if (e.target.dataset.rotate) {
            toggleRotate(e.target.dataset.rotate);
        }
    });

    F3.TIME.start();
}
init(document.querySelector('canvas'));

相关标签: # 页面布置