three+cannon实现一个三维文字菜单点击重力推拉效果代码

代码语言:html

所属分类:三维

代码描述:three+cannon实现一个三维文字菜单点击重力推拉效果代码

代码标签: three cannon 三维 文字 菜单 重力

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">


    <meta name="viewport" content="width=device-width, initial-scale=1">

<link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/aqua-1.5.5.css">

    <style>
        body {
          display: flex;
          justify-content: center;
          align-items: center;
          min-height: 100vh;
          margin: 0;
          background: #f7f7fd;
        }
        
        :root {
          --blue-color-1: #2c3e50;
        }
        
        .bg-blue-1 {
          background: var(--blue-color-1);
        }
    </style>




</head>

<body>
    <div class="relative w-screen h-screen">
        <nav class="menu fixed hv-center z-5 pointer-events-none">
            <ul class="menu-list text-center space-y-12 text-9xl opacity-0">
                <li class="menu-list-item"><a href="#">Home</a></li>
                <li class="menu-list-item"><a href="#">Archives</a></li>
                <li class="menu-list-item"><a href="#">About</a></li>
            </ul>
        </nav>
        <div class="stage w-full h-full bg-blue-1"></div>
    </div>
    <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.123.js"></script>
    <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/cannon.js"></script>
    <script>
        const calcAspect = (el) => el.clientWidth / el.clientHeight;
        const getNormalizedMousePos = (e) => {
            return {
                x: (e.clientX / window.innerWidth) * 2 - 1,
                y: -(e.clientY / window.innerHeight) * 2 + 1
            };
        };
        // 创建文本
        const createText = (text = "", config, material = new THREE.MeshStandardMaterial({
            color: "#ffffff"
        })) => {
            const geo = new THREE.TextGeometry(text, config);
            const mesh = new THREE.Mesh(geo, material);
            return mesh;
        };
        // 加载字体
        const loadFont = (url) => {
            const loader = new THREE.FontLoader();
            return new Promise((resolve) => {
                loader.load(url, (font) => {
                    resolve(font);
                });
            });
        };
        const menuFontUrl = "//repo.bfw.wiki/bfwrepo/fonts/helvetiker_regular.typeface.json";
        const menuFontConfig = {
            size: 3,
            height: 0.4,
            curveSegments: 24,
            bevelEnabled: true,
            bevelThickness: 0.9,
            bevelSize: 0.3,
            bevelSegments: 10
        };
        class MouseTracker {
            constructor() {
                this.mousePos = new THREE.Vector2(0, 0);
                this.mouseSpeed = 0;
            }
            // 追踪鼠标位置
            trackMousePos() {
                window.addEventListener("mousemove", (e) => {
                    this.setMousePos(e);
                });
                window.addEventListener("touchstart", (e) => {
                    this.setMousePos(e.touches[0]);
                }, { passive: false });
                window.addEventListener("touchmove", (e) => {
                    this.setMousePos(e.touches[0]);
                });
            }
            // 设置鼠标位置
            setMousePos(e) {
                const { x, y } = getNormalizedMousePos(e);
                this.mousePos.x = x;
                this.mousePos.y = y;
            }
            // 追踪鼠标速度
            trackMouseSpeed() {
                // https://stackoverflow.com/questions/6417036/track-mouse-speed-with-js
                let lastMouseX = -1;
                let lastMouseY = -1;
                let mouseSpeed = 0;
                window.addEventListener("mousemove", (e) => {
                    const mousex = e.pageX;
                    const mousey = e.pageY;
                    if (lastMouseX > -1) {
                        mouseSpeed = Math.max(Math.abs(mousex - lastMouseX), Math.abs(mousey - lastMouseY));
                        this.mouseSpeed = mouseSpeed / 100;
                    }
                    lastMouseX = mousex;
                    lastMouseY = mousey;
                });
                document.addEventListener("mouseleave", () => {
                    this.mouseSpeed = 0;
                });
            }
        }
        class RaycastSelector {
            constructor(scene, camera) {
                this.scene = scene;
                this.camera = camera;
                this.raycaster = new THREE.Raycaster();
                this.mouseTracker = new MouseTracker();
                this.mouseTracker.trackMousePos();
            }
            // 获取点击物
            getInterSects(targets = this.scene.children) {
                this.raycaster.setFromCamera(this.mouseTracker.mousePos, this.camera);
                const intersects = this.raycaster.intersectObjects(targets, true);
                return intersects;
            }
            // 获取第一个选中物
            getFirstIntersect(targets = this.scene.children) {
                const intersects = this.getInterSects(targets);
                const intersect = intersects[0];
                if (!intersect || !intersect.face) {
                    return null;
                }
                return intersect;
            }
            // 选中点击物时
            onChooseIntersect(target) {
                const intersect = this.getFirstIntersect();
                if (!intersect) {
                    return null;
                }
                const object = intersect.object;
                return target === object ? intersect : null;
            }
            // 高亮选中物
            highlightIntersect(color = "#ff0000") {
                document.addEventListener("click", () => {
                    const intersect = this.getFirstIntersect();
                    if (!intersect) {
                        return null;
                    }
                    const object = intersect.object;
                    const material = object.material;
                    console.log(object.name);
                    if (!material.isHighlighted) {
                        material.isHighlighted = true;
                        material.originColor = new THREE.Color(material.color.r, material.color.g, material.color.b);
                        material.color.set(color);
                    }
                    else {
                        material.isHighlighted = false;
                        material.color.set(material.originColor);
                    }
                });
            }
        }
        class Base {
            constructor(sel, debug = false) {
                this.debug = debug;
                this.container = document.querySelector(sel);
                this.perspectiveCameraParams = {
                    fov: 75,
                    near: 0.1,
                    far: 100
                };
                this.orthographicCameraParams = {
                    zoom: 2,
                    near: -100,
                    far: 1000
                };
                this.cameraPosition = new THREE.Vector3(0, 3, 10);
                this.lookAtPosition = new THREE.Vector3(0, 0, 0);
                this.rendererParams = {
                    outputEncoding: THREE.LinearEncoding,
                    config: {
                        alpha: true,
                        antialias: true
                    }
                };
                this.mousePos = new THREE.Vector2(0, 0);
            }
            // 初始化
            init() {
                this.createScene();
                this.createPerspectiveCamera();
                this.createRenderer();
                this.createMesh({});
                this.createLight();
                this.createOrbitControls();
                this.addListeners();
                this.setLoop();
            }
            // 创建场景
            createScene() {
                const scene = new THREE.Scene();
                if (this.debug) {
                    scene.add(new THREE.AxesHelper());
                    const stats = Stats();
                    this.container.appendChild(stats.dom);
                    this.stats = stats;
                }
                this.scene = scene;
            }
            // 创建透视相机
            createPerspectiveCamera() {
                const { perspectiveCameraParams, cameraPosition, lookAtPosition } = this;
                const { fov, near, far } = perspectiveCameraParams;
                const aspect = calcAspect(this.container);
                const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
                camera.position.copy(cameraPosition);
                camera.lookAt(lookAtPosition);
                this.camera = camera;
            }
            // 创建正交相机
            createOrthographicCamera() {
                const { orthographicCameraParams, cameraPosition, lookAtPosition } = this;
                const { left, right, top, bottom, near, far } = orthographicCameraParams;
                const camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
                camera.position.copy(cameraPosition);
                camera.lookAt(lookAtPosition);
                this.camera = camera;
            }
            // 更新正交相机参数
            updateOrthographicCameraParams() {
                const { container } = this;
                const { zoom, near, far } = this.orthographicCameraParams;
                const aspect = calcAspect(container);
                this.orthographicCameraParams = {
                    left: -zoom * aspect,
                    right: zoom * aspect,
                    top: zoom,
                    bottom: -zoom,
                    near,
                    far,
                    zoom
                };
            }
            // 创建渲染
            createRenderer() {
                var _a;
                const { rendererParams } = this;
                const { outputEncoding, config } = rendererParams;
                const renderer = new THREE.WebGLRenderer(config);
                renderer.setSize(this.container.clientWidth, this.container.clientHeight);
                renderer.outputEncoding = outputEncoding;
                this.resizeRendererToDisplaySize();
                (_a = this.container) === null || _a === void 0 ? void 0 : _a.appendChild(renderer.domElement);
                this.renderer = renderer;
                this.renderer.setClearColor(0x000000, 0);
            }
            // 允许投影
            enableShadow() {
                this.renderer.shadowMap.enabled = true;
            }
            // 调整渲染器尺寸
            resizeRendererToDisplaySize() {
                const { renderer } = this;
                if (!renderer) {
                    return;
                }
                const canvas = renderer.domElement;
                const pixelRatio = window.devicePixelRatio;
                const { clientWidth, clientHeight } = canvas;
                const width = (clientWidth * pixelRatio) | 0;
                const height = (clientHeight * pixelRatio) | 0;
                const isResizeNeeded = canvas.width !== width || canvas.height !== height;
                if (isResizeNeeded) {
                    renderer.setSize(width, height, false);
                }
                return isResizeNeeded;
            }
            // 创建网格
            createMesh(meshObject, container = this.scene) {
                const { geometry = new THREE.BoxGeometry(1, 1, 1), material = new THREE.MeshStandardMaterial({
                    color: new THREE.Color("#d9dfc8")
                }), position = new THREE.Vector3(0, 0, 0) } = meshObject;
                const mesh = new THREE.Mesh(geometry, material);
                mesh.position.copy(position);
                container.add(mesh);
                return mesh;
            }
            // 创建光源
            createLight() {
                const dirLight = new THREE.DirectionalLight(new THREE.Color("#ffffff"), 0.5);
                dirLight.position.set(0, 50, 0);
                this.scene.add(dirLight);
                const ambiLight = new THREE.AmbientLight(new THREE.Color("#ffffff"), 0.4);
                this.scene.add(ambiLight);
            }
            // 创建轨道控制
            createOrbitControls() {
                const controls = new OrbitControls(this.camera, this.renderer.domElement);
                const { lookAtPosition } = this;
                controls.target.copy(lookAtPosition);
                controls.update();
                this.controls = controls;
            }
            // 监听事件
            addListeners() {
                this.onResize();
            }
            // 监听画面缩放
            onResize() {
                window.addEventListener("resize", (e) => {
                    if (this.camera instanceof THREE.PerspectiveCamera) {
                        const aspect = calcAspect(this.container);
                        const camera = this.camera;
                        camera.aspect = aspect;
                        camera.updateProjectionMatrix();
                    }
                    else if (this.camera instanceof THREE.OrthographicCamera) {
                        this.updateOrthographicCameraParams();
                        const camera = this.camera;
                        const { left, right, top, bottom, near, far } = this.orthographicCameraParams;
                        camera.left = left;
                        camera.right = right;
                        camera.top = top;
                        camera.bottom = bottom;
                        camera.near = near;
                        camera.far = far;
                        camera.updateProjectionMatrix();
                    }
                    this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
                });
            }
            // 动画
            update() {
                console.log("animation");
            }
            // 渲染
            setLoop() {
                this.renderer.setAnimationLoop(() => {
                    this.resizeRendererToDisplaySize();
                    this.update();
                    if (this.controls) {
                        this.controls.update();
                    }
                    if (this.stats) {
                        this.stats.update();
                    }
                    if (this.composer) {
                        this.composer.render();
                    }
                    else {
                    .........完整代码请登录后点击上方下载按钮下载查看

网友评论0