地形threejs

地形threejs

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

示例

在这里插入图片描述

HTML

<div id="threejs"></div>

CSS

* {
 margin: 1px;
}

JS

var camera, scene, renderer, light, rectangles = [];

var raycaster, INTERSECTED;
var mouse, controls, stats;
var container;

var MOUSEDOWN, MOUSEUP, MOUSEBTN;

var RECT_SIZE = 25,
    RECT_HEIGHT = 256,
    GRID_SIZE = 27;
var NUM_CUBES = GRID_SIZE * GRID_SIZE;

var SHADOW_MAP_WIDTH = 2048,
    SHADOW_MAP_HEIGHT = 1024;

var guiOption = function () {
    this.color0 = "#ffae23";
    this.viewMode = 'Orbit Mode';
    this.brushType = 'Gaussian';
    this.brushSize = 1.0;
    this.brushMagnitude = 30;
    this.blurMagnitude = 0.13;
    this.orbitViewRadius = 400;
    this.orbitViewTheta = 0;
    this.reset = function () {
        reset();
    };
    this.toggleShadow = function () {
        castShadow();
    };
    this.castShadow = true;
    this.singleColor = function () {
        setSingleColor();
    };
    this.randomColor = function () {
        setRandomColor();
    };
};

var options = new guiOption();

$.ready(main());

function main() {
    setUpGUI();
    setUpStats(document.body);
    init();
    animate();
}

function init() {
    MOUSEDOWN = false;
    MOUSEUP = true;

    container = document.getElementById("threejs");

    document.body.appendChild(container);

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setClearColor(0xDEB887);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.sortObjects = false;
    renderer.shadowMapEnabled = true;
    renderer.shadowMapType = THREE.PCFShadowMap;

    container.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.z = 400;

    scene = new THREE.Scene();
    mouse = new THREE.Vector2();
    raycaster = new THREE.Raycaster();
    controls = new THREE.OrbitControls(camera, renderer.domElement);
    rectangles = [];

    // LIGHTS
    var ambient = new THREE.AmbientLight(0x444444);
    scene.add(ambient);
    light = new THREE.SpotLight(0xffffff, 1, 0, Math.PI / 2, 1);
    light.position.set(0, 1500, 1000);
    light.target.position.set(0, 0, 0);
    light.castShadow = true;
    light.shadowCameraNear = 1200;
    light.shadowCameraFar = 2500;
    light.shadowCameraFov = 50;
    light.shadowBias = 0.0001;
    light.shadowDarkness = 0.5;
    light.shadowMapWidth = SHADOW_MAP_WIDTH;
    light.shadowMapHeight = SHADOW_MAP_HEIGHT;

    scene.add(light);

    populateRectangles(scene);
    showCaseRectangles();

    document.addEventListener('keydown', onDocumentKeyDown, false);
    document.addEventListener('mousemove', onDocumentMouseMove, false);
    document.addEventListener('mousedown', onDocumentMouseDown, false);
    document.addEventListener('mouseup', onDocumentMouseUp, false);
    window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    requestAnimationFrame(animate);
    stats.begin();
    render();
    stats.end();
}

function render() {

    // View Mode
    switch (options.viewMode) {
    case 'Orbital Control':
        controls.update();
        break;
    case 'Orbit Mode':

        options.orbitViewTheta += 0.1;
        if (options.orbitViewTheta >= 360) {
            options.orbitViewTheta = 0;
        }
        camera.position.x = options.orbitViewRadius * Math.sin(THREE.Math.degToRad(options.orbitViewTheta));
        camera.position.y = options.orbitViewRadius;
        camera.position.z = options.orbitViewRadius * Math.cos(THREE.Math.degToRad(options.orbitViewTheta));
        camera.lookAt(scene.position);
        camera.updateMatrixWorld();
        break;
    }

    // Brush Action
    if (MOUSEDOWN) {
        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects(scene.children);

        if (intersects.length >= 1 && MOUSEBTN == 1) {
            INTERSECTED = intersects[0].object;
            applyBrush(3);
        }
    }
    renderer.render(scene, camera);
}

function populateRectangles(parent) {
    var x = 0;
    var z = 0;
    var row = 0;
    var col = 0;
    var rectangle;

    var geometry = new THREE.BoxGeometry(RECT_SIZE, RECT_HEIGHT, RECT_SIZE);

    for (var i = 0; i < NUM_CUBES; i++) {

        var material = new THREE.MeshLambertMaterial({
            color: Math.random() * 0xffffff
        });

        if ((i % GRID_SIZE) === 0) {
            col = 1;
            row++;
        } else {
            col++;
        }

        x = -(((GRID_SIZE * RECT_SIZE) / 2) - ((RECT_SIZE) * col) + (RECT_SIZE / 2));
        z = (((GRID_SIZE * RECT_SIZE) / 2) - ((RECT_SIZE) * row) + (RECT_SIZE / 2));

        rectangle = new THREE.Mesh(geometry, material);
        rectangle.position.set(x, -3000, z);
        rectangle.castShadow = options.castShadow;
        rectangle.receiveShadow = options.castShadow;
        rectangles.push(rectangle);

        parent.add(rectangle);
    }
}

