最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Three.js?3D模型展示與交互實現(xiàn)完整代碼

 更新時間:2025年08月11日 10:00:48   作者:取什名字  
Three.js是一個開源的WebGL庫,它提供了一套易于使用的API來創(chuàng)建和顯示3D圖形在網(wǎng)頁上,這篇文章主要介紹了Three.js?3D模型展示與交互實現(xiàn)的相關(guān)資料,需要的朋友可以參考下

前言

本文將詳細解析一個基于Three.js的3D模型展示與交互系統(tǒng)的完整實現(xiàn)代碼,該系統(tǒng)包含了模型加載、環(huán)境光照、用戶交互、響應(yīng)式設(shè)計等多個功能模塊。

一、代碼概述

這段代碼實現(xiàn)了一個完整的3D產(chǎn)品展示系統(tǒng),主要功能包括:

  1. 創(chuàng)建3D場景并設(shè)置正交相機

  2. 加載并顯示3D模型

  3. 實現(xiàn)模型旋轉(zhuǎn)交互(鼠標拖拽和慣性效果)

  4. 添加加載動畫

  5. 實現(xiàn)響應(yīng)式布局

  6. 自定義光標效果

二、核心代碼解析

1. 場景初始化

這部分代碼初始化了Three.js的核心組件:

const scene = new THREE.Scene();
const boxElement = document.querySelector(".productModel_box");
const width = boxElement.clientWidth;
const height = boxElement.clientHeight;

// 設(shè)置正交相機
const aspect = width / height;
const frustumSize = 10;
const camera = new THREE.OrthographicCamera(
    (frustumSize * aspect) / -2,
    (frustumSize * aspect) / 2,
    frustumSize / 2,
    frustumSize / -2,
    0.1,
    1000
);
camera.position.z = 7.5;

// 創(chuàng)建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(width, height);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.NoToneMapping;
boxElement.appendChild(renderer.domElement);
  • scene: 3D場景容器

  • camera: 使用正交投影相機(OrthographicCamera),適合產(chǎn)品展示

  • renderer: WebGL渲染器,開啟抗鋸齒和透明背景

2. 加載動畫實現(xiàn)

function createLoadingCube() {
    const loadingScene = new THREE.Scene();
    const loadingCamera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
    loadingCamera.position.z = 5;
    const loadingRenderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    loadingRenderer.setClearAlpha(0);
    loadingRenderer.setSize(100, 100);
    document.getElementById("loading-cube").appendChild(loadingRenderer.domElement);

    const cube = new THREE.Mesh(
        new THREE.BoxGeometry(2, 2, 2),
        new THREE.MeshBasicMaterial({ color: 0xfe5000, wireframe: true })
    );
    loadingScene.add(cube);
    loadingScene.add(new THREE.AmbientLight(0xffffff, 1));

    function animateLoadingCube() {
        requestAnimationFrame(animateLoadingCube);
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        loadingRenderer.render(loadingScene, loadingCamera);
    }

    animateLoadingCube();
    return function () {
        document.getElementById("loading-cube").removeChild(loadingRenderer.domElement);
    };
}

const cleanupLoadingCube = createLoadingCube();

這段代碼創(chuàng)建了一個旋轉(zhuǎn)的線框立方體作為加載動畫:

  1. 創(chuàng)建獨立的場景、相機和渲染器

  2. 添加一個橙色線框立方體

  3. 實現(xiàn)立方體旋轉(zhuǎn)動畫

  4. 返回清理函數(shù),用于加載完成后移除動畫

3. 環(huán)境光照設(shè)置

const pmremGenerator = new THREE.PMREMGenerator(renderer);
new THREE.RGBELoader().load(
    "https://cdn.shopify.com/s/files/1/0753/2393/2896/files/photo_studio_01_2k.hdr?v=1746778998",
    (hdrTexture) => {
        const envMap = pmremGenerator.fromEquirectangular(hdrTexture).texture;
        scene.environment = envMap;
        hdrTexture.dispose();
        pmremGenerator.dispose();
    }
);

使用HDR環(huán)境貼圖創(chuàng)建逼真的光照效果:

  1. 使用PMREMGenerator預(yù)處理環(huán)境貼圖

  2. 加載2K分辨率的HDR貼圖

  3. 將處理后的環(huán)境貼圖應(yīng)用到場景

4. 模型加載與設(shè)置

const loader = new THREE.GLTFLoader();
const dracoLoader = new THREE.DRACOLoader();
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/libs/draco/");
loader.setDRACOLoader(dracoLoader);

let model = null;
let initialRotation = { x: 0, y: Math.PI };
let hasPlayedScrollAnimation = false;

loader.load(`{{ section.settings.modelLink }}`, (gltf) => {
    model = gltf.scene;
    model.scale.set(7.5, 7.5, 7.5);
    model.position.set(0, -3.5, 0);

    model.traverse((child) => {
        if (child.isMesh && child.material) {
            // 可調(diào)整材質(zhì)屬性
        }
    });

    scene.add(model);
    initialRotation = { x: model.rotation.x, y: model.rotation.y };

    setTimeout(() => rotateY180(), 500);
    setupScrollTriggerWithGSAP();

    gsap.to("#loading-container", {
        opacity: 0,
        duration: 0.5,
        onComplete: () => {
            document.getElementById("loading-container").style.display = "none";
            cleanupLoadingCube();
        },
    });
});

