html页面3D模型渲染之-Google-model-viewer

2,880 阅读3分钟

我正在参加「掘金·启航计划」

前言

接上一篇文章,“# html页面3D模型渲染之——three.js” juejin.cn/post/722590…

本文实现另外一种3D渲染的方法

效果

直接上效果图

QQ录屏20230509141302.gif

model-viewer

说到3d渲染不得不说一下,“Google-model-viewer”,这是由Google开发的一个开源项目,用于在Web上显示和交互三维模型,反正就是一句话,允许用户以交互方式浏览、旋转、缩放和移动模型,以便从不同的角度和距离查看模型。 这是他的官方api链接,modelviewer.dev/examples/au…

实现技术

本文是基于产品详情列表去实现的3D模型渲染,有产品的轮播图预览,3D预览。

上代码,

js引入

<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>

这是model-viewer的js库,要实现3d渲染这个是必不可少的。

html代码

<model-viewer class="tabs__active___8IvFf modelViewer"
    src="https://cdn.shopify.com/s/files/1/0551/1957/7176/files/YH-4404.glb?v=1683186253" exposure="1"
    shadow-intensity="0" camera-controls="true" data-js-focus-visible="true" disable-zoom disable-tap
    interaction-policy="always-allow" camera-orbit="30deg 70deg 100%" min-camera-orbit="auto auto 1m" 
    max-camera-orbit="auto auto 1m" loading preload="true" max-field-of-view="auto" reveal="auto"
    range-request-strategy="performance"
    environment-image="https://stormsend1.djicdn.com/uploads/3d/8f490eaaa02516662cbdba7233ec72bc.hdr"
    ar-status="not-presenting" on-touchstart="if (this.canScale) {this.scale = 1;}">

    <div slot="progress-bar"></div>
</model-viewer>

说一下各个属性的作用

  • exposure: 控制环境的亮度,其值在0到1之间,1表示最亮,0表示最暗。
  • shadow-intensity: 控制阴影的强度,其值在0到1之间,1表示最强,0表示没有阴影。
  • camera-controls: 控制是否启用默认的相机控制器,其值为true或false。
  • data-js-focus-visible: 用于指示元素是否支持键盘焦点可见性(keyboard focus visibility),其值为true或false。
  • disable-zoom: 禁用缩放功能,其值为true或false。
  • disable-tap: 禁用触摸功能,其值为true或false。
  • interaction-policy: 控制交互策略,其值可以是"always-allow"、"allow-when-focused"或"allow-when-pointer-down"。
  • camera-orbit: 控制相机绕物体的旋转角度,其值是一个包含三个参数的字符串,分别表示绕x、y、z轴旋转的角度。
  • min-camera-orbit: 控制相机绕物体的最小旋转角度,其值可以是一个数字或"auto"。
  • max-camera-orbit: 控制相机绕物体的最大旋转角度,其值可以是一个数字或"auto"。
  • loading: 控制模型加载过程中的显示效果,其值可以是"auto"、"lazy"或"eager"。
  • preload: 控制模型是否预加载,其值为true或false。
  • max-field-of-view: 控制相机的最大视野,其值可以是一个数字或"auto"。
  • reveal: 控制模型的出现方式,其值可以是"auto"或"interaction".
  • range-request-strategy: 控制范围请求的策略,其值可以是"performance"或"load-complete"。
  • environment-image: 控制环境贴图的路径,其值是一个字符串。
  • ar-status: 控制AR状态,其值可以是"not-presenting"、"presenting"或"failed".
  • on-touchstart: 触摸事件的回调函数,用于处理触摸事件。

js代码

 class Render {
    domRender() {
        const viewer = document.querySelector('model-viewer');
       // viewer.minScale = 0.1; // 设置最小缩放比例为50%
        function loading() {
            const progressBar = document.getElementById('progress');
            const loadingText = document.getElementById('loading-text');
            viewer.addEventListener('progress', (event) => {
                const loaded = event.detail.totalProgress;
                loadingText.textContent = `${(loaded * 100).toFixed(0)}%`;
            });
            viewer.addEventListener('load', () => {

                loadingText.textContent = 'Loading Complete!';
                setTimeout(() => {
                    document.getElementById('loading').style.display = 'none';
                }, 500);
                //100%后清除定时器
                clearInterval(loadingInterval);
            });
        }
        const loadingInterval = setInterval(loading, 100);
    }

}

//加载3D渲染
var render = new Render();
//渲染以及绑定事件
render.domRender();

非常简单,相比于three.js,它更容易入手。 Model Viewer和Three.js都是用于在Web上创建和展示3D模型的工具。它们各有自己的优点和缺点,下面是它们的一些主要特点:

Model Viewer的优点:

  • Model Viewer是基于Web Components技术实现的,易于使用和集成到Web应用程序中。
  • Model Viewer支持多种3D模型格式,包括glTF、OBJ、FBX、Collada等。
  • Model Viewer提供了丰富的交互功能和选项,如相机控制、阴影、环境贴图等。
  • Model Viewer支持在AR和VR设备上查看3D模型,具有更广泛的应用场景。

Model Viewer的缺点:

  • Model Viewer的功能相对较为简单,不支持高级的3D图形编程。
  • Model Viewer的扩展性有限,不太适合开发复杂的3D应用程序。

Three.js的优点:

  • Three.js是一个强大的3D图形库,支持高级的3D图形编程。
  • Three.js提供了丰富的3D图形效果和功能,如阴影、纹理、光照、动画等。
  • Three.js支持多种3D模型格式,可以在多个平台和设备上使用。
  • Three.js有庞大的开发者社区和活跃的维护者,提供了丰富的文档和示例。

Three.js的缺点:

  • Three.js需要一定的3D图形编程知识才能使用,对于初学者来说有一定的学习曲线。
  • Three.js的代码相对较为复杂,需要仔细的调试和优化才能获得较好的性能。
  • Three.js的兼容性有一定的局限性,需要考虑不同平台和设备的差异性。

综上所述,Model Viewer适合于快速创建和展示简单的3D模型,而Three.js适合于开发复杂的3D应用程序和游戏。

附上全部代码

粘贴即用

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
    <title>model-viewer</title>
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        .model{width: 600px;}
        .dmodel_max {
            position: relative;
        }

        .modelViewer,
        .dmodel_max {
            width: 600px !important;
            height: 400px !important;

        }

        #loading {
            position: absolute;
            top: 50%;
            text-align: center;
            left: 0;
            transform: translateY(-50%);
            width: 100%;
            height: 100%;
            background-color: #ffffff;
            z-index: 9999;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .tabs_flex{
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .tabs_flex li{list-style: none;padding: 6px 20px;}
        .tabs_flex li a{display: flex;padding: 6px 30px;border-radius: 16px;text-decoration: none;align-items: center;}
        .tabs_flex li a.active{background: #660099;color: #ffffff;}
        .tabs_flex li a.active .whiteicon{display: block;}
        .tabs_flex li a img{margin-right: 10px;}
        .tabs_flex li a.active .blockicon{display: none;}
        .whiteicon{display: none;}
        .tab-content {
            display: none;
            width: 600px !important;
            height: 400px !important;
        }

        .tab-content.active {
            display: block;
        }

        #loading-text {

            font-size: 20px;
            color: #660099;
        }
    </style>
</head>

<body>
    <!-- 谷歌实现的一个 web component,可用于查看 Web 上的 3D 模型并与之交互 -->
    <script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
    
    <div class="model">
        <div id="tab1" class="tab-content active">
            <img src="/image/pro3.png" alt="" style="width: 100%;height: auto;">
        </div>
        <div id="tab2" class="tab-content">
            <div class="dmodel_max">
                <div id="loading">
                    <div class="dmodel_flex">
                        <div id="progress">
                            <img src="/selling/lodding.gif" alt="">
                        </div>
                        <div id="loading-text"></div>
                    </div>
                </div>
                <model-viewer class="tabs__active___8IvFf modelViewer"
                    src="https://cdn.shopify.com/s/files/1/0551/1957/7176/files/YH-4404.glb" exposure="1"
                    shadow-intensity="0" camera-controls="true" data-js-focus-visible="true" disable-zoom disable-tap
                    interaction-policy="always-allow" camera-orbit="30deg 70deg 100%" min-camera-orbit="auto auto 1m" 
                    max-camera-orbit="auto auto 1m" loading preload="true" max-field-of-view="auto" reveal="auto"
                    range-request-strategy="performance"
                    environment-image="https://stormsend1.djicdn.com/uploads/3d/8f490eaaa02516662cbdba7233ec72bc.hdr"
                    ar-status="not-presenting" on-touchstart="if (this.canScale) {this.scale = 1;}">
                  
                    <div slot="progress-bar"></div>
                </model-viewer>
            </div>
        </div>
        <ul class="tabs_flex">
            <li><a href="#tab1" class="active">
                <img src="./image/whiteimg.png" alt="" width="24" height="24" class="whiteicon">
                <img src="./image/blockimg.png" alt="" width="24" height="24" class="blockicon">
                Photos
            </a></li>
            <li><a href="#tab2">
                <img src="./image/block3d.png" alt="" width="24" height="24" class="blockicon">
                <img src="./image/white3d.png" alt="" width="24" height="24" class="whiteicon">
                3D</a></li>
        </ul>
    </div>
   
    <script>
        $(function () {
            // 定义一个对象来记录每个 tab 是否已经加载过内容
            var loaded = {
                tab1: false,
                tab2: false
            };
            // 绑定 tab 点击事件
            $('.tabs_flex a').click(function (e) {
                e.preventDefault();
                // 获取当前点击的 tab 的 ID
                var tabId = $(this).attr('href');
                console.log(tabId)
                // 如果该 tab 还未加载过内容,则加载内容
                if (!loaded[tabId.substring(1)]) {
                    if (tabId == "#tab2") {
                        //加载3D渲染
                        var render = new Render();
                        //渲染以及绑定事件
                        render.domRender();
                    }
                    loaded[tabId.substring(1)] = true;
                }
                // 隐藏所有 tab 内容并移除 active 类
                $('.tab-content').removeClass('active');
                $('.tabs_flex a').removeClass('active');
                // 显示当前点击的 tab 内容并添加 active 类
                $(tabId).addClass('active');
                $(this).addClass('active');
            });
        });
        //model_list = model_list.reverse();
        //封装渲染
        class Render {
           
            domRender() {
                const viewer = document.querySelector('model-viewer');
               // viewer.minScale = 0.1; // 设置最小缩放比例为50%
                function loading() {
                    const progressBar = document.getElementById('progress');
                    const loadingText = document.getElementById('loading-text');
                    viewer.addEventListener('progress', (event) => {
                        const loaded = event.detail.totalProgress;
                        loadingText.textContent = `${(loaded * 100).toFixed(0)}%`;
                    });
                    viewer.addEventListener('load', () => {

                        loadingText.textContent = 'Loading Complete!';
                        setTimeout(() => {
                            document.getElementById('loading').style.display = 'none';
                        }, 500);
                        //100%后清除定时器
                        clearInterval(loadingInterval);
                    });
                }
                const loadingInterval = setInterval(loading, 100);
            }

        }
       
    </script>
</body>

</html>