THREE.js - 旋转移动 3D 球

2023-12-23

我是 THREE.js 的新手,对物理学的了解非常少 - 但我正在尝试构建一个足球游戏引擎(从顶部看),而现在我正在努力处理球的运动。

当尝试将球从一侧移动到另一侧时,旋转始终面向一个方向,我不明白如何使其沿其移动方向旋转。

我添加了一个简单的代码来显示这个问题。非常感谢您的帮助。

     /*
            *
            * SET UP MOTION PARAMS
            * 
            */

            var degrees = 10;
            var power = 1;
            var angleRad = degrees * Math.PI / 120;

            var velocityX = Math.cos(angleRad) * power;
            var velocityY = Math.sin(angleRad) * power;
            var velocityZ = 1;

            var friction = 1;
            var gravity = 0.2;
            var bounciness = 0.9;



            window.onload = function (params) {

                /*
                *
                * SET UP THE WORLD
                * 
                */
                
                
                
                //set up the ratio
                var gWidth = window.innerWidth;
                var gHeight = window.innerHeight;
                var ratio = gWidth / gHeight;
                var borders = [40, 24] //indicate where the ball needs to move in mirror position


                //set the scene
                scene = new THREE.Scene();
                scene.background = new THREE.Color(0xeaeaea);

                //set the camera
                var camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
                camera.position.z = 120;   

                //set the light
                var light = new THREE.SpotLight(0xffffff, 1);
                light.position.set(100, 1, 0); 		
                light.castShadow = true;         
                light.position.set(0, 0, 100);
                scene.add(light);

                //  set the renderer 
                var renderer = new THREE.WebGLRenderer();

                //properties for casting shadow
                renderer.shadowMap.enabled = true;
                renderer.shadowMap.type = THREE.PCFSoftShadowMap; 

                renderer.setSize(gWidth, gHeight);
                document.body.appendChild(renderer.domElement);



                
                /*
                *
                * ADD MESH TO SCENE
                * 
                */


                // create and add the ball
                var geometry = new THREE.SphereGeometry(5, 5, 5);
                var material = new THREE.MeshLambertMaterial({ color: 'gray' });
                var ball = new THREE.Mesh(geometry, material);

                ball.castShadow = true;
                ball.receiveShadow = false;
                scene.add(ball);


                
                // create and add the field
                var margin = 20;
                var fieldRatio = 105 / 68;

                var width = 90;
                var height = width / fieldRatio;

                var material = new THREE.MeshLambertMaterial({ color: 'green' });
                var geometry = new THREE.BoxGeometry(width, height, 1);
                var field = new THREE.Mesh(geometry, material);

                field.receiveShadow = true;
                field.position.z = -1;
                scene.add(field);




                /*
                * setting up rotation axis 
                */


                var rotation_matrix = null;

                var setQuaternions = function () {
                    setMatrix();
                    ball.rotation.set(Math.PI / 2, Math.PI / 4, Math.PI / 4); // Set initial rotation
                    ball.matrix.makeRotationFromEuler(ball.rotation); // Apply rotation to the object's matrix
                }

                var setMatrix = function () {
                    rotation_matrix = new THREE.Matrix4().makeRotationZ(angleRad); // Animated rotation will be in .01 radians along object's X axis
                }

                setQuaternions();


                /*
                *
                * ANIMATION STEP
                * 
                */

                var render = function (params) {

                    // add velocity to ball
                    ball.position.x += velocityX;
                    ball.position.z += velocityZ;
                    ball.position.y += velocityY;


                    //validate if ball is stop moving
                    if (Math.abs(velocityX) < 0.02 && Math.abs(velocityY) < 0.02) {
                        console.log("DONE!");
                        return;
                    }



                    // handle boucing effect
                    if (ball.position.z < 1) {
                        velocityZ *= -bounciness;
                        ball.position.z = 1
                    }


                    // Update the object's rotation & apply it
                    ball.matrix.multiply(rotation_matrix);
                    ball.rotation.setFromRotationMatrix(ball.matrix);


                    //reducing speed by friction
                    angleRad *= friction;
                    velocityX *= friction;
                    velocityY *= friction;
                    velocityZ *= friction;


                    //set up the matrix 
                    setMatrix();
                    


                    //validate ball is withing its borders otherwise go in the mirror direction
                    if (Math.abs(ball.position.x) > borders[0]) {
                        velocityX *= -1;
                        ball.position.x = (ball.position.x < 0) ? borders[0] * -1 : borders[0];
                    }

                    if (Math.abs(ball.position.y) > borders[1]) {
                        velocityY *= -1;
                        ball.position.y = (ball.position.y < 0) ? borders[1] * -1 : borders[1];
                    }


                    // reduce ball height with gravity
                    velocityZ -= gravity;

                    

                    //render the page
                    renderer.render(scene, camera);

                    requestAnimationFrame(render);
                }

                render();

            }