function onDocumentKeyDown(event) {

    switch (event.which) {

    case 66:
        for (var i = 0; i < rectangles.length; i++) {
            TweenMax.to(rectangles[i].position, 1 + Math.random() * 1, {
                y: 100,
                ease: SteppedEase.config(12 + Math.ceil(Math.random() * 5)),
            });
        }
        break;
    case 67:
        for (var i = 0; i < rectangles.length; i++) {
            TweenMax.to(rectangles[i].position, 1 + Math.random() * 2, {
                y: 100,
                ease: Elastic.easeOut,
            });
        }
        break;
    case 80:
        break;
    case 86:
        var t1 = new TimelineLite();
        for (var i = 0; i < rectangles.length; i++) {
            t1.to(rectangles[i].position, .005, {
                y: 10,
                ease: Linear.easeNone,
            });
        }
        t1.play();
        break;
    case 88:
        TweenMax.to(rectangles[0].position, 1, {
            y: 10,
            ease: Elastic.easeOut,
        });
        //xrectangles[0].position.y += 20;
        break;
    }
}

function onDocumentMouseMove(event) {
    event.preventDefault();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}

function onDocumentMouseDown(event) {
    MOUSEUP = false;
    MOUSEDOWN = true;
    MOUSEBTN = event.which;
}

function onDocumentMouseUp(event) {
    MOUSEDOWN = false;
    MOUSEUP = true;
}

function applyBrush() {

    var x = INTERSECTED.position.x;
    var z = INTERSECTED.position.z;

    var col = (x + ((GRID_SIZE * RECT_SIZE) / 2) - (RECT_SIZE / 2)) / RECT_SIZE;
    var row = ((z - ((GRID_SIZE * RECT_SIZE) / 2) - (RECT_SIZE / 2)) / -RECT_SIZE) - 1;
    var index = row * GRID_SIZE + col;

    //console.log(col + ' ' + row + ' ' + index);
    var sigma = 1;
    var strength = 1 / 49;
    var width = 3;

    switch (options.brushType) {
    case 'Gaussian':
        gaussianBrush(options.brushSize, options.brushMagnitude, row, col);
        break;
    case 'Pinpoint':
        pinpointBrush(options.brushSize, options.brushMagnitude, row, col);
        break;
    case 'Blur':
        blurBrush(options.blurMagnitude, row, col);
        break;
    case 'Color':
        colorBrush(options.brushSize, options.color0, row, col);
        break;
    }
}

function gaussianBrush(sigma, magnitude, row, col) {
    var fWidth = Math.ceil(sigma * 3);
    var fSize = (fWidth * 2) + 1;
    var newRow = 0;
    var newCol = 0;
    var index, fIndex = 0;
    var gFilter;

    gFilter = createGaussianFilter(sigma, magnitude);

    for (var i = -fWidth; i <= fWidth; i++) {
        for (var j = -fWidth; j <= fWidth; j++) {
            newRow = row + i;
            newCol = col + j;

            if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
                index = (newRow * GRID_SIZE) + newCol;
                rectangles[index].position.y += gFilter[fIndex];
            }
            fIndex += 1;
        }
    }
}

function pinpointBrush(sigma, magnitude, row, col) {
    var fWidth = Math.ceil(sigma * 2);
    var fSize = (fWidth * 2) + 1;
    var newRow = 0;
    var newCol = 0;
    var index;
    var gFilter;

    if (sigma < 0.6) {
        index = (row * GRID_SIZE) + col;
        rectangles[index].position.y += magnitude;
    } else {
        for (var i = -fWidth; i <= fWidth; i++) {
            for (var j = -fWidth; j <= fWidth; j++) {
                newRow = row + i;
                newCol = col + j;

                if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
                    index = (newRow * GRID_SIZE) + newCol;
                    rectangles[index].position.y += magnitude / 6;
                }
            }
        }
    }
}

