three.js实现拖拽生成模型场景

news2024/10/6 11:02:28

 THREE.js 可以实现很多web 3D的效果,最近想实现一个拖拽生成场景的功能,主要用到拖拽API,draggable 的几个事件来实现,拖拽模型时记录模型属性,释放到画布时生成当前屏幕坐标对应的焦点上,最后生成模型。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Drag and Drop 3D Models</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        overflow: hidden;
      }

      #tools {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 100px;
        background-color: #f2f2f2;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        z-index: 1;
      }

      #scene {
        position: absolute;
        right: 0;
        top: 0;
        bottom: 0;
        left: 100px;
        background-color: #ddd;
      }

      #resetBtn {
        position: absolute;
        right: 20px;
        bottom: 20px;
        z-index: 2;
        padding: 8px;
        border: none;
        border-radius: 4px;
        background-color: #007bff;
        color: #fff;
        font-size: 16px;
        cursor: pointer;
      }

      img {
        width: 50px;
        height: 50px;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="tools">
      <img id="box" src="images/box.svg" draggable="true" />
      <img id="cylinder" src="images/cylinder.svg" draggable="true" />
    </div>
    <div id="scene"></div>
    <button id="resetBtn">Reset</button>
<script src="threejs.js"></script> <script src="OrbitControls.js"></script>
    <script>
      // 场景
      var scene = new THREE.Scene();
scene.background = new THREE.Color(0x002244);
      // 渲染器
      var renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.setSize(window.innerWidth - 100, window.innerHeight);
      document.getElementById("scene").appendChild(renderer.domElement);

      // 相机
      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        500
      );
      camera.near = 0.1;
camera.far = 10000;
camera.updateProjectionMatrix();
     camera.position.set(0, 200, 500);
      camera.lookAt(scene.position);

      // 地面网格
  // 地面网格
// 创建地面网格
//var geometry = new THREE.PlaneGeometry(10, 10);
//var material = new THREE.MeshBasicMaterial({ color: 0x888888, wireframe: true });
//var ground = new THREE.Mesh(geometry, material);
//ground.rotation.x = -Math.PI / 2;
//.receiveShadow = true; // 让地面网格接收阴影
//scene.add(ground);
      

      
var groundSize = 1000;
var ground = createGround(groundSize);
scene.add(ground);

// 创建两个球体,一个在地面上方,另一个在地面下方
var sphereRadius = 50;
var sphereTop = createSphere(sphereRadius);
sphereTop.position.set(0, sphereRadius, 0);
scene.add(sphereTop);

var sphereBottom = createSphere(sphereRadius);
sphereBottom.position.set(0, -sphereRadius, 0);
scene.add(sphereBottom);

// 创建环境光
var ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);

// 创建点光源
var pointLight = new THREE.PointLight(0xffffff, 1, 1000);
pointLight.position.set(-100, 200, 100);
scene.add(pointLight);

function createGround(size) {
  var geometry = new THREE.PlaneGeometry(size, size, 10, 10);
  var material = new THREE.MeshLambertMaterial({ color: 0x888888 , wireframe: true});
  var mesh = new THREE.Mesh(geometry, material);
  mesh.rotation.x = -Math.PI / 2;
  mesh.receiveShadow = true;
  return mesh;
}

function createSphere(radius) {
  var geometry = new THREE.SphereGeometry(radius, 32, 32);
  var material = new THREE.MeshPhongMaterial({ color: 0xff0000 });
  var mesh = new THREE.Mesh(geometry, material);
  return mesh;
}

      // 模型列表
      var models = {
        box: new THREE.BoxGeometry(50, 50, 50),
        cylinder: new THREE.CylinderGeometry(25, 25, 50, 20),
      };

      // 记录被选中的模型和交叉点
      var selectedModel = null;
      var intersects = null;

      // 工具栏按钮被拖动时,将其ID存储在dataTransfer中方便后续使用
      document.querySelectorAll("#tools img").forEach((img) => {
        img.addEventListener("dragstart", function (event) {
          selectedModel = models[this.id].clone();
          var currentTarget = event.currentTarget;
          event.dataTransfer.setData("text", currentTarget.id);
        });
      });

      // 场景可拖放,将模型放置在与地面网格相交的位置
      document
        .getElementById("scene")
        .addEventListener("dragover", function (event) {
          event.preventDefault();
        });
      document
        .getElementById("scene")
        .addEventListener("drop", function (event) {
          event.preventDefault();
             var raycaster = new THREE.Raycaster();
        var mouse = new THREE.Vector2();
        mouse.x = (event.offsetX / renderer.domElement.clientWidth) * 2 - 1;
        mouse.y = -(event.offsetY / renderer.domElement.clientHeight) * 2 + 1;
        raycaster.setFromCamera(mouse, camera);
        console.log(event.offsetX,event.offsetY);
        intersects = raycaster.intersectObject(ground);
          if (selectedModel && intersects) {
            var mesh = new THREE.Mesh(
              selectedModel,
              new THREE.MeshPhongMaterial({
                color: "#" + ((Math.random() * 0xffffff) << 0).toString(16),
              })
            );
            mesh.position.copy(intersects[0].point);
            mesh.position.y += selectedModel.parameters.height / 2;
            scene.add(mesh);
          }
        });

      // 重置场景
      document.getElementById("resetBtn").addEventListener("click", function () {
        while (scene.children.length > 1) {
          scene.remove(scene.children[1]);
        }
      });

      // 渲染场景
      function render() {
        renderer.render(scene, camera);
      }
      render();

      // 监听窗口大小变化
      window.addEventListener("resize", function () {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth - 100, window.innerHeight);
        render();
      });

      // 鼠标移动事件,稍后更新交叉点
      document.addEventListener("mousemove", function (event) {
     
      });

      // FPS控件
      var controls = new THREE.OrbitControls(camera, renderer.domElement);
      controls.target.set(0, 50, 0);
      controls.update();

      // 动画循环
      function animate() {
        requestAnimationFrame(animate);
        render();
      }
      animate();
    </script>
  </body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/539601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