body {
    padding: 0;
    margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<html>

<head>

</head>

<body>
</body>

</html>

如果你想包括摩擦力和惯性等,这实际上是一种非常先进的物理学,可以以超现实的方式进行。但是你可以采取一些捷径来获得不错的视觉滚动效果......

如果你在球的运动方向上取向量,你可以通过运动向量与世界向上向量的叉积得到一个垂直向量。

该矢量是球在与地面完全摩擦时绕其旋转的轴。一旦有了该轴,您就可以对对象使用 .rotateOnWorldAxis ( axis : Vector3,angle : Float )。

然后你必须根据球的半径和行进的距离计算出旋转多少。所以它是运动矢量 * (PI*2) / 周长的长度(在下面的代码中称为幅度)球的。

让我知道这是否有帮助...

p.s - 你的“angleRad”计算除以120而不是180..我修复了这个问题。

/*
 *
 * SET UP MOTION PARAMS
 * 
 */

var degrees = 35;
var power = 0.45;
var angleRad = degrees * Math.PI / 180;

var velocityX = Math.cos(angleRad) * power;
var velocityY = Math.sin(angleRad) * power;
var velocityZ = 1;

var friction = 1;
var gravity = 0.2;
var bounciness = 0.9;

var ballRadius = 5;
var ballCircumference = Math.PI * ballRadius * 2;
var ballVelocity = new THREE.Vector3();
var ballRotationAxis = new THREE.Vector3(0, 1, 0);


window.onload = function(params) {

  /*
   *
   * SET UP THE WORLD
   * 
   */



  //set up the ratio
  var gWidth = window.innerWidth;
  var gHeight = window.innerHeight;
  var ratio = gWidth / gHeight;
  var borders = [40, 24] //indicate where the ball needs to move in mirror position


  //set the scene
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xeaeaea);

  //set the camera
  var camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
  camera.position.z = 120;

  //set the light
  var light = new THREE.SpotLight(0xffffff, 1);
  light.position.set(100, 1, 0);
  light.castShadow = true;
  light.position.set(0, 0, 35);
  scene.add(light);

  //  set the renderer 
  var renderer = new THREE.WebGLRenderer();

  //properties for casting shadow
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;

  renderer.setSize(gWidth, gHeight);
  document.body.appendChild(renderer.domElement);




  /*
   *
   * ADD MESH TO SCENE
   * 
   */


  // create and add the ball
  var geometry = new THREE.SphereGeometry(ballRadius, 8, 8);

  //make a checkerboard texture for the ball...
  var canv = document.createElement('canvas')
  canv.width = canv.height = 256;
  var ctx = canv.getContext('2d')
  ctx.fillStyle = 'white';
  ctx.fillRect(0, 0, 256, 256);
  ctx.fillStyle = 'black';
  
  for (var y = 0; y < 16; y++)
    for (var x = 0; x < 16; x++)
      if ((x & 1) != (y & 1)) ctx.fillRect(x * 16, y * 16, 16, 16);
  var ballTex = new THREE.Texture(canv);
  ballTex.needsUpdate = true;


  var material = new THREE.MeshLambertMaterial({
    map: ballTex
  });
  var ball = new THREE.Mesh(geometry, material);

  ball.castShadow = true;
  ball.receiveShadow = false;
  scene.add(ball);



  // create and add the field
  var margin = 20;
  var fieldRatio = 105 / 68;

  var width = 90;
  var height = width / fieldRatio;

  var material = new THREE.MeshLambertMaterial({
    color: 'green'
  });
  var geometry = new THREE.BoxGeometry(width, height, 1);
  var field = new THREE.Mesh(geometry, material);

  field.receiveShadow = true;
  field.position.z = -1;
  scene.add(field);




  /*
   * setting up rotation axis 
   */


  var rotation_matrix = null;

  var setQuaternions = function() {
    setMatrix();
    ball.rotation.set(Math.PI / 2, Math.PI / 4, Math.PI / 4); // Set initial rotation
    ball.matrix.makeRotationFromEuler(ball.rotation); // Apply rotation to the object's matrix
  }

  var setMatrix = function() {
    rotation_matrix = new THREE.Matrix4().makeRotationZ(angleRad); // Animated rotation will be in .01 radians along object's X axis
  }

  setQuaternions();


  /*
   *
   * ANIMATION STEP
   * 
   */

  var render = function(params) {

    // add velocity to ball
    ball.position.x += velocityX;
    ball.position.z += velocityZ;
    ball.position.y += velocityY;


    //validate if ball is stop moving
    if (Math.abs(velocityX) < 0.02 && Math.abs(velocityY) < 0.02) {
      console.log("DONE!");
      return;
    }



    // handle boucing effect
    if (ball.position.z < 1) {
      velocityZ *= -bounciness;
      ball.position.z = 1
    }


    // Update the object's rotation & apply it
    /*
                    ball.matrix.multiply(rotation_matrix);   ball.rotation.setFromRotationMatrix(ball.matrix);
    //set up the matrix 
    setMatrix();
*/

    // Figure out the rotation based on the velocity and radius of the ball...
    ballVelocity.set(velocityX, velocityY, velocityZ);
    ballRotationAxis.set(0, 0, 1).cross(ballVelocity).normalize();
    var velocityMag = ballVelocity.length();
    var rotationAmount = velocityMag * (Math.PI * 2) / ballCircumference;
    ball.rotateOnWorldAxis(ballRotationAxis, rotationAmount)


    //reducing speed by friction
    angleRad *= friction;
    velocityX *= friction;
    velocityY *= friction;
    velocityZ *= friction;





    //validate ball is withing its borders otherwise go in the mirror direction
    if (Math.abs(ball.position.x) > borders[0]) {
      velocityX *= -1;
      ball.position.x = (ball.position.x < 0) ? borders[0] * -1 : borders[0];
    }

    if (Math.abs(ball.position.y) > borders[1]) {
      velocityY *= -1;
      ball.position.y = (ball.position.y < 0) ? borders[1] * -1 : borders[1];
    }


    // reduce ball height with gravity
    velocityZ -= gravity;



    //render the page
    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  render();

}
body {
  padding: 0;
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<html>

<head>

</head>

<body>
</body>

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

THREE.js - 旋转移动 3D 球 的相关文章

  • dojo dijit.form.DateTextBox 约束不起作用,datetextbox

    嗨 我是 javascript 和 dojo 的新手 我正在尝试使用两个带有下拉日历的 dijit DateTextBox 来建立数据库查询的日期范围 一旦选择了开始日期或结束日期 我想限制可用的日期 以便不可能选择按时间顺序排列在开始日期
  • 如何在同一页面上使用AJAX处理多个表单

    我有一个表单 当我单击 提交 时 它就被提交了 然后该表单隐藏 操作页面的结果显示在 div 中 classname dig 它工作正常 但是当我添加另一个表单时 它停止正常工作并且所有表单同时提交 我如何更改我的代码 done click
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • jquery.find() 可以只选择直接子项吗?

    我应该向 jQuery find 提供什么参数来选择元素子元素而不选择其他元素 我不能用 gt 引导选择器 而用 将选择所有后代 而不仅仅是直接子代 我知道 jQuery children 但这是一个库 因此用户能够提供自己的选择器 并且我
  • 使用 useReducers 调度函数发送多个操作?

    使用时是否可以通过调度函数发送多个动作useReducer挂钩反应 我尝试向它传递一组操作 但这会引发未处理的运行时异常 明确地说 通常会有一个初始状态对象和一个减速器 如下所示 const initialState message1 nu
  • 我想检查 $('#td1').text() === "x" 是否?

    我想检查innerHtml是否有X或O 所以我不能再次添加任何其他东西 但它不起作用 添加检查代码后它就停止了 我在这里尝试做一个简单的XO游戏来更熟悉javascript和jquery 我也不确定是否可以用 jQuery 做到这一点
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 使用 jQuery/JS 打开时使
    标签的内容具有动画效果

    我只想要 HTML5 的内容details标记为 滑行 动画打开 而不是仅仅弹出打开 立即出现 这可以用 jQuery Javascript 实现吗 Fiddle http jsfiddle net 9h4Hq HTML
  • 检查 JavaScript 字符串是否为 URL

    JavaScript 有没有办法检查字符串是否是 URL 正则表达式被排除在外 因为 URL 很可能是这样写的stackoverflow 也就是说它可能没有 com www or http 如果你想检查一个字符串是否是有效的 HTTP UR
  • 从未用 @flow 标记的导入文件中获取类型定义

    TL DR我怎么告诉flow从未声明的导入模块导入类型定义 flow 加长版 流接缝能够从不使用流语法的文件中派生类型 请参阅示例 示例文件 flow js if Math random lt 0 5 var y hello else va
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • 表单计算器脚本基本价格未加载 OnLoad

    我的表单中有一个计算器来计算我的下拉选项选择 function select calculate on change calc input type checkbox calculate on click calc function cal
  • Babel 7 Jest Core JS“TypeError:wks不是函数”

    将我的项目升级到 Babel 7 后 通过 Jest 运行测试会抛出以下错误 测试在 Babel 6 中运行没有任何问题 但在 Babel 7 中失败并出现以下错误 TypeError wks is not a function at Ob
  • Firefox 书签探索未超过 Javascript 的第一级

    我已经编写了一些代码来探索我的 Firefox 书签 但我只获得了第一级书签 即我没有获得文件夹中的链接 e g 搜索引擎 雅虎网站 谷歌网站 在此示例中 我只能访问 Search engines 和 google com 不能访问 yah
  • 提交表单并重定向页面

    我在 SO 上看到了很多与此相关的其他问题 但没有一个对我有用 我正在尝试提交POST表单 然后将用户重定向到另一个页面 但我无法同时实现这两种情况 我可以获取重定向或帖子 但不能同时获取两者 这是我现在所拥有的
  • Electron - 为什么在关闭事件时将 BrowserWindow 实例设置为 null

    The 电子文档 https electronjs org docs api browser window 提供以下代码示例来创建新窗口 const BrowserWindow require electron let win new Br
  • 如何使用tampermonkey模拟react应用程序中的点击?

    我正在尝试使用 Tampermonkey 脚本模拟对 React 元素的点击 不幸的是 由于 React 有自己的影子 DOM 所以天真的方法使用document querySelector 不工作 我遇到了一些需要修改 React 组件本
  • Laravel 中只向登录用户显示按钮

    如果我以 John 身份登录 如何才能只显示 John 的红色按钮而不显示 Susan 的红色按钮 测试系统环境 Win10 Laravel5 4 Mysql5 7 19 table class table table responsive
  • 条件在反应本机生产中失败,但在开发中有效

    我创建了一个反应本机应用程序 我需要通过它进行比较 如果属实 就会执行死刑 问题是 该条件适用于 React Native 开发模式 而不适用于 React Native 生产版本 我使用 firebase 作为数据库 也使用 redux
  • 导致回发到与弹出窗口不同的页面

    我有一个主页和一个详细信息页面 详细信息页面是从主页调用的 JavaScript 弹出窗口 当单击详细信息页面上的 保存 按钮时 我希望主页 刷新 是否有一种方法可以调用主页的回发 同时还可以从详细信息页面维护保存回发 Edit 使用win

随机推荐

  • 如何在C# winforms中调用表单上多个文本框控件的Text_Changed事件

    我的表格大约有 20 个TextBox控制 我想开火Text Changed事件 而无需为每个单独的文本框添加事件 有没有办法循环遍历文本框来触发此事件 我想做的是在文本更改时清除标签控件 对于错误描述 我使用标签控件来显示消息 而不是显示
  • 在没有新初始化的情况下使用类中的数据

    我有一个 TabBar 布局 在 主页 选项卡中我有一个 连接 按钮 按下该按钮时会向 TransferViewController 类发送一个操作以创建 GameKit 会话 然后我有另一个名为 发送 的选项卡 其中有一个按钮 上面写着
  • Laravel Vue.js API:axios 的 PUT 方法不会向控制器发送任何数据

    我正在尝试使用 Laravel 和 Vue js 中的 API 更新模型中的一些数据 但我不能这样做 因为 axios 不会向服务器发送任何数据 我在发送之前检查数据并且它们存在 我使用 FormData append 添加所有字段 我在发
  • 如何在 Java 中加密/解密文件中的文本

    我的代码有问题 当我加密数据时 例如 在本例中 我使用接收者的公钥加密的模拟密钥 然后保存到文本文件中 当我读取该文本文件并尝试解密它时 使用接收者的私钥 我得到了不同的密钥 因此我无法使用它来解密加密的消息 发件人代码 import ja
  • 朱莉娅交换有什么问题!宏?

    我正在尝试写一个简单的swap Julia 中的宏 了解宏系统 到目前为止 这是我的代码 macro swap x y quote local tmp esc y x esc y y tmp end end a 1 b 2 swap a b
  • 如何从不同的JAR中读取多个同名的资源文件?

    如果类路径中有两个 JAR 文件 它们的根目录中都包含名为 config properties 的资源 有没有办法找回both文件类似于getClass getResourceAsStream 该顺序不相关 另一种方法是加载类路径中符合特定
  • 在 JavaScript 中声明多个变量

    在 JavaScript 中 可以像这样声明多个变量 var variable1 Hello World var variable2 Testing var variable3 42 或者像这样 var variable1 Hello Wo
  • 使用长时间运行的后台消费者任务时 Task.Factory.StartNew 中的静默异常?

    这通知未处理的异常 new Thread gt throw new Exception Start 这不会 至少在您等待 检索结果之前 Task Factory StartNew gt throw new Exception 为什么 抛出异
  • 测试 Django 电子邮件后端

    在我的 settings py 中 我输入 EMAIL BACKEND mailer backend DbBackend 所以即使从from django core mail import send mail the send mail函数
  • Coq 平等实现

    我正在编写一种玩具语言 其中 AST 中的节点可以有任意数量的子节点 Num has 0 Arrow有 2 个 等等 您可以致电这些接线员 此外 AST 中可能只有一个节点被 聚焦 我们对数据类型进行索引Z如果它有焦点 或者H如果没有 我需
  • 在 gpshell 中更改 Global Platform 默认密钥后,java 卡管理器身份验证失败

    我想更改用于加载小程序和向卡管理器发送安全消息的全局平台默认密钥 我可以使用以下命令成功更改我的金雅拓默认 GP 卡密钥 mode 211 enable trace establish context card connect reader
  • 这个 GNU 对三元运算符的扩展有多广泛?

    这是根据以下规则对三元运算进行的 GNU 扩展 维基百科 https en wikipedia org wiki 3F C iMyVal iVal iDft 虽然我完全知道这是一个 GNU 扩展 但有时使用这种特殊语法可能会非常方便 那么
  • 通用工厂方法的类型提示

    我很好奇是否可以通过 Python 中的类型参数推断泛型类型 用于类型提示 例如 考虑一个 相当愚蠢的 工厂方法 from typing import TypeVar Type T TypeVar T class Test1 object
  • Amazon SES 电子邮件地址未经验证

    我从亚马逊服务器开始 开始研究SES 我正在使用 asp net C 并制作了基于代码的教程 我已经检查了域 还检查了将在其中运行测试的电子邮件 因此 当我运行代码时 它会生成以下错误消息 事务失败 服务器响应为 消息被拒绝 电子邮件地址未
  • C++ 函数返回引用

    为什么我不能 不应该将对局部变量的引用返回给函数 是不是因为函数执行完毕临时变量就自动销毁了 const string wrap string s1 const string s2 string temp temp s2 s1 s2 ret
  • Typescript 函数返回类型基于可选参数的存在,而不使用函数重载

    打字稿游乐场 https www typescriptlang org play code C4TwDgpgBAKgmgBQKIH0CMUC8UBE9no4BQoksiqATFrvlcSeNAMIDyAcgCICSM3HNHGy69 7Bg
  • 无法设置浮动操作按钮的渐变背景

    我试图将浮动操作按钮的背景设置为渐变 我已经看到了很多解决方案 但没有一个适合我 无论我尝试什么 它都会向我显示一个黑色的操作按钮 我尝试过将背景设置为彩色 但这也不起作用 我正在尝试创建底部导航栏 My code
  • 如何在 Mono for Android (monodroid) 和 MonoTouch 中使用本机 C++ 库

    我有兴趣使用 Mono for Android 和 MonoTouch 来构建可以利用我拥有的大量 C 本机库的移动应用程序 我可以获得一些有关如何调用方法或将代码合并到 iOS 或 Android 上的最终移动应用程序中的具体说明吗 我在
  • 如何在 C# 中打印用户的输入? [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 嘿 我刚刚开始 C 课程 所以我对编程还很陌生 我在打印用户的输入时遇到问题 当我要求用户输入本周跑的英里数时 它会显示输入 然后
  • THREE.js - 旋转移动 3D 球

    我是 THREE js 的新手 对物理学的了解非常少 但我正在尝试构建一个足球游戏引擎 从顶部看 而现在我正在努力处理球的运动 当尝试将球从一侧移动到另一侧时 旋转始终面向一个方向 我不明白如何使其沿其移动方向旋转 我添加了一个简单的代码来