What’s on our mind?

Collection of articles, design, site, and resources made by designers and publisher @Menu View

* index36
// 화면 설정
const scene = new THREE.Scene();

// 카메라 설정
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 450);

// 렌더링 설정
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor("hotpink");
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector("#canvas-wrapper").appendChild(renderer.domElement);

// 꽃 설정
const petalRadius = 150;
const geometry = new THREE.TetrahedronBufferGeometry(petalRadius);
const material = new THREE.MeshNormalMaterial();
const group = new THREE.Group();

const CustomSinCurve = function (scale) {
    THREE.Curve.call(this);
    this.scale = scale === undefined ? 1 : scale;
};
CustomSinCurve.prototype = Object.create(THREE.Curve.prototype);
CustomSinCurve.prototype.constructor = CustomSinCurve;
CustomSinCurve.prototype.getPoint = function (t) {
    const tx = t * 3 - 1.5;
    const ty = Math.sin(2 * Math.PI * t);
    const tz = 0;

    return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
};

const Flower = function (group, distance = null) {
    this.group = group;
    this.dist = distance;
    this.group.position.x = petalRadius * -1;
    this.group.position.y = Math.round(petalRadius / 2);
    this.group.rotation.z = 250;

    if (distance !== null) {
        this.group.position.x = Math.round(this.dist / 2);
        this.group.position.y = Math.round(petalRadius * -0.5);
        this.group.position.z = 10;

        this.group.rotation.x = Math.round(this.dist / -2);
        this.group.rotation.z = Math.round(this.dist * 2);
    }
};

Flower.prototype.create = function () {
    const petalCount = 180;
    for (let i = 0; i < petalCount; i++) {
        const mesh = new THREE.Mesh(geometry, material);
        const tau = 2 * Math.PI;

        mesh.rotation.x = Math.random() * tau;
        mesh.rotation.y = Math.random() * tau;

        mesh.matrixAutoUpdate = false;
        mesh.updateMatrix();

        this.group.add(mesh);
    }
};

Flower.prototype.createStem = function () {
    const path = new CustomSinCurve(petalRadius);
    const geometryStem = new THREE.TubeBufferGeometry(path, 1, 5, 20, false);
    const meshStem = new THREE.Mesh(geometryStem, material);

    meshStem.position.x = petalRadius;
    this.group.add(meshStem);
};

const f1group = new THREE.Group();
const f1 = new Flower(f1group);
f1.create();
f1.createStem();

const f2group = new THREE.Group();
const f2dist = Math.floor(1000 / 5);
const f2 = new Flower(f2group, f2dist);
f2.create();
f2.createStem();

group.add(f1group);
group.add(f2group);
scene.add(group);

const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const colorMaterial = "#ff0080";
const newMaterial = new THREE.MeshPhongMaterial({color: colorMaterial, shininess: 60 });

// 조명 설정
const light = new THREE.DirectionalLight();
light.position.set(0, 0.5, 1);
scene.add(light);

// 마우스 설정
let mouseX = 0;
let mouseY = 0;
const mouseFX = {
    coordinates(cX, cY) {
        mouseX = cX - window.innerWidth / 2;
        mouseY = cY - window.innerHeight / 2;

        const limit = 700;
        if (mouseX >= limit || mouseX <= limit * -1) mouseX = limit;
    },
    calcObjPickingRay(gp) {
        const ob = gp.children;
        const intersects = raycaster.intersectObjects(ob, true);

        ob.forEach((el) => {
            el.material = intersects.length > 0 ? newMaterial : material;
            el.material.needsUpdate = true;
        });
    },
    addMouseOver(cX, cY) {
        mouse.x = (cX / window.innerWidth) * 2 - 1;
        mouse.y = -(cY / window.innerHeight) * 2 + 1;

        raycaster.setFromCamera(mouse, camera);

        const flowerGroups = [f1group, f2group];
        flowerGroups.forEach((el) => {
            mouseFX.calcObjPickingRay(el);
        });
    },
    onMouseMove(e) {
        mouseFX.addMouseOver(e.clientX, e.clientY);
        mouseFX.coordinates(e.clientX, e.clientY);
    },
    onTouchMove(e) {
        const touchX = e.changedTouches[0].clientX;
        const touchY = e.changedTouches[0].clientY;
        mouseFX.coordinates(touchX, touchY);
    },
};
document.addEventListener("mousemove", mouseFX.onMouseMove);
document.addEventListener("touchmove", mouseFX.onTouchMove);

// 사이즈 설정
const onWindowResize = () => {
    const w = window.innerWidth;
    const h = window.innerHeight;

    camera.aspect = w / h;
    camera.updateProjectionMatrix();

    renderer.setSize(w, h);
};
window.addEventListener("resize", onWindowResize);

// 애니메이션
const createAnimRotation = () => {
    const t = Date.now() * 0.001;
    const rx = Math.sin(t * 0.7);
    const ry = Math.sin(t * 0.3);

    group.rotation.x = rx;
    group.rotation.y = ry;
};

// 렌더링
const render = () => {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (mouseY * -1 - camera.position.y) * 0.05;
    camera.lookAt(scene.position);

    createAnimRotation();

    renderer.render(scene, camera);
    requestAnimationFrame(render);
};
render();