【three.js练习程序】创建简单物理地形

2023-11-19

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ceshi</title>
    <style>
        body
        {
            margin: 0;
            overflow: hidden;
        }
    </style>
    <script src="./build/three.js"></script>
    <script src="./examples/js/libs/ammo.js"></script>
    <script src="./examples/js/controls/OrbitControls.js"></script>
    <script src="./examples/js/ImprovedNoise.js"></script>
</head>
<body>
    <div id="ThreeJs">
    </div>
    <script>
        var camera, controls, scene, renderer;
        var clock = new THREE.Clock();

        // 物理引擎相关变量
        var gravityConstant = -9.8;
        var collisionConfiguration;
        var dispatcher;
        var broadphase;
        var solver;
        var physicsWorld;
        var rigidBodies = [];
        var margin = 0.05;
        var transformAux1 = new Ammo.btTransform();
        var time = 0;

        // 高度场相关
        var terrainWidthExtents = 50;
        var terrainDepthExtents = 50;
        var terrainWidth = 50;
        var terrainDepth = 50;
        var terrainHalfWidth = terrainWidth / 2;
        var terrainHalfDepth = terrainDepth / 2;
        var terrainMaxHeight = 50;
        var terrainMinHeight = -20;
        var heightData = null;
        var ammoHeightData = null;

        init();
        animate();

        function init() {

            heightData = generateHeight(terrainWidth, terrainDepth);

            initGraphics();
            initPhysics();
            createObjects();
        }

        function initGraphics() {
            // three.js基本场景配置
            camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 2000);
            camera.position.x = 50;
            camera.position.y = 50;
            camera.position.z = 50;

            controls = new THREE.OrbitControls(camera);
            controls.target.y = 2;

            renderer = new THREE.WebGLRenderer();
            renderer.setClearColor(new THREE.Color("#bfd1e5"));
            renderer.shadowMapEnabled = true;
            renderer.setSize(window.innerWidth, window.innerHeight);
            // 场景
            scene = new THREE.Scene();
            // 环境光
            var ambientLight = new THREE.AmbientLight(0x404040);
            scene.add(ambientLight);
            // 线性光
            var light = new THREE.DirectionalLight(0xffffff, 1);
            light.position.set(-20, 20, 10);
            light.castShadow = true;
            var d = 50;
            light.shadow.camera.left = -d;
            light.shadow.camera.right = d;
            light.shadow.camera.top = d;
            light.shadow.camera.bottom = -d;

            light.shadow.camera.near = 2;
            light.shadow.camera.far = 50;

            light.shadow.mapSize.x = 1024;
            light.shadow.mapSize.y = 1024;
            scene.add(light);

            var axes = new THREE.AxisHelper(50);               //创建三轴表示
            scene.add(axes);
            // 添加窗口大小变化监听
            window.addEventListener('resize', onWindowResize, false);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function initPhysics() {
            // bullet基本场景配置
            collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
            dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
            broadphase = new Ammo.btDbvtBroadphase();
            solver = new Ammo.btSequentialImpulseConstraintSolver();
            physicsWorld = new Ammo.btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
            physicsWorld.setGravity(new Ammo.btVector3(0, gravityConstant, 0));
        }

        function createObjects() {
            var pos = new THREE.Vector3();
            var quat = new THREE.Quaternion();

            //创建物理地形
            var geometry = new THREE.PlaneBufferGeometry(50, 50, terrainWidth - 1, terrainDepth - 1);
            geometry.rotateX(-Math.PI / 2);
            var vertices = geometry.attributes.position.array;
            for (var i = 0, j = 0, l = vertices.length; i < l; i++, j += 3) {
                // j + 1 because it is the y component that we modify
                vertices[j + 1] = heightData[i];
            }
            geometry.computeVertexNormals();
            var groundMaterial = new THREE.MeshPhongMaterial({ color: 0xC7C7C7 });
            terrainMesh = new THREE.Mesh(geometry, groundMaterial);
            terrainMesh.receiveShadow = true;
            terrainMesh.castShadow = true;
            scene.add(terrainMesh);

            var groundShape = createTerrainShape(heightData);
            var groundTransform = new Ammo.btTransform();
            groundTransform.setIdentity();
            // 设置bullet计算时物体中心
            groundTransform.setOrigin(new Ammo.btVector3(0, (terrainMaxHeight + terrainMinHeight) / 2, 0));
            var groundMass = 0;
            var groundLocalInertia = new Ammo.btVector3(0, 0, 0);
            var groundMotionState = new Ammo.btDefaultMotionState(groundTransform);
            var groundBody = new Ammo.btRigidBody(new Ammo.btRigidBodyConstructionInfo(groundMass, groundMotionState, groundShape, groundLocalInertia));
            physicsWorld.addRigidBody(groundBody);

            //创建50个小球
            for (var i = 0; i < 50; i++) {
                var ballMass = 1.2;
                var ballRadius = 0.5;

                var ball = new THREE.Mesh(new THREE.SphereGeometry(ballRadius, 20, 20), createRendomColorObjectMeatrial());
                ball.castShadow = true;
                ball.receiveShadow = true;
                var ballShape = new Ammo.btSphereShape(ballRadius);
                ballShape.setMargin(margin);
                pos.set(Math.random() + 10, 3 * (i + 1) + 20, Math.random() - 10);
                quat.set(0, 0, 0, 1);
                createRigidBody(ball, ballShape, ballMass, pos, quat);
                ball.userData.physicsBody.setFriction(1.5);
            }

            //创建50个方块
            for (var i = 0; i < 50; i++) {
                pos.set(Math.random() - 10, 3 * (i + 1) + 20, Math.random() + 10);
                quat.set(0, 0, 0, 1);
                createParallellepiped(1, 1, 1, 1, pos, quat, createRendomColorObjectMeatrial());
            }
        }

        function createRendomColorObjectMeatrial() {
            var color = Math.floor(Math.random() * (1 << 24));
            return new THREE.MeshPhongMaterial({ color: color });
        }

        function createParallellepiped(sx, sy, sz, mass, pos, quat, material) {
            var threeObject = new THREE.Mesh(new THREE.BoxGeometry(sx, sy, sz, 1, 1, 1), material);
            threeObject.castShadow = true;
            threeObject.receiveShadow = true;
            var shape = new Ammo.btBoxShape(new Ammo.btVector3(sx * 0.5, sy * 0.5, sz * 0.5));
            shape.setMargin(margin);
            createRigidBody(threeObject, shape, mass, pos, quat);
            return threeObject;
        }

        function createRigidBody(threeObject, physicsShape, mass, pos, quat) {
            threeObject.position.copy(pos);
            threeObject.quaternion.copy(quat);
            var transform = new Ammo.btTransform();
            transform.setIdentity();
            transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z));
            transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w));
            var motionState = new Ammo.btDefaultMotionState(transform);
            var localInertia = new Ammo.btVector3(0, 0, 0);
            physicsShape.calculateLocalInertia(mass, localInertia);
            var rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, physicsShape, localInertia);
            var body = new Ammo.btRigidBody(rbInfo);
            threeObject.userData.physicsBody = body;
            scene.add(threeObject);
            if (mass > 0) {
                rigidBodies.push(threeObject);
                body.setActivationState(4);
            }
            physicsWorld.addRigidBody(body);
            return body;
        }

        function animate() {
            requestAnimationFrame(animate);
            var deltaTime = clock.getDelta();
            updatePhysics(deltaTime);
            controls.update(deltaTime);
            renderer.render(scene, camera);
            time += deltaTime;
        }

        function updatePhysics(deltaTime) {
            physicsWorld.stepSimulation(deltaTime);
            // 更新物体位置
            for (var i = 0, iL = rigidBodies.length; i < iL; i++) {
                var objThree = rigidBodies[i];
                var objPhys = objThree.userData.physicsBody;
                var ms = objPhys.getMotionState();
                if (ms) {
                    ms.getWorldTransform(transformAux1);
                    var p = transformAux1.getOrigin();
                    var q = transformAux1.getRotation();
                    objThree.position.set(p.x(), p.y(), p.z());
                    objThree.quaternion.set(q.x(), q.y(), q.z(), q.w());
                }
            }
        }

        function generateHeight(width, height) {
            var size = width * height, data = new Float32Array(size),
                perlin = new ImprovedNoise(), quality = 1, z = Math.random() * 10;
            for (var j = 0; j < 4; j++) {
                for (var i = 0; i < size; i++) {
                    var x = i % width, y = ~ ~(i / width);
                    data[i] += Math.abs(perlin.noise(x / quality, y / quality, z) * quality);
                }
                quality *= 3;
            }
            return data;
        }

        // 生成物理引擎用高度场
        function createTerrainShape(heightData) {
            // This parameter is not really used, since we are using PHY_FLOAT height data type and hence it is ignored
            var heightScale = 1;
            // Up axis = 0 for X, 1 for Y, 2 for Z. Normally 1 = Y is used.
            var upAxis = 1;
            // hdt, height data type. "PHY_FLOAT" is used. Possible values are "PHY_FLOAT", "PHY_UCHAR", "PHY_SHORT"
            var hdt = "PHY_FLOAT";
            // Set this to your needs (inverts the triangles)
            var flipQuadEdges = false;
            // Creates height data buffer in Ammo heap
            ammoHeightData = Ammo._malloc(4 * terrainWidth * terrainDepth);
            // Copy the javascript height data array to the Ammo one.
            var p = 0;
            var p2 = 0;
            for (var j = 0; j < terrainDepth; j++) {
                for (var i = 0; i < terrainWidth; i++) {
                    // write 32-bit float data to memory
                    Ammo.HEAPF32[ammoHeightData + p2 >> 2] = heightData[p];
                    p++;
                    // 4 bytes/float
                    p2 += 4;
                }
            }
            // Creates the heightfield physics shape
            var heightFieldShape = new Ammo.btHeightfieldTerrainShape(
                terrainWidth,
                terrainDepth,
                ammoHeightData,
                heightScale,
                terrainMinHeight,
                terrainMaxHeight,
                upAxis,
                hdt,
                flipQuadEdges
        );
            // Set horizontal scale
            var scaleX = terrainWidthExtents / (terrainWidth - 1);
            var scaleZ = terrainDepthExtents / (terrainDepth - 1);
            heightFieldShape.setLocalScaling(new Ammo.btVector3(scaleX, 1, scaleZ));
            heightFieldShape.setMargin(0.05);
            return heightFieldShape;
        }

        document.getElementById("ThreeJs").appendChild(renderer.domElement);
    </script>