模型加載流程:

  1. 使用GLTFLoader和DRACOLoader加載壓縮的GLTF模型

  2. 設(shè)置模型縮放和位置

  3. 遍歷模型所有子元素,可調(diào)整材質(zhì)屬性

  4. 添加模型到場景

  5. 加載完成后隱藏加載動畫

  6. 執(zhí)行初始旋轉(zhuǎn)動畫(rotateY180)

5. 交互系統(tǒng)實現(xiàn)

let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
let targetRotation = { x: 0, y: 0 };
let currentRotation = { x: 0, y: 0 };
const maxRotationX = Math.PI / 3;
const rotationSensitivity = 0.003;
let velocity = { x: 0, y: 0 };
const friction = 0.95;

// 鼠標移動處理
document.addEventListener("mousemove", (e) => {
    mouseX = e.clientX;
    mouseY = e.clientY;

    if (isInsideBox && !isOverReturnIcon) {
        updateCursorPosition(mouseX, mouseY);
        cursor.style.display = "flex";
        document.body.classList.remove("normal-cursor");
    } else {
        cursor.style.display = "none";
        document.body.classList.add("normal-cursor");
    }

    if (!isDragging || !model) return;

    const deltaMove = {
        x: e.clientX - previousMousePosition.x,
        y: e.clientY - previousMousePosition.y,
    };

    velocity = {
        x: -deltaMove.y * rotationSensitivity * 0.5,
        y: deltaMove.x * rotationSensitivity * 0.5,
    };

    targetRotation.y += deltaMove.x * rotationSensitivity;
    targetRotation.x += deltaMove.y * rotationSensitivity;
    targetRotation.x = Math.max(-maxRotationX, Math.min(maxRotationX, targetRotation.x));
    previousMousePosition = { x: e.clientX, y: e.clientY };
});

// 動畫循環(huán)
function animate() {
    requestAnimationFrame(animate);
    if (!isDragging) {
        targetRotation.y += velocity.y;
        targetRotation.x += velocity.x;
        velocity.x *= friction;
        velocity.y *= friction;
    }

    currentRotation.x += (targetRotation.x - currentRotation.x) * 0.1;
    currentRotation.y += (targetRotation.y - currentRotation.y) * 0.1;

    if (model) {
        model.rotation.x = currentRotation.x;
        model.rotation.y = currentRotation.y;
    }

    renderer.render(scene, camera);
}

交互系統(tǒng)關(guān)鍵點:

  1. 鼠標拖拽實現(xiàn)模型旋轉(zhuǎn)

  2. 添加旋轉(zhuǎn)慣性效果(velocity和friction)

  3. 限制X軸旋轉(zhuǎn)角度(maxRotationX)

  4. 平滑過渡效果(使用currentRotation和targetRotation插值)

  5. 自定義光標效果

三、功能擴展點

這段代碼還可以進一步擴展:

  1. 模型材質(zhì)自定義:在模型加載后的traverse回調(diào)中可以修改材質(zhì)屬性

  2. 滾動動畫:setupScrollTriggerWithGSAP函數(shù)可以擴展為基于滾動的動畫

  3. 多點觸控:當前只支持單點觸控,可以擴展為多點觸控縮放

  4. 模型點擊事件:添加模型特定部件的點擊交互

四、總結(jié)

這個3D模型展示系統(tǒng)實現(xiàn)了:

  • 專業(yè)的加載流程(加載動畫+進度提示)

  • 高質(zhì)量的渲染效果(HDR環(huán)境光)

  • 流暢的交互體驗(拖拽+慣性)

  • 響應(yīng)式設(shè)計(窗口大小變化適配)

  • 移動端支持(觸摸事件處理)

通過分析這段代碼,我們可以學習到如何使用Three.js構(gòu)建一個完整的產(chǎn)品3D展示系統(tǒng),涵蓋了從加載到交互的完整流程。

到此這篇關(guān)于Three.js 3D模型展示與交互實現(xiàn)的文章就介紹到這了,更多相關(guān)Three.js 3D模型展示與交互內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

万山特区| 米泉市| 海盐县| 化隆| 南乐县| 周宁县| 玉山县| 潮州市| 内黄县| 昌邑市| 山阴县| 星座| 锦屏县| 茌平县| 明水县| 延长县| 泌阳县| 梅河口市| 大同县| 稻城县| 紫云| 昆明市| 梨树县| 临沧市| 光山县| 米林县| 庐江县| 新平| 镇平县| 宣威市| 阿拉尔市| 黄山市| 剑阁县| 运城市| 洛阳市| 台山市| 宜良县| 遂宁市| 马龙县| 太保市| 长海县|