<!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>

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

  1. 【three.js练习程序】创建简单物理场景

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. unity3d教程动态创建简单平面地形

    unity3d创建地形是不须要usingUnityEditor的.这里使用了AssetDatabase.所以需using UnityEditor; 创建三步: 1.TerrainData terrai ...

  3. 基于Babylon.js编写宇宙飞船模拟程序1——程序基础结构、物理引擎使用、三维罗盘

    计划做一个宇宙飞船模拟程序,首先做一些技术准备. 可以访问https://ljzc002.github.io/test/Spacetest/HTML/PAGE/spacetestwp2.html查看测 ...

  4. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  5. 使用Visual Studio 2010 创建简单的Silverlight应用程序

    使用Visual Studio 2010 创建简单的Silverlight应用程序 Silverlight是创建动态的引人的RIAs(Rich Internet Application)的新方法.这里 ...

  6. 在 Web 应用中创建 Node.js 应用程序

    本分步指南将通过 Azure Web 应用帮助您启动并运行示例 Node.JS 应用程序.除 Node.JS 外,Azure Web 应用还支持其他语言,如 PHP..NET.Node.JS.Pyth ...

  7. 用chrome的snippets片段功能创建页面js外挂程序,从控制台创建js小脚本

    用chrome的snippets片段功能创建页面js外挂程序,从控制台创建js小脚本 Chrome的snippets是小脚本,还可以创作并在Chrome DevTools的来源面板中执行.可以访问和从 ...

  8. 用简单的 Node.js 后台程序浅析 HTTP 请求与响应

    用简单的 Node.js 后台程序浅析 HTTP 请求与响应 本文写于 2020 年 1 月 18 日 我们来看两种方式发送 HTTP 请求,一种呢,是命令行的 curl 命令:一种呢是直接在浏览器的 ...

  9. Socket创建简单服务器和客户端程序

    使用Socket编程创建简单服务器和客户端 要知道的 Socket-AddressFamily, SocketType, ProtocolType https://blog.csdn.net/weix ...

随机推荐

  1. Centos配置vsftpd

    #安装vsftpdyum install vsftpd #限制用户只能访问配置的目录,不能访问其他路径#修改vi /etc/vsftpd/vsftpd.conf chroot_list_enable= ...

  2. ASP.NET Core 中使用 Hangfire 定时启动 Scrapyd 爬虫

    用 Scrapy 做好的爬虫使用 Scrapyd 来管理发布启动等工作,每次手动执行也很繁琐;考虑可以使用 Hangfire 集成在 web 工程里. Scrapyd 中启动爬虫的请求如下: curl ...

  3. Java设计模式之工厂方法模式(转) 实现是抽象工厂?

    Java设计模式之工厂方法模式 责任编辑:覃里作者:Java研究组织   2009-02-25   来源:IT168网站   文本Tag: 设计模式 Java [IT168 技术文章]         ...

  4. sql-原生jdbc连接7步

    原生jdbc链接一般分为7步, 来获取链接并执行sql语句 1, 准备4大参数 static { url = "jdbc:mysql://localhost:3306/test" ...

  5. CRM项目测试第一天

    经过前几天代码的修改,界面的完善.主要的功能都实现了!今天主要是交换各组的项目,互相来测试,找bug. 在互相测试的过程,我听见有一组应该算是讨论的比价激烈的!我们组我们自己找到了bug,但是测试我们 ...

  6. Docker基础教程(安装篇)

    Linux安装: 1.yum -y install docker-io 2.service docker start 3.chkconfig docker on Window安装: Docker 引擎 ...

  7. 从客户端(ASPxFormLayout1$txtRule="<YYYY><MM><DD><XXXX>")中检测到有潜在危险的 Request.Form 值

    在有文本框的值属于这种时<YYYY><MM><DD><XXXX>,会报这个错 在webconfig中加入 <httpRuntime request ...

  8. unity 中Canvas MatchHeight

    设置了 UI Scale Mode = Scale With Screen Size, Reference Resolution = X 1334, Y 750, Screen Match Mode ...

  9. Tomcat9.0环境搭建与源码编译

    使用IntelliJ IDEA  搭建Tomcat9.0项目   准备条件:   下载源码 这里我们下载的Tomcat的源码版本是9.0.12. 下载地址: https://tomcat.apache ...

  10. python基础训练题1-列表操作

    1,在列表末尾添加一个值 >>> l = [ 10, 20 ] >>> l [10, 20] >>> l.append( 'ghostwu' ) ...