function blurBrush(magnitude, row, col) {
    var fWidth = 1;
    var fSize = (fWidth * 2) + 1;

    var newRow = 0;
    var newCol = 0;
    var index = (row * GRID_SIZE) + col;
    var fIndex = 0;
    var gFilter;

    var neighbors;
    var sum = 0;

    for (var i = -fWidth; i <= fWidth; i++) {
        for (var j = -fWidth; j <= fWidth; j++) {

            newRow = row + i;
            newCol = col + j;

            if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
                findex = (newRow * GRID_SIZE) + newCol;

                sum += (rectangles[findex].position.y + 255) * magnitude;
            }
        }
    }
    //console.log(sum);
    rectangles[index].position.y = sum - 255;
}


function colorBrush(sigma, color, row, col) {
    var c = parseHex(color);
    var fWidth = Math.ceil(sigma);
    var fSize = (fWidth * 2) + 1;
    var newRow = 0;
    var newCol = 0;
    var index;

    if (sigma < 1) {
        index = (row * GRID_SIZE) + col;
        rectangles[index].material.color.setHex(c);
    } else {
        for (var i = -fWidth; i <= fWidth; i++) {
            for (var j = -fWidth; j <= fWidth; j++) {
                newRow = row + i;
                newCol = col + j;

                if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
                    index = (newRow * GRID_SIZE) + newCol;
                    rectangles[index].material.color.setHex(c);
                }

            }
        }
    }
}

function createGaussianFilter(sigma, magnitude) {
    var fWidth = Math.ceil(sigma * 3);
    var fSize = (fWidth * 2) + 1;
    var gFilter = [];
    var temp;
    var sum = 0;

    for (var x = -fWidth; x <= fWidth; x++) {
        for (var y = -fWidth; y <= fWidth; y++) {
            temp = Math.exp(-((x * x) + (y * y)) / (2 * (sigma * sigma))) / (2 * Math.PI * (sigma * sigma));
            sum += temp;
            gFilter.push(temp);
        }
    }

    for (var i = 0; i < gFilter.length; i++) {
        gFilter[i] = (gFilter[i] / sum) * magnitude;
    }

    return gFilter;
}

function castShadow() {
    if (options.castShadow) {
        options.castShadow = false;
    } else {
        options.castShadow = true;
    }
    for (var i = 0; i < rectangles.length; i++) {
        rectangles[i].castShadow = options.castShadow;
        rectangles[i].recieveShadow = options.castShadow;
    }
}

function setSingleColor() {
    var c = parseHex(options.color0);
    for (var i = 0; i < rectangles.length; i++) {
        rectangles[i].material.color.setHex(c);
    }
}

function setRandomColor() {
    for (var i = 0; i < rectangles.length; i++) {
        rectangles[i].material.color.setHex(Math.random() * 0xffffff);
    }
}

function showCaseRectangles() {
    for (var i = 0; i < rectangles.length; i++) {
        TweenMax.to(rectangles[i].position, 1 + Math.random() * 1.5, {
            y: -85,
            //ease: SteppedEase.config(12 + Math.ceil(Math.random() * 5)),
            //ease: Elastic.easeOut,
            ease: Power4.easeInOut,
        });
        TweenMax.to(rectangles[i].position, 1 + Math.random() * 1, {
            y: -155,
            delay: 3,
            ease: Elastic.easeOut,
        });
    }
}

function reset() {
    for (var i = 0; i < rectangles.length; i++) {
        TweenMax.to(rectangles[i].position, 1 + Math.random() * 1, {
            y: -155,
            ease: Elastic.easeOut,
        });
    }
}

function setUpGUI() {
    var gui = new dat.GUI();

    var f0 = gui.addFolder('View Mode');
    f0.add(options, 'viewMode', ['Orbital Control', 'Orbit Mode', 'Stationary Mode']);
    f0.add(options, 'orbitViewTheta', 0, 360).listen();
    f0.add(options, 'orbitViewRadius', 100, 500);

    var f1 = gui.addFolder('Brush');
    f1.add(options, 'brushType', ['Gaussian', 'Pinpoint', 'Blur', 'Color']);
    f1.add(options, 'brushSize', .5, 2).onChange(function (value) {
        brushSize = value;
    });
    f1.add(options, 'brushMagnitude', -40, 40).onChange(function (value) {
        brushMagnitude = value;
    });
    f1.add(options, 'blurMagnitude', .10, .15);

    var f2 = gui.addFolder('Lighting');
    f2.add(options, 'toggleShadow');

    var f3 = gui.addFolder('Color');
    f3.addColor(options, 'color0').name('Color');
    f3.add(options, 'singleColor');
    f3.add(options, 'randomColor');

    gui.add(options, 'reset').name('Reset');
}

function setUpStats(parent) {
    stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    stats.setMode(0);
    parent.appendChild(stats.domElement);
}

function parseHex(hex) {
    return '0x' + hex.slice(1);
}

猜你喜欢

转载自blog.csdn.net/weixin_45544796/article/details/107763125