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

该文章演示了如何利用THREE.js库创建一个3D场景,用户可以通过拖拽工具栏中的3D模型到画布上,模型会在与地面相交的点生成,并自动调整位置。场景中包含环境光、点光源以及可交互的3D元素,如球体和地面网格。此外,还提供了重置场景的功能。
摘要由CSDN通过智能技术生成

e71234e73afc4f3f8b07f46ec842bfa1.gif

 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>

 

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
实现科目二车内场景,需要先了解 Three.js 的基础知识,包括场景、相机、渲染器、光源、材质和几何体等概念。 接下来,可以通过以下步骤实现科目二车内场景: 1. 创建场景对象 首先需要创建一个场景对象,用于存放所有的物体和光源。 ```javascript var scene = new THREE.Scene(); ``` 2. 创建相机对象 接下来需要创建一个相机对象,用于定义视角和裁剪平面。 ```javascript var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); ``` 3. 创建渲染器对象 渲染器对象用于将 3D 场景渲染到 HTML 页面上。 ```javascript var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); ``` 4. 添加光源 在场景中添加光源可以让物体产生阴影和真实感。 ```javascript var light = new THREE.PointLight(0xffffff, 1, 100); light.position.set(0, 0, 0); scene.add(light); ``` 5. 创建几何体和材质 接下来可以创建车内场景的几何体和材质了。可以使用 Three.js 内置的几何体和材质,也可以自定义。 ```javascript // 创建车座 var seatGeometry = new THREE.BoxGeometry(3, 0.5, 2); var seatMaterial = new THREE.MeshPhongMaterial({ color: 0x808080 }); var seatMesh = new THREE.Mesh(seatGeometry, seatMaterial); seatMesh.position.set(0, -0.5, 0); scene.add(seatMesh); // 创建方向盘 var steeringWheelGeometry = new THREE.CylinderGeometry(0.2, 0.2, 0.5, 32); var steeringWheelMaterial = new THREE.MeshPhongMaterial({ color: 0x808080 }); var steeringWheelMesh = new THREE.Mesh(steeringWheelGeometry, steeringWheelMaterial); steeringWheelMesh.position.set(1.5, 0, 0); scene.add(steeringWheelMesh); ``` 6. 渲染场景 最后需要调用渲染器对象的 render 方法,将场景渲染到 HTML 页面上。 ```javascript function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); ``` 通过以上步骤,就可以实现一个简单的科目二车内场景了。当然,还可以通过添加更多的几何体和材质、调整光源和相机等方式来增强场景的真实感。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11eleven

你的鼓励是我创作的动力 !

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值