主要内容: 使用 threejs 创建 20x20 的网格,鼠标移动时,方块跟随移动,点击时在网格任意位置放置方块,按 shift 时,删除当前位置方块。

流程如下:

  • 创建网格
  • 创建一个与网格同样尺寸的平面
  • 创建一个方块 mesh_1 与网格同样的尺寸
  • 一个与网格同样的方块 geometry_2 , 不加入 scene 中
  • 三个事件:
    • 鼠标移动事件,随着鼠标移动,更改 mesh_1 位置,并重新渲染
    • 鼠标点击事件,在交点位置,创建新 mesh, 若是相交对象不为 平面,则删除当前对象
    • keydown, keyup, 更改是否删除的状态

详细代码如下:


import * as THREE from './build/three.module'
import { stat } from 'fs'; var camera, scene, renderer;
var moveMesh, staticGeo,staticMat, plane;
var objects = [];
var raycaster, mouse;
var isShiftDown = false; function init() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(500, 800, 1300);
camera.lookAt(0, 0, 0); scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0); // lights
var light = new THREE.AmbientLight(0x606060);
scene.add(light); // grids
var grid = new THREE.GridHelper(1000, 20);
scene.add(grid); // plane, 辅助碰撞检测
var planeGeo = new THREE.PlaneBufferGeometry(1000, 1000);
var planMat = new THREE.MeshBasicMaterial({color: 0xffff00, visible : true});
plane = new THREE.Mesh(planeGeo, planMat);
plane.rotateX(-Math.PI /2);
scene.add(plane);
objects.add(plane); // 射线 raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2(); // moveCube;
var moveGeo = new THREE.BoxBufferGeometry(50, 50, 50);
var moveMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.5, transparent: true });
moveMesh = new THREE.Mesh(moveGeo, moveMaterial);
scene.add(moveMesh); // static cube
staticGeo = new THREE.BoxBufferGeometry(50, 50, 50);
staticMat = new THREE.MeshLambertMaterial({ color: 0xfeb74c, map: new THREE.TextureLoader().load('textures/square-outline-textured.png') }); renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement);
document.body.addEventListener('mousemove', onDocuementMouseMove, false);
document.body.addEventListener('mousedown', onDocumentMouseDown, false);
document.body.addEventListener('keydown', onDocuementKeyDown, false);
document.body.addEventListener('keyup', onDocuementKeyUp, false); window.addEventListener('resize', onWindowResize, false);
} function onDocumentMouseDown(event) {
event.preventDefault(); // 鼠标位置归一化
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 通过摄像机与鼠标更新射线
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
if(intersects.length > 0) {
var intersect = intersects[0];
if (isShiftDown) {
if(intersect.object !== plane) {
scene.remove(intersect.object);
objects.splice(objects.indexOf(intersect.object), 1);
}
}
else
{
var staticMesh = new THREE.Mesh(staticGeo, staticMat);
staticMesh.position.copy(intersect.point).add(intersect.face.normal);
staticMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);
scene.add(staticMesh);
objects.push(staticMesh);
}
} } function onDocuementMouseMove(event) {
event.preventDefault();
// 鼠标位置归一化
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 通过摄像机与鼠标更新射线
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects); if(intersects.length > 0) {
intersect = intersects[0];
// 移动位置到目标点
moveMesh.position.copy(intersect.point).add(intersect.face.normal);
// 计算具体方格
moveMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);
}
render();
} function onDocuementKeyDown(event) {
switch (event.keyCode) {
case 16: isShiftDown = true; break;
}
} function onDocuementKeyUp(event) {
switch (event.keyCode) {
case 16: isShiftDown = false; break;
}
} function onWindowResize() {
camera.aspect = window.innerWidth/ window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight); } function render()
{
renderer.render(scene, camera);
}

threejs 学习之的更多相关文章

  1. ThreeJS学习6_几何体相关(BufferGeometry)

    ThreeJS学习6_几何体相关(BufferGeometry) 使用 BufferGeometry 可以有效减少向 GPU 传输几何体相关数据所需的开销 可以自定义顶点位置, 面片索引, 法向量, ...

  2. # ThreeJS学习7_裁剪平面(clipping)

    ThreeJS学习7_裁剪平面(clipping) 目录 ThreeJS学习7_裁剪平面(clipping) 1. 裁剪平面简介 2. 全局裁剪和局部裁剪 3. 被多个裁剪平面裁剪后 4. 被多个裁剪 ...

  3. WebGL和ThreeJs学习6--射线法确定3D空间中所选物体

    一.在 threejs 中如何确定下图3D空间中鼠标点击位置的 object 对象? 二.射线法确定步骤及代码 //Three.js提供一个射线类Raycaster来拾取场景里面的物体.更方便的使用鼠 ...

  4. WebGL和ThreeJs学习5--ThreeJS基本功能控件

      Threejs 2017年6月6日 15:06 Stats: new Stats();性能监视器,性能测试的方法,引入 Stats.js        http://www.hewebgl.com ...

  5. threejs学习笔记(二)

    THREE.WebGLRenderer THREE.Scene THREE.OrthographicCamera正交相机 THREE.PerspectiveCamera透视相机 renderer.se ...

  6. threejs学习笔记(一)

    得到webgl的渲染管线

  7. threejs和3d各种效果的学习

    写给即将开始threejs学习的自己,各种尝试,各种记忆.不要怕,灰色的年华终会过去. 一个技术学习的快慢,以及你的深刻程度,还有你的以后遇到这个东西的时候的反应速度,很大程度上,取决于你的博客的深刻 ...

  8. 初识webgl--我的webgl学习第一课(基于threeJs)

    一,我为什么要学习webgl 一个偶然的机会,在和朋友的聊天过程中,听说了webgl,也许过去也看到过,但是没有特别在意过.原来,JavaScript也可以很好的渲染并在网页上显示三维动画,不用借助插 ...

  9. gis和threejs的学习资料

    *********************************** 基础知识/名词 瓦片/矢量瓦片GeoJson - 绘制GeoJson看数据, geojson规范, 中文版 ********** ...

随机推荐

  1. Facebook Libra - 第一笔交易

    第一笔交易 假定 运行的是Linux或者macOS系统 网络连接正常 git已安装 macOS中安装了Homebrew Linux中安装了yum或者apt-get 提交一笔交易的步骤 克隆并构建Lib ...

  2. akka 集群分片

    akka 集群 Sharding分片 分片上下级结构 集群(多台节点机) —> 每台节点机(1个片区) —> 每个片区(多个分片) —> 每个分片(多个实体) 实体: 分片管理的 A ...

  3. 【题解】生日蛋糕-C++

    Description 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体.设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, ...

  4. Linux 系统的基本操作及工具的使用

    基本操作命令如:useradd.userdel.passwd.su 添加用户.删除用户.修改密码.切换用户 ls.ll.cd.cp.mv.chmod ps.kil.man mkdir.touch.ta ...

  5. 【CYH-02】NOIp考砸后虐题赛:坐标:题解

    代码: 这道题也并不难,用排序+简单动规即可.因为@Kevin_Wa 大佬放的是c++,所以我来一发Pascal. var min,max,i,a1,b1,c1,d1,n:longint; a,b,c ...

  6. vijos P1848 记数问题

    自答[119ms内存456.0 KiB] #include<iostream>using namespace std;int num = 0;void judge(int n, int x ...

  7. 深入了解数据校验:Java Bean Validation 2.0(JSR380)

    每篇一句 吾皇一日不退役,尔等都是臣子 相关阅读 [小家Java]深入了解数据校验(Bean Validation):基础类打点(ValidationProvider.ConstraintDescri ...

  8. 如何优雅关闭 Spring Boot 应用

    ## 前言 随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kill 命令,这种停止应用的方式会让应用将所有处理 ...

  9. 【RabbitMQ】一文带你搞定RabbitMQ延迟队列

    本文口味:鱼香肉丝   预计阅读:10分钟 一.说明 在上一篇中,介绍了RabbitMQ中的死信队列是什么,何时使用以及如何使用RabbitMQ的死信队列.相信通过上一篇的学习,对于死信队列已经有了更 ...

  10. 解决Vuex持久化插件-在F5刷新页面后数据不见的问题

    页面刷新后,想保存页面未保存的数据.我们总是习惯于放在浏览器的sessionStorage和localStorage中.但是用了vue后,vuex便可以被应用了. vuex优势:相比sessionSt ...