增量更新和原始快照

三色标记法 2.1 基本算法 要找出存活对象&#xff0c;根据可达性分析&#xff0c;从GC Roots开始进行遍历访问&#xff0c;可达的则为存活对象&#xff1a; 最终结果&#xff1a;A/D/E/F/G 可达 我们把遍历对象图过程中遇到的对象&#xff0c;按“是否访问过”这个条件标记成…

【LeeCode】每日一题:复制带随机指针的链表

​&#x1f47b;内容专栏&#xff1a;《LeetCode刷题专栏》 &#x1f428;本文概括&#xff1a; 138.复制带随机指针的链表 &#x1f43c;本文作者&#xff1a;花 碟 &#x1f438;发布时间&#xff1a;2023.5.18 ​复制带随机指针的链表 力扣链接-> 138.复制带随机指针的链…

VS2019新建WebService/Web服务/asmx并通过IIS实现发布和调用

场景 对接第三方系统提供接口文档中显示为asmx接口 访问接口返回数据格式为 xml中的数据格式为json数据。 需要在本地新建并模拟调试环境。 注&#xff1a; 博客&#xff1a;霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主 实现 1、WebService WebService…

LeetCode刷题 --- 链表

定义一个node节点 class ListNode {int val;ListNode next;ListNode() {}ListNode(int val) {this.val val;}ListNode(int val, ListNode next) {this.val val;this.next next;} } 206 反转链表 题目&#xff1a;给你单链表的头节点 head &#xff0c;请你反转链表&#x…

【FAQ】视频编辑服务常见问题及解答

Q1问题描述 1、 访问贴纸等素材的时候提示“网络异常&#xff0c;请重试”怎么办&#xff1f; 2、 使用AI能力时&#xff0c;提示“errorCode:20124 errorMsg:Method not Allowed”&#xff1f; 解决方案 请做以下检查&#xff1a; 1、 在代码中检查鉴权信息是否已设置。如…

AI法律助手:ChatGPT如何提供智能化解决方案

日常生活中&#xff0c;民事纠纷不可避免&#xff0c;涉及到多种问题&#xff0c;如合同纠纷、劳动纠纷、婚姻家事、民间借贷、交通事故、工伤赔偿、房屋租赁等。解决这些问题&#xff0c;需要花费大量时间和精力&#xff0c;但现在&#xff0c;我们有了一种全新的解决方案&…

蓝库云:建立智慧零售,零代码技术能起到什么作用

随着科技的进步更多智能化的技术及应用融入我们生活中&#xff0c;例如零售行业在现代零售和传统零售的区别不仅在于营销策略、销售方式、销售渠道以及运营模式等方面&#xff0c;更多是在现代零售则更注重数字化营销&#xff0c;发挥社交媒体和电子商务渠道的作用&#xff0c;…

“前端”工匠系列(二):合格的工匠,怎么做好价值落地 | 京东云技术团队

一、“技术鄙视链&#xff1f;” 如果你是一个技术人&#xff0c;相信都知道技术圈有个相互的鄙视链&#xff0c;这个链条从技术人自己认知的角度在以业务价值为中心嵌套的一层一层的环&#xff0c;就像洋葱&#xff0c;具体的描述这里不赘述了。 出门左拐随便抓住一个人问一…

RabbitMQ应用问题——消息补偿机制以及代码示例