</html>

 

转载于:https://www.cnblogs.com/tiandsp/p/8455228.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【three.js练习程序】创建简单物理地形 的相关文章

  • Imgur API 版本 3 JavaScript 上传示例

    我在网上找到的所有示例都是早期版本的 Imgur API 或非 JS 代码 所有这些都使用新 API 中不存在的 API 密钥 相反 你会得到一个client id and secret 任何人都有示例代码 展示如何使用其 API 版本 3
  • 在生产中使用 babel-node 可以吗

    我一直在使用 babel node 和 browserify 以及 babelify 转换来开发一个网站 以支持 ES6 语法 我只是想知道 我可以在生产中运行它吗 babel node server 而不是 node server 要在
  • 如何将 div (或任何元素)覆盖在表格行 (tr) 上?

    我想在恰好有多个列的表行 tr 标记 上覆盖一个 div 或任何可以使用的元素 我尝试了几种方法 似乎都不起作用 我在下面发布了我当前的代码 我确实得到了一个覆盖 但不是直接覆盖在该行上 我尝试将覆盖顶部设置为 div Bottom css
  • 执行页面的 javascript 后保存页面的 html 输出

    我正在尝试抓取一个网站 它首先加载 html js 使用js修改表单输入字段 然后使用POST 如何获得 POSTed 页面的最终 html 输出 我尝试使用 phantomjs 执行此操作 但它似乎只有渲染图像文件的选项 谷歌搜索表明这应
  • 在 Angular 单元测试中应该如何处理运行块?

    我的理解是 当您在 Angular 单元测试中加载模块时 run块被调用 我认为如果你正在测试一个组件 你不会想同时测试run块 因为unit测试应该只是测试一个unit 真的吗 如果是的话有什么办法可以防止run阻止运行 我的研究让我认为
  • Chrome 内存/垃圾收集问题

    我在使用 Chrome 时遇到内存 垃圾收集问题 我正在开发一个照片上传网站 该网站允许我的客户使用 HTML5 和文件 API 拖放照片进行上传 因此这在 IE 中不起作用 它仅适用于 Chrome 和 FF 我还没有在 Safari O
  • Vue Draggable - 如何仅替换所选项目以防止移动网格上的所有其他项目?

    这是一个要测试的示例 https codesandbox io s j4vn761455 file src App vue 112 116 https codesandbox io s j4vn761455 file src App vue
  • SVG 中三角形的圆角

    我正在尝试制作一个具有圆角的三角形 三角形将如下所示 左下角是唯一看起来相当容易制作的角 主要是因为这是一个 90 度的 转弯 该转弯是使用QSVG 中的命令具有以下参数 Q x y height x y height RADIUS从我正在
  • 如何在启用导航栏的情况下打开新的浏览器窗口?

    我有这个JS方法 function OpenLink strDestination var features left 10 top 10 location 0 menubar 0 resizable 0 scrollbars 1 stat
  • Famo.us 滚动视图高度

    我正在尝试使用著名的顺序布局在滚动视图下方添加图像 但滚动视图的高度有问题 这就是我创建滚动视图的方式 var scrollview new Scrollview direction Utility Direction X options
  • AngularJS - 服务、工厂、过滤器等中的依赖注入

    因此 我想在我的 Angular 应用程序中使用一些插件和库 目前 我只是引用这些函数 方法 因为它们是在 99 的应用程序中以完全忽略依赖注入的方式使用的 我有 例如 javascript 库 MomentJS 它处理格式化和验证日期 并
  • jspm / jQuery / TypeScript - 模块“jquery”没有默认导出

    我正在尝试使用 TypeScript 和 jspm system js 来引导 Web 应用程序进行模块加载 我还没有走多远 安装 jspm 后 并使用它来安装 jQuery jspm install jquery 以及基础知识 main
  • 大型应用的回流/布局性能

    我正在使用 GWT 构建一个 HTML 应用程序 其性能总体上是正确的 有时 它会加载 DOM 中的许多对象 并且应用程序会变得很慢 我使用 Chrome 开发者工具分析器来查看时间花在哪里 在 Chrome 下 一旦应用程序被编译 即没有
  • 表单序列化javascript(无框架)

    想知道 javascript 中是否有一个没有 jquery 或任何框架的函数可以让我序列化表单并访问序列化版本 2023 年更新 Use FormData https developer mozilla org en US docs We
  • 使用 Socket.IO 时如何访问会话标识符?

    我有一个聊天 我需要管理独特的连接 我四处搜寻 但我找到的解决方案似乎都已被弃用 那么 如何使用 Socket IO 获取套接字的会话 ID 我在用着Node js http en wikipedia org wiki Node js Ex
  • 在多个数组中搜索字符串,然后设置 var - jQuery

    我正在寻找基于字符串存在于哪个数组中设置一个变量 例如 var primary red blue yellow var secondary orange purple green 然后检查 purple 并返回它在 secondary 数组
  • 简单的颜色变化

    我正在创建一个用户界面 用户可以在其中更改页面的颜色值 我想要的是获取分配给其背景颜色的值并将其变亮一定程度 我只是想获得一条亮点线 而不必每次都制作新图像 示例 用户将背景颜色设置为 ECECEC 现在我希望某个元素边框变成 F4F4F4
  • 无法从 JSON 请求获取数据,尽管我知道它已返回

    我试图获取从 getJSON 返回的数据 但我无法让它工作 我已经在 search twitter API 上尝试了相同的代码 效果很好 但它不适用于其他网站 我知道数据已返回 因为我在使用检查器时可以找到它 我通过检查器找到的值是 id
  • 在 Firefox 中使用 Javascript 检测键盘布局

    有没有办法在 Firefox 中检测客户端的键盘布局 我知道 Chrome 的答案是肯定的 请参阅https developer mozilla org en US docs Web API Navigator keyboard https
  • 如何从react-bootstrap复选框获取值/属性?

    我正在尝试使用反应引导复选框 https react bootstrap github io components html forms controls https react bootstrap github io components

