首页 / 应用软件 / 实战教学,为网站添加基于AR的虚拟产品摆放与场景体验功能

实战教学,为网站添加基于AR的虚拟产品摆放与场景体验功能

实战教学:为WordPress网站添加基于AR的虚拟产品摆放与场景体验功能

引言:AR技术如何重塑电商体验

在当今数字化时代,增强现实(AR)技术正以前所未有的速度改变着消费者的购物体验。想象一下,当用户访问您的网站时,他们不仅能看到产品的平面图片,还能通过手机摄像头将虚拟产品"放置"在自己的真实环境中,从各个角度查看产品细节,甚至与产品进行互动。这种沉浸式体验不仅显著提升用户参与度,还能大幅降低退货率,提高转化率。

根据最新市场研究,采用AR技术的电商平台平均转化率提升了40%,客户互动时间增加了近一倍。对于WordPress网站所有者来说,集成AR功能不再是遥不可及的高科技梦想,而是可以通过代码二次开发实现的实用功能。

本教程将详细指导您如何为WordPress网站添加基于AR的虚拟产品摆放与场景体验功能,通过实用的代码示例和分步指南,帮助您打造前沿的交互式购物体验。

第一部分:AR技术基础与准备工作

1.1 AR技术原理简介

增强现实(AR)是一种将虚拟信息叠加到真实世界中的技术,通过设备摄像头捕捉现实场景,并在其上叠加计算机生成的图像、视频或3D模型。在电商领域,AR主要应用于:

  1. 虚拟试穿/试戴:用户可以看到产品穿戴在身上的效果
  2. 虚拟摆放:将家具、装饰品等放置在实际环境中查看效果
  3. 产品交互:允许用户旋转、缩放、自定义虚拟产品

1.2 技术选型与工具准备

在开始开发前,我们需要选择合适的AR技术方案:

方案一:基于Web的AR(WebAR)

  • 优点:无需安装应用,跨平台兼容性好
  • 技术栈:A-Frame、AR.js、Three.js
  • 适合:轻量级AR体验,快速部署

方案二:原生AR SDK集成

  • 优点:性能更好,功能更丰富
  • 技术栈:ARKit(iOS)、ARCore(Android)
  • 适合:高性能要求的复杂AR体验

方案三:混合方案

  • 结合WebAR和原生SDK的优势
  • 使用WebXR Device API

对于WordPress网站,我们推荐使用WebAR方案,因为它具有最好的兼容性和部署便利性。

开发环境准备:

  1. WordPress开发环境(本地或测试服务器)
  2. 代码编辑器(VS Code、Sublime Text等)
  3. 基础的前端开发知识(HTML、CSS、JavaScript)
  4. 3D模型处理工具(如Blender,用于准备产品模型)

1.3 3D模型准备与优化

AR体验的核心是3D模型,我们需要为每个产品准备高质量的3D模型:

  1. 模型格式选择

    • GLTF/GLB:推荐格式,体积小,加载快
    • OBJ+MTL:通用格式,但文件较大
    • FBX:功能丰富,但需要转换
  2. 模型优化技巧

    • 减少多边形数量(在保持质量的前提下)
    • 压缩纹理图像
    • 使用合理的LOD(细节层次)系统
    • 确保模型尺寸与实际产品一致
  3. 模型创建流程

    产品测量 → 3D建模 → 纹理贴图 → 模型优化 → 格式转换 → 测试验证

第二部分:WordPress环境配置与基础架构

2.1 创建自定义插件框架

首先,我们需要创建一个WordPress插件来管理所有AR相关功能:

<?php
/**
 * Plugin Name: AR Product Viewer for WordPress
 * Plugin URI: https://yourwebsite.com/
 * Description: 为WordPress网站添加AR产品查看和虚拟摆放功能
 * Version: 1.0.0
 * Author: Your Name
 * License: GPL v2 or later
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 定义插件常量
define('ARPV_VERSION', '1.0.0');
define('ARPV_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('ARPV_PLUGIN_URL', plugin_dir_url(__FILE__));

// 初始化插件
class AR_Product_Viewer {
    
    private static $instance = null;
    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        $this->init_hooks();
    }
    
    private function init_hooks() {
        // 后台初始化
        add_action('admin_init', array($this, 'admin_init'));
        
        // 添加管理菜单
        add_action('admin_menu', array($this, 'add_admin_menu'));
        
        // 前端资源加载
        add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
        
        // 后台资源加载
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
        
        // 添加短代码
        add_shortcode('ar_product_viewer', array($this, 'ar_product_viewer_shortcode'));
        
        // 为产品添加自定义字段
        add_action('add_meta_boxes', array($this, 'add_product_ar_meta_box'));
        add_action('save_post', array($this, 'save_product_ar_meta'));
    }
    
    // 更多方法将在后续章节实现...
}

// 启动插件
AR_Product_Viewer::get_instance();
?>

2.2 数据库设计与模型管理

我们需要扩展WordPress数据库来存储AR相关数据:

// 在插件激活时创建数据库表
register_activation_hook(__FILE__, 'arpv_create_database_tables');

function arpv_create_database_tables() {
    global $wpdb;
    
    $charset_collate = $wpdb->get_charset_collate();
    $table_name = $wpdb->prefix . 'arpv_models';
    
    $sql = "CREATE TABLE IF NOT EXISTS $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        product_id bigint(20) NOT NULL,
        model_name varchar(255) NOT NULL,
        model_file_url varchar(500) NOT NULL,
        model_type varchar(50) DEFAULT 'glb',
        model_size int(11) DEFAULT 0,
        scale_x float DEFAULT 1.0,
        scale_y float DEFAULT 1.0,
        scale_z float DEFAULT 1.0,
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY product_id (product_id)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
    
    // 添加版本选项
    add_option('arpv_db_version', '1.0');
}

2.3 后台管理界面设计

创建用户友好的后台界面来管理AR模型:

// 添加管理菜单
public function add_admin_menu() {
    add_menu_page(
        'AR产品查看器',
        'AR产品查看器',
        'manage_options',
        'ar-product-viewer',
        array($this, 'render_admin_page'),
        'dashicons-visibility',
        30
    );
    
    add_submenu_page(
        'ar-product-viewer',
        '模型管理',
        '模型管理',
        'manage_options',
        'arpv-model-manager',
        array($this, 'render_model_manager_page')
    );
    
    add_submenu_page(
        'ar-product-viewer',
        'AR设置',
        '设置',
        'manage_options',
        'arpv-settings',
        array($this, 'render_settings_page')
    );
}

// 渲染模型管理页面
public function render_model_manager_page() {
    ?>
    <div class="wrap">
        <h1>AR模型管理</h1>
        
        <div class="arpv-admin-container">
            <div class="arpv-admin-header">
                <button id="arpv-add-model" class="button button-primary">添加新模型</button>
                <div class="arpv-search-box">
                    <input type="text" id="arpv-model-search" placeholder="搜索模型...">
                </div>
            </div>
            
            <div class="arpv-model-list">
                <table class="wp-list-table widefat fixed striped">
                    <thead>
                        <tr>
                            <th>ID</th>
                            <th>产品名称</th>
                            <th>模型名称</th>
                            <th>文件类型</th>
                            <th>文件大小</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody id="arpv-model-table-body">
                        <!-- 通过AJAX动态加载 -->
                    </tbody>
                </table>
            </div>
            
            <!-- 模型上传模态框 -->
            <div id="arpv-upload-modal" class="arpv-modal" style="display:none;">
                <div class="arpv-modal-content">
                    <span class="arpv-close-modal">&times;</span>
                    <h2>上传3D模型</h2>
                    <form id="arpv-upload-form">
                        <div class="arpv-form-group">
                            <label for="arpv-product-select">关联产品</label>
                            <select id="arpv-product-select" required>
                                <option value="">选择产品...</option>
                                <?php
                                $products = get_posts(array(
                                    'post_type' => 'product',
                                    'posts_per_page' => -1,
                                    'post_status' => 'publish'
                                ));
                                
                                foreach ($products as $product) {
                                    echo '<option value="' . $product->ID . '">' . $product->post_title . '</option>';
                                }
                                ?>
                            </select>
                        </div>
                        
                        <div class="arpv-form-group">
                            <label for="arpv-model-name">模型名称</label>
                            <input type="text" id="arpv-model-name" required>
                        </div>
                        
                        <div class="arpv-form-group">
                            <label for="arpv-model-file">模型文件</label>
                            <input type="file" id="arpv-model-file" accept=".glb,.gltf,.fbx,.obj" required>
                            <p class="description">支持GLB, GLTF, FBX, OBJ格式,建议使用GLB格式以获得最佳性能</p>
                        </div>
                        
                        <div class="arpv-form-group">
                            <label for="arpv-model-scale">模型缩放比例</label>
                            <input type="number" id="arpv-model-scale" step="0.1" value="1.0" min="0.1" max="10">
                        </div>
                        
                        <button type="submit" class="button button-primary">上传模型</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <?php
}

第三部分:WebAR核心功能实现

3.1 集成AR.js与Three.js框架

首先,我们需要在前端加载必要的AR和3D渲染库:

// 前端资源加载
public function enqueue_frontend_assets() {
    // 只在需要AR功能的页面加载
    if ($this->should_load_ar_assets()) {
        // Three.js - 3D渲染引擎
        wp_enqueue_script('three-js', 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js', array(), 'r128', true);
        
        // AR.js - WebAR框架
        wp_enqueue_script('ar-js', 'https://cdn.jsdelivr.net/npm/ar.js@latest/aframe/build/aframe-ar.min.js', array('three-js'), null, true);
        
        // GLTF加载器
        wp_enqueue_script('gltf-loader', ARPV_PLUGIN_URL . 'assets/js/loaders/GLTFLoader.js', array('three-js'), '1.0', true);
        
        // 自定义AR控制器
        wp_enqueue_script('arpv-ar-controller', ARPV_PLUGIN_URL . 'assets/js/ar-controller.js', array('three-js', 'ar-js', 'gltf-loader'), ARPV_VERSION, true);
        
        // AR样式
        wp_enqueue_style('arpv-ar-style', ARPV_PLUGIN_URL . 'assets/css/ar-style.css', array(), ARPV_VERSION);
        
        // 传递数据到前端
        wp_localize_script('arpv-ar-controller', 'arpv_ajax', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('arpv_nonce')
        ));
    }
}

// 判断是否需要加载AR资源
private function should_load_ar_assets() {
    // 检查是否在产品页面
    if (is_product() || has_shortcode(get_post()->post_content, 'ar_product_viewer')) {
        return true;
    }
    
    // 检查是否在支持AR的页面模板
    $template = get_page_template_slug();
    if ($template === 'template-ar-product.php') {
        return true;
    }
    
    return false;
}

3.2 创建AR查看器组件

实现核心的AR查看器组件:

// assets/js/ar-controller.js
class ARProductViewer {
    constructor(options) {
        this.options = {
            containerId: 'ar-viewer-container',
            productId: 0,
            modelUrl: '',
            modelScale: 1.0,
            ...options
        };
        
        this.scene = null;
        this.camera = null;
        this.renderer = null;
        this.controls = null;
        this.model = null;
        this.arToolkitSource = null;
        this.arToolkitContext = null;
        
        this.init();
    }
    
    init() {
        this.createARScene();
        this.loadProductModel();
        this.setupEventListeners();
        this.animate();
    }
    
    createARScene() {
        // 创建场景
        this.scene = new THREE.Scene();
        
        // 创建相机
        this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 20);
        
        // 创建渲染器
        this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.outputEncoding = THREE.sRGBEncoding;
        
        // 添加到容器
        const container = document.getElementById(this.options.containerId);
        if (container) {
            container.appendChild(this.renderer.domElement);
        }
        
        // 添加光源
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
        this.scene.add(ambientLight);
        
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
        directionalLight.position.set(0, 10, 5);
        this.scene.add(directionalLight);
        
        // 初始化AR.js
        this.initARToolkit();
    }
    
    initARToolkit() {
        // 创建AR.js源
        this.arToolkitSource = new THREEx.ArToolkitSource({
            sourceType: 'webcam',
            sourceWidth: 1280,
            sourceHeight: 720,
            displayWidth: window.innerWidth,
            displayHeight: window.innerHeight
        });
        
        // 初始化源
        this.arToolkitSource.init(() => {
            // 调整渲染器大小
            this.onResize();
        });
        
        // 创建AR.js上下文
        this.arToolkitContext = new THREEx.ArToolkitContext({
            cameraParametersUrl: ARPV_PLUGIN_URL + 'assets/data/camera_para.dat',
            detectionMode: 'mono',
            maxDetectionRate: 30,
            canvasWidth: this.arToolkitSource.domElement.clientWidth,
            canvasHeight: this.arToolkitSource.domElement.clientHeight
        });
        
        // 初始化上下文
        this.arToolkitContext.init(() => {
            // 相机投影矩阵将根据AR上下文更新
            this.camera.projectionMatrix.copy(this.arToolkitContext.getProjectionMatrix());
        });
        
        // 创建AR标记
        const markerRoot = new THREE.Group();
        this.scene.add(markerRoot);
        
        // 创建标记控制器
        const markerControls = new THREEx.ArMarkerControls(this.arToolkitContext, markerRoot, {
            type: 'pattern',
            patternUrl: ARPV_PLUGIN_URL + 'assets/data/patt.hiro',
            changeMatrixMode: 'cameraTransformMatrix'
        });
        
        // 将模型添加到标记根组
        this.modelContainer = markerRoot;
    }
    
    async loadProductModel() {
        if (!this.options.modelUrl) {
            console.error('未提供模型URL');
            return;
        }
        
        try {
            const loader = new THREE.GLTFLoader();
            
            loader.load(
                this.options.modelUrl,
                (gltf) => {
                    this.model = gltf.scene;
                    
                    // 调整模型大小和位置
                    const box = new THREE.Box3().setFromObject(this.model);
                    const size = box.getSize(new THREE.Vector3());
                    const maxDim = Math.max(size.x, size.y, size.z);
                    const scale = this.options.modelScale / maxDim;
                    
                    this.model.scale.set(scale, scale, scale);
                    this.model.position.set(0, 0, 0);
                    
                    // 添加到场景
                    if (this.modelContainer) {
                        this.modelContainer.add(this.model);
                    } else {
                        this.scene.add(this.model);
                    }
                    
                    // 触发模型加载完成事件
                    this.dispatchEvent('modelLoaded', { model: this.model });
                    
                    console.log('模型加载成功');
                },
                (progress) => {
                    // 加载进度
                    const percent = (progress.loaded / progress.total * 100).toFixed(2);
                    this.dispatchEvent('modelLoading', { percent });
                },
                (error) => {
                    console.error('模型加载失败:', error);
                    this.dispatchEvent('modelError', { error });
                }
            );
        } catch (error) {
            console.error('加载模型时出错:', error);
        }

3.3 实现模型交互控制

// 继续 assets/js/ar-controller.js
    setupEventListeners() {
        // 窗口大小调整
        window.addEventListener('resize', () => this.onResize());
        
        // 触摸/鼠标事件
        this.setupInteractionEvents();
        
        // 键盘控制
        window.addEventListener('keydown', (e) => this.onKeyDown(e));
        
        // 自定义事件监听
        this.eventListeners = {};
    }
    
    setupInteractionEvents() {
        const canvas = this.renderer.domElement;
        let isDragging = false;
        let previousMousePosition = { x: 0, y: 0 };
        
        // 触摸事件
        canvas.addEventListener('touchstart', (e) => {
            e.preventDefault();
            if (e.touches.length === 1) {
                // 单指触摸 - 旋转
                isDragging = true;
                previousMousePosition = {
                    x: e.touches[0].clientX,
                    y: e.touches[0].clientY
                };
            } else if (e.touches.length === 2) {
                // 双指触摸 - 缩放
                this.startPinchDistance = this.getPinchDistance(e);
            }
        });
        
        canvas.addEventListener('touchmove', (e) => {
            e.preventDefault();
            
            if (e.touches.length === 1 && isDragging && this.model) {
                // 单指拖动 - 旋转模型
                const currentMousePosition = {
                    x: e.touches[0].clientX,
                    y: e.touches[0].clientY
                };
                
                const delta = {
                    x: currentMousePosition.x - previousMousePosition.x,
                    y: currentMousePosition.y - previousMousePosition.y
                };
                
                // 根据拖动距离旋转模型
                this.rotateModel(delta.x * 0.01, delta.y * 0.01);
                
                previousMousePosition = currentMousePosition;
            } else if (e.touches.length === 2 && this.startPinchDistance && this.model) {
                // 双指捏合 - 缩放模型
                const currentPinchDistance = this.getPinchDistance(e);
                const scaleFactor = currentPinchDistance / this.startPinchDistance;
                
                this.scaleModel(scaleFactor);
                this.startPinchDistance = currentPinchDistance;
            }
        });
        
        canvas.addEventListener('touchend', (e) => {
            isDragging = false;
            this.startPinchDistance = null;
        });
        
        // 鼠标事件(桌面设备)
        canvas.addEventListener('mousedown', (e) => {
            if (e.button === 0) { // 左键
                isDragging = true;
                previousMousePosition = { x: e.clientX, y: e.clientY };
            }
        });
        
        canvas.addEventListener('mousemove', (e) => {
            if (isDragging && this.model) {
                const currentMousePosition = { x: e.clientX, y: e.clientY };
                const delta = {
                    x: currentMousePosition.x - previousMousePosition.x,
                    y: currentMousePosition.y - previousMousePosition.y
                };
                
                this.rotateModel(delta.x * 0.01, delta.y * 0.01);
                previousMousePosition = currentMousePosition;
            }
        });
        
        canvas.addEventListener('mouseup', () => {
            isDragging = false;
        });
        
        // 鼠标滚轮缩放
        canvas.addEventListener('wheel', (e) => {
            e.preventDefault();
            if (this.model) {
                const scaleFactor = e.deltaY > 0 ? 0.9 : 1.1;
                this.scaleModel(scaleFactor);
            }
        });
    }
    
    getPinchDistance(e) {
        const dx = e.touches[0].clientX - e.touches[1].clientX;
        const dy = e.touches[0].clientY - e.touches[1].clientY;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    rotateModel(deltaX, deltaY) {
        if (!this.model) return;
        
        // 限制旋转角度
        this.model.rotation.y += deltaX;
        this.model.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, this.model.rotation.x + deltaY));
    }
    
    scaleModel(factor) {
        if (!this.model) return;
        
        // 限制缩放范围
        const currentScale = this.model.scale.x;
        const newScale = Math.max(0.1, Math.min(5, currentScale * factor));
        
        this.model.scale.set(newScale, newScale, newScale);
    }
    
    onKeyDown(e) {
        if (!this.model) return;
        
        switch(e.key) {
            case 'r': // 重置模型位置和旋转
                this.model.rotation.set(0, 0, 0);
                this.model.scale.set(1, 1, 1);
                break;
            case '+': // 放大
                this.scaleModel(1.1);
                break;
            case '-': // 缩小
                this.scaleModel(0.9);
                break;
            case ' ': // 空格键 - 切换AR模式
                this.toggleARMode();
                break;
        }
    }
    
    toggleARMode() {
        // 切换AR模式和普通3D查看模式
        this.isARMode = !this.isARMode;
        
        if (this.isARMode) {
            this.enterARMode();
        } else {
            this.exitARMode();
        }
    }
    
    enterARMode() {
        // 启动摄像头
        this.arToolkitSource.init(() => {
            this.arToolkitContext.arController.play();
        });
        
        this.dispatchEvent('arModeEntered');
    }
    
    exitARMode() {
        // 停止摄像头
        this.arToolkitContext.arController.stop();
        
        this.dispatchEvent('arModeExited');
    }
    
    onResize() {
        if (this.arToolkitSource) {
            this.arToolkitSource.onResizeElement();
            this.arToolkitSource.copyElementSizeTo(this.renderer.domElement);
        }
        
        if (this.camera) {
            this.camera.aspect = window.innerWidth / window.innerHeight;
            this.camera.updateProjectionMatrix();
        }
        
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    }
    
    animate() {
        requestAnimationFrame(() => this.animate());
        
        // 更新AR上下文
        if (this.arToolkitSource && this.arToolkitSource.ready) {
            this.arToolkitContext.update(this.arToolkitSource.domElement);
        }
        
        // 渲染场景
        this.renderer.render(this.scene, this.camera);
    }
    
    // 事件系统
    addEventListener(event, callback) {
        if (!this.eventListeners[event]) {
            this.eventListeners[event] = [];
        }
        this.eventListeners[event].push(callback);
    }
    
    removeEventListener(event, callback) {
        if (this.eventListeners[event]) {
            const index = this.eventListeners[event].indexOf(callback);
            if (index > -1) {
                this.eventListeners[event].splice(index, 1);
            }
        }
    }
    
    dispatchEvent(event, data) {
        if (this.eventListeners[event]) {
            this.eventListeners[event].forEach(callback => {
                callback(data);
            });
        }
    }
    
    // 销毁清理
    destroy() {
        window.removeEventListener('resize', this.onResize);
        
        if (this.model && this.scene) {
            this.scene.remove(this.model);
        }
        
        if (this.renderer) {
            this.renderer.dispose();
            this.renderer.forceContextLoss();
        }
        
        if (this.arToolkitContext) {
            this.arToolkitContext.arController.stop();
        }
    }
}

// 全局访问
window.ARProductViewer = ARProductViewer;

3.4 创建产品页面集成短代码

// 在插件主类中添加短代码处理
public function ar_product_viewer_shortcode($atts) {
    $atts = shortcode_atts(array(
        'product_id' => 0,
        'width' => '100%',
        'height' => '500px',
        'mode' => 'both' // '3d', 'ar', 'both'
    ), $atts, 'ar_product_viewer');
    
    // 获取产品信息
    $product_id = $atts['product_id'] ?: get_the_ID();
    $model_data = $this->get_product_model_data($product_id);
    
    if (!$model_data) {
        return '<p class="arpv-error">该产品暂无AR模型</p>';
    }
    
    // 生成唯一ID
    $viewer_id = 'arpv-' . uniqid();
    
    ob_start();
    ?>
    <div class="arpv-product-viewer-container">
        <div id="<?php echo esc_attr($viewer_id); ?>" 
             class="arpv-viewer" 
             style="width: <?php echo esc_attr($atts['width']); ?>; 
                    height: <?php echo esc_attr($atts['height']); ?>;">
        </div>
        
        <div class="arpv-controls">
            <div class="arpv-control-group">
                <button class="arpv-btn arpv-btn-rotate" title="旋转">
                    <span class="dashicons dashicons-image-rotate"></span>
                </button>
                <button class="arpv-btn arpv-btn-zoom-in" title="放大">
                    <span class="dashicons dashicons-plus"></span>
                </button>
                <button class="arpv-btn arpv-btn-zoom-out" title="缩小">
                    <span class="dashicons dashicons-minus"></span>
                </button>
                <button class="arpv-btn arpv-btn-reset" title="重置">
                    <span class="dashicons dashicons-image-rotate"></span>
                </button>
            </div>
            
            <?php if ($atts['mode'] !== '3d') : ?>
            <div class="arpv-control-group">
                <button class="arpv-btn arpv-btn-ar arpv-btn-primary" title="AR模式">
                    <span class="dashicons dashicons-camera"></span>
                    <span>在您的空间中查看</span>
                </button>
            </div>
            <?php endif; ?>
            
            <div class="arpv-control-group arpv-instructions">
                <p class="arpv-hint">
                    <span class="dashicons dashicons-info"></span>
                    提示:使用鼠标拖动旋转,滚轮缩放,或点击AR按钮在真实环境中查看
                </p>
            </div>
        </div>
        
        <div class="arpv-ar-overlay" style="display: none;">
            <div class="arpv-ar-header">
                <button class="arpv-btn arpv-btn-close-ar">返回</button>
                <h3>AR模式</h3>
                <p>将相机对准平面表面,等待模型出现</p>
            </div>
            <div class="arpv-ar-hint">
                <p>移动设备:单指旋转模型,双指缩放</p>
            </div>
        </div>
    </div>
    
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        // 初始化AR查看器
        const viewer = new ARProductViewer({
            containerId: '<?php echo esc_js($viewer_id); ?>',
            productId: <?php echo intval($product_id); ?>,
            modelUrl: '<?php echo esc_js($model_data['url']); ?>',
            modelScale: <?php echo floatval($model_data['scale']); ?>
        });
        
        // 绑定控制按钮
        $('.arpv-btn-rotate').on('click', function() {
            // 自动旋转动画
            viewer.startAutoRotate();
        });
        
        $('.arpv-btn-zoom-in').on('click', function() {
            viewer.scaleModel(1.2);
        });
        
        $('.arpv-btn-zoom-out').on('click', function() {
            viewer.scaleModel(0.8);
        });
        
        $('.arpv-btn-reset').on('click', function() {
            viewer.resetModel();
        });
        
        $('.arpv-btn-ar').on('click', function() {
            $('.arpv-ar-overlay').show();
            viewer.enterARMode();
        });
        
        $('.arpv-btn-close-ar').on('click', function() {
            $('.arpv-ar-overlay').hide();
            viewer.exitARMode();
        });
        
        // 处理模型加载事件
        viewer.addEventListener('modelLoaded', function(data) {
            console.log('模型加载完成', data);
            $('.arpv-hint').fadeOut();
        });
        
        viewer.addEventListener('modelLoading', function(data) {
            console.log('模型加载进度:', data.percent + '%');
        });
    });
    </script>
    <?php
    
    return ob_get_clean();
}

private function get_product_model_data($product_id) {
    global $wpdb;
    $table_name = $wpdb->prefix . 'arpv_models';
    
    $model = $wpdb->get_row($wpdb->prepare(
        "SELECT * FROM $table_name WHERE product_id = %d ORDER BY id DESC LIMIT 1",
        $product_id
    ));
    
    if ($model) {
        return array(
            'url' => $model->model_file_url,
            'scale' => $model->scale_x,
            'name' => $model->model_name
        );
    }
    
    return false;
}

第四部分:高级功能与优化

4.1 多模型场景与产品搭配

// 添加多模型支持
public function add_scene_builder_meta_box() {
    add_meta_box(
        'arpv_scene_builder',
        'AR场景构建器',
        array($this, 'render_scene_builder_meta_box'),
        'product',
        'normal',
        'high'
    );
}

public function render_scene_builder_meta_box($post) {
    wp_nonce_field('arpv_scene_builder', 'arpv_scene_builder_nonce');
    
    $scene_data = get_post_meta($post->ID, '_arpv_scene_data', true);
    $scene_data = $scene_data ? json_decode($scene_data, true) : array();
    
    ?>
    <div class="arpv-scene-builder">
        <div class="arpv-scene-controls">
            <button type="button" class="button arpv-add-to-scene">添加产品到场景</button>
            <button type="button" class="button arpv-save-scene">保存场景</button>
            <button type="button" class="button arpv-reset-scene">重置场景</button>
        </div>
        
        <div class="arpv-scene-preview">
            <div id="arpv-scene-viewer" style="width: 100%; height: 400px; background: #f5f5f5;">
                <!-- 3D场景预览 -->
            </div>
        </div>
        
        <div class="arpv-scene-items">
            <h3>场景中的产品</h3>
            <ul id="arpv-scene-list">
                <?php if (!empty($scene_data['items'])) : ?>
                    <?php foreach ($scene_data['items'] as $item) : ?>
                        <li data-product-id="<?php echo esc_attr($item['product_id']); ?>">
                            <span class="arpv-item-name"><?php echo esc_html($item['name']); ?></span>
                            <button type="button" class="button arpv-remove-item">移除</button>
                        </li>
                    <?php endforeach; ?>
                <?php endif; ?>
            </ul>
        </div>
        
        <input type="hidden" id="arpv-scene-data" name="arpv_scene_data" 
               value="<?php echo esc_attr(json_encode($scene_data)); ?>">
    </div>
    
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        let sceneViewer = null;
        let sceneItems = <?php echo $scene_data ? json_encode($scene_data['items']) : '[]'; ?>;
        
        // 初始化场景查看器
        function initSceneViewer() {
            sceneViewer = new ARSceneViewer({
                containerId: 'arpv-scene-viewer',
                items: sceneItems
            });
        }
        
        // 添加产品到场景
        $('.arpv-add-to-scene').on('click', function() {
            // 打开产品选择模态框
            $('#arpv-product-selector').show();
        });
        
        // 保存场景
        $('.arpv-save-scene').on('click', function() {
            const sceneData = {
                items: sceneItems,
                camera_position: sceneViewer ? sceneViewer.getCameraPosition() : null,
                lighting: sceneViewer ? sceneViewer.getLightingSettings() : null
            };
            
            $('#arpv-scene-data').val(JSON.stringify(sceneData));
            alert('场景已保存');
        });
        
        // 初始化
        initSceneViewer();
    });
    </script>
    <?php
}

4.2 性能优化与缓存策略

// 实现模型缓存和CDN集成
class ARPV_Cache_Manager {
    private static $instance = null;
    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function get_model_url($model_id, $use_cache = true) {
        $cache_key = 'arpv_model_' . $model_id;
        
        if ($use_cache) {
            $cached_url = get_transient($cache_key);
            if ($cached_url !== false) {
                return $cached_url;
            }
        }
        
        // 从数据库获取模型信息
        global $wpdb;
        $table_name = $wpdb->prefix . 'arpv_models';
        $model = $wpdb->get_row($wpdb->prepare(
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5188.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部