RabbitMQ应用问题——消息补偿机制以及代码示例 RabbitMQ应用问题 消息可靠性的保障 消息补偿机制 详细说明 这里使用了简单的代码进行演示&#xff0c;订单的消费者没有写&#xff0c;在订单的消费同时&#xff0c;发送一条增加积分消息到积分队列。 详细流程途中都有注明…

STM32+ov7725+ESP8266实现无线图传-完成上位机图像显示

一、需求 stm32f407探索者开发板和STM32F103ZET6战舰开发板。接正点原子ov5640、OV7725、OV2640摄像头,通过esp8266Wi-Fi模块(透传模式)将摄像头采集到的rgb565格式图片通过tcp/ip协议上传到上位机显示。 二、设计思路 【1】使用QT开发上位机,建立TCP服务器,接收ESP8266…

DistilPose: Tokenized Pose Regression with Heatmap Distillation

论文名字&#xff1a;DistilPose&#xff1a;使用热图蒸馏的令牌化姿势回归 论文地址&#xff1a;2303.02455.pdf (arxiv.org)https://arxiv.org/pdf/2303.02455.pdf项目地址&#xff1a;yshMars/DistilPose: Implementation for: DistilPose: Tokenized Pose Regression with…

科幻风的卡片视频播放

上一篇博文展示了卡片中的VR展示&#xff0c;那篇主要是卡片的3D转动来展示未显示的部分图片。这篇&#xff0c;我们来点科幻的。 我们在卡片中播放视频的同时来拖动卡片或转动它。像下面那样&#xff1a; 这个主要依赖了两个库&#xff0c;具体代码如下&#xff1a; <!D…

智能问答支持自定义问答

# -*- coding: utf-8 -*- # Time : 2023-5-12 14:15 # Author : shenzh # FileName: chat_bot_v1.py # Software: PyCharm """Description:一期智能机器人设计完成&#xff0c;支持自定义问题和答案随时增加功能""" import json import jie…

NOV Diagram for .NET Crack

NOV Diagram for .NET Crack 增加了对Microsoft.NET 7.0的支持-NOV现在完全支持.NET Core 7.0&#xff0c;此外还支持Microsoft.NET Framework 4.7.2、.NET Core 5.0和.NET Core 6.0的内部版本。 添加了对读取Microsoft Visio 2003-2010绘图(VSD文件)的支持。 改进了SVG导出。 …

哈希表应用——位图

应用场景&#xff1a;海量数据处理&#xff08;这里的海量是指一般数据量非常大如以亿为单位的数据量&#xff09; 目录 面试题 位图概念 位图的实现 位图的应用 应用一 应用二 位图应用变形 面试题 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&…

Java之多线程进阶

目录 一.上节内容复习 1.线程池的实现 2.自定义一个线程池,构造方法的参数及含义 3.线程池的工作原理 4.拒绝策略 5.为什么不推荐系统提供的线程池 二.常见的锁策略 1.乐观锁和悲观锁 2.轻量级锁和重量级锁 3.读写锁和普通互斥锁 4.自旋锁和挂起等待锁 5.可重入锁和…

精彩回顾 | Fortinet Accelerate 2023·中国区巡展厦门站

Fortinet Accelerate 2023中国区 5月16日&#xff0c;Fortinet Accelerate 2023中国区巡展来到魅力“鹭岛”——厦门&#xff0c;技术、产品和业务专家&#xff0c;携手亚马逊云科技、唯一网络等云、网、安合作伙伴&#xff0c;与交通、物流、金融等各行业典型代表客户&#x…

GPT大语言模型Vicuna本地化部署实践(效果秒杀Alpaca) | 京东云技术团队

​ 背景 上一篇文章《[GPT大语言模型Alpaca-lora本地化部署实践]》介绍了斯坦福大学的Alpaca-lora模型的本地化部署&#xff0c;并验证了实际的推理效果。 总体感觉其实并不是特别理想&#xff0c;原始Alpaca-lora模型对中文支持并不好&#xff0c;用52k的中文指令集对模型进…

信息安全工程实验——口令攻击和钓鱼攻击(自用)

目录 实验目的 实验原理 实验内容 练习1windows口令破解 1、基本操作 2、思考与总结 练习2&#xff1a;QQ 邮箱的钓鱼攻击 1、构造钓鱼页面 2、接收钓鱼所得的账号和密码&#xff08;分档&#xff09; 3、实验验证 4、思考与总结 实验目的 &#xff08;1&#xff09…

网络安全实验——信息收集与主机发现

目录 实验目的 实验原理 实验内容 1.信息搜集 1.ping探测 2. Nmap扫描 3. 探测总结 2.主机发现程序开发 3.主机发现 实验总结 实验目的 1.了解信息搜集的一般步骤。 2.学会熟练使用ping命令。 3.学会利用Nmap等工具进行信息搜集。 4.了解IP助手函数。 5.掌握Sen…