随机推荐

  • MES系统给制造型企业带来了哪些效益

    MES系统要怎么给制造型企业带来效益 在这场剧烈的市场竞争中 制造企业不只要在产品质量和创新上具有竞争优势 而且产品的价格在很大程度上决定了企业的市场竞争力 MES系统如何去打破生产暗箱 建造通明化工厂 提高生产效率 如今 中国工厂存在两大
  • 逃逸闭包和非逃逸闭包

    在使用swift开发 使用闭包作为参数传递到函数中 但是总是默认提示加上 escaping 逃逸闭包 是指闭包在函数结束时 闭包就会随着函数的结束而被释放 非逃逸闭包 是指闭包在函数结束时 逃逸函数 不会随函数的结束而被释放 在该闭包执行后
  • ubuntu 下实现 docker+ovs+quagga搭建网络---bgp

    注 本机上现有quagga镜像 ovs虚拟交换机 2 9 1 docker 18 09 7 实现bgp网络搭建 1 sudo ovs vsctl add br br1 增加一个ovs网桥br1 2 sudo docker images 查看
  • ADFS 概念与基本开发介绍 (1)

    如您转载本文 必须标明本文作者及出处 如有任何疑问请与我联系 me nap7 com ADFS 相关开发技术的中文资料相对匮乏 之前再弄这个东西的时候搞的比较辛苦 因此总结此文档 以解后人之忧 本文会首先介绍与联合身份验证有关的概念及相关的
  • 泰迪杯挑战赛优秀论文-A题-基于数据挖掘的上市公司高送转预测

    目 录 第 1 章 绪论 1 1问题背景 1 2问题重述 1 3本文主要工作与创新点 1 4模型假设 1 5本文研究意义 第 2 章 相关理论 2 1高送转相关知识介绍 2 1 1高送转的实质 2 1 2预测下一年上市公司高送转的一些其他条
  • Redis 事务

    目录 Redis 事务 一 Redis事务的概念 二 redis事务提出的逻辑 三 redis事务的基本操作 四 事务的执行流程 五 redis锁 六 redis分布式锁 Redis 事务 一 Redis事务的概念 Redis 事务的本质是
  • 3、思科模拟器介绍 (认识思科模拟器界面、安装思科模拟器、思科模拟器汉化)

    认识思科模拟器界面 标题栏 菜单栏 思科模拟器软件包 CSDN思科模拟器安装 https download csdn net download weixin 53645521 85135225 百度网盘思科模拟器安装包 链接 https p
  • 图像恢复(加噪与去噪)

    人工智能导论实验导航 实验一 斑马问题 https blog csdn net weixin 46291251 article details 122246347 实验二 图像恢复 https blog csdn net weixin 46
  • tar命令笔记

    作用 tar 可以保存文件属性 本身不具备压缩能力 配合gzip或者bzip 进行压缩解压缩 参数 相关参数如下 来自百度百科 c create 创建新的tar文件 x extract get 解开tar文件 t list 列出tar文件中
  • 火狐浏览器文本两端对齐无效text-align: justify

    找了很多地方 尝试很多办法都不好使 直到看到这篇 只需要设置了text align justify时加设一个white space pre line就可以了
  • [Docker]使用Docker部署Kafka

    Kafka 是一个分布式流处理平台 它依赖于 ZooKeeper 作为其协调服务 在 Kafka 集群中 ZooKeeper 负责管理和协调 Kafka 的各个节点 因此 要在 Docker 容器中启动 Kafka 通常需要同时启动一个 Z
  • 对数器的简单使用

    对数器 1 前言 2 内容 简介对数器 以排序算法的检测为实例 3 总结 4 更新日志 1 前言 学习左神的数据结构的过程中 推荐使用对数器检验自己的算法是否正确 2 内容 简介对数器 1 对数器的作用 在一个题目未OJ的时候 可以通过对数
  • Transformer学习笔记

    一 Transformer诞生背景 Transformer模型是解决序列转录问题的一大创新 在Transformer模型之前 序列转录模型都或多或少的基于复杂的循环或卷积神经网络 循环神经网络的计算是时序性的 位置的计算必须基于之前所有位置
  • 微信小程序数据 \n 换行符失效解决办法

    最近遇到一个问题 使用uni app写小程序时 拿到一个字符串 后台返回的 需要在 n 处换行 但是直接使用 let title 黄鹤楼送 n孟浩然之广陵
  • 使用python对银行信息管理系统的简单实现

    一 首先是用户属性的类 class account object 储存用户信息的类 def init self id1 name tel money self id id1 账户 self name name 姓名 self tel tel
  • mo管理器java_Android开发之通过包管理器获取安装应用信息

    最近在自己写一个APP 有一个模块需要获取手机应用的一些信息 坑还是有 但都基本踩过了 自己把他实现了出来 实现方法还是很需要掌握的 底部弹出的对话框中四个选项的实现不多做说明 主要讲讲如何获取这些安装的应用信息 好了 不多说 看看效果图
  • 1024,干程序才懂得节日!

    1024程序员节 1024程序员节是广大程序员的共同节日 1024是2的十次方 二进制计数的基本计量单位之一 针对程序员经常周末加班与工作日熬夜的情况 部分互联网机构倡议每年的10月24日为1024程序员节 在这一天建议程序员拒绝加班 程序
  • 【C/C++】报错问题积累

    1 出现Deprecated declaration XXX give arg types c文件中 有没有参数的函数时 声明需要加void即 main c void fun main h void fun void
  • androidX 在AndroidMainfest里面加入provider后编译不通过

  • 【three.js练习程序】创建简单物理地形