为了更好的理解camera的position、lookAt与up属性,文章最开始我们先来阐述three.js的坐标系转换的概念。
文章的最开始首先讨论在哪里进行点击事件的监听的问题,当鼠标触发点击事件时,event会输出点击位置相对于各个参考系所产生的坐标,在此我们只讨论常用的offsetX、offsetY以及clientX、clientY。
offsetX:设置或获取鼠标点击位置相对于触发事件对象(触发事件DOM的内部不包含border)的水平(X)距离
offsetY:设置或获取鼠标点击位置相对于触发事件对象(触发事件DOM的内部不包含border)的垂直(Y)距离
clientX:设置或获取鼠标相对于浏览器可视区域的水平坐标
clientY:设置或获取鼠标相对于浏览器可视区域的垂直坐标
如图(1)示,window中(clientX,clientY)都是相对于左上角坐标原点的距离,而(offsetX,offsetY)中触发事件的对象这个概念就很重要,是相对于当前DOM元素不包含border及其外部的content部分左上角原点坐标,如果在展示界面存在header,(clientX,clientY)还需要转换才能作为画布的坐标,所以推介选取(offsetX,offsetY)作为监听事件获得的坐标。

图(1)不同坐标数据展示
如果展示模型的画布如果是整个可视页面,监听window得到的坐标(clientX,clientY)与(offsetX,offsetY)都是一致的。但往往我们只会选择一个区域进行三维模型的展示, 这时若监听对象为window,就会在画布外触发点击事件,容易产生不必要的问题。所以此时最好把监听对象设置为存放画布的DOM元素,不仅在画布外不会触发不必要的事件,并且可以直观的获得该点相对于画布的坐标。
element.addEventListener('click',()=>{})
window.addEventListener('click',()=>{})
这里我们先抛出屏幕坐标、标准化设备坐标与世界坐标的概念。
屏幕坐标:以左上角为原点,横向为x轴,纵向向下为y轴;屏幕坐标系在three.js中为canvas画布的坐标系,如图(2)示

图(2)屏幕坐标系
标准化设备坐标(NormalizedDeviceCoordinates,NDC) :标准化设备坐标是一个横纵坐标值在-1到1的一小段空间,坐标原点位于区域正中心。如图(3)示

图(3)标准化设备坐标系
世界坐标:场景坐标原点坐标系,世界坐标是物体相对场景坐标原点的位置,如图(4)示

图(4)世界坐标系
首先我们了解如何从屏幕坐标系转化为标准化设备坐标系,最后转化为世界坐标系的过程 。
step 1:
当鼠标在canvas画布上点击时,获得屏幕坐标系(Sx,Sy),将其转化为( Nx,Ny),可得
转化为代码就是
const x = (x / Width) * 2 - 1,
const y = - (y /Height) * 2 + 1,
step 2:
将得到的设备坐标转化为三维向量;
const nVector = new THREE.Vector3((x / Width) * 2 - 1,- (y /Height) * 2 + 1,0.5)
step 3:
three.js有封装好的方法.unporject( ),将设备坐标转为世界坐标系;
const worldVector = nVector.unprojet( camera )
同上可得
step1:
将世界坐标系转化为标准坐标系
const nVector = worldVector .projet( camera )
step2:
将标准坐标系转化为屏幕坐标系,公式为
.position:Vectors
表示对象局部位置的Vector3。默认值为(0, 0, 0)
官方文档的解释很容易理解,就是相机相对于世界坐标系原点的位置,换句话说相机距离场景中心的距离。距离越近看到的物体越少越大,距离越远看到的物体越多越小。设置一个合适的位置对于观察场景内模型具有很重要的意义。

图(5)相机看向物体
object3D.lookAt ( vector:Vector3) :undefined
object3D.lookAt( x : Float, y : Float, z : Float ) :undefinedvector - 一个表示世界空间中位置的向量。
也可以使用世界空间坐标的位置分量。
旋转物体使其在世界空间中面朝一个点。这一方法不支持其父级被旋转过或者被位移过的物体。
也就是说,这个object的永远朝向 .lookAt( ) 中向量的位置,如果在创建object时使用这个属性,就会产生构建的物体总是会朝向向量的方向,图(6)示为raycaster射线射中返回的数据,借由这些数据和。lookAt()方法,我们可以完成很多有趣的功能,例如在物体表面形成数据点,或者构建垂直于当前面的线等等。

图(6)相机看向物体
而相机的这个属性可以理解为”看向“哪里,只有保证视角中出现这个对象,我们才能通过画布看到。在渲染场景时,通常都是将相机看向场景的原点,以此来保证可视界面的完整,我们也可以把相机放置在场景中移动的物体上,设置看向某个方向,借此完成动态巡检等功能。
.up:Vector3
这个属性由lookAt方法所使用,例如,来决定结果的朝向。 默认值是Object3D.DefaultUp,
即( 0, 1, 0 )
通过前面阐述的世界坐标系概念可知,这个”结果的朝向“指的是场景的坐标系的朝向,默认的朝向为Y轴向上,X轴向右,Z轴向外,那么我们设置这个值会得到什么?
a.设置Y轴向上
换句话说,就是哪个方向是向上的,设置.up为(0,1,0),就可以得到图(7)的样式,Y轴向上,X轴向右,Z轴向外。
camera.position.set(1,30,60)
camera.lookAt(0,0,0)
camera.up = new THREE.Vector3(0,1,0)

图(7)Y轴向上
b.设置Y轴向上
那么,设置.up为(1,0,0),就可以得到图(8)的样式,x轴向上,X轴向坐,Z轴向外。
camera.position.set(1,30,60)
camera.lookAt(0,0,0)
camera.up = new THREE.Vector3(1,0,0)

图(8)X轴向上
c.设置Z轴向上
设置.up为(0,0,1)时,就可以得到图(9),由图可知Z轴向外,那么为什么Z轴没有向上?通过图(10)可以知道相机的位置在Z轴正半轴,看向Z轴的负半轴,改变.up()的值,相机的位置也是在跟随着一起移动,所以得到如图所示的结果。
camera.position.set(1,30,60)
camera.lookAt(0,0,0)
camera.up = new THREE.Vector3(1,0,0)

图(9)Z轴向上

我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
让我们计算MRI范围内的类别:defcount_classesObjectSpace.count_objects[:T_CLASS]endk=count_classes用类方法定义类:classAdefself.foonilendend然后运行:putscount_classes-k#=>3请解释一下,为什么是三个? 最佳答案 查看MRI代码,每次你创建一个Class时,在Ruby中它是Class类型的对象,ruby会自动为这个新类创建“元类”类,这是另一个单例类型的Class对象。C函数调用(class.c)是:rb_define
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐
我的ruby脚本从命令行参数获取某些输入。它检查是否缺少任何命令行参数,然后提示用户输入。但是我无法使用gets从用户那里获得输入。示例代码:test.rbname=""ARGV.eachdo|a|ifa.include?('-n')name=aputs"Argument:#{a}"endendifname==""puts"entername:"name=getsputsnameend运行脚本:rubytest.rbraghav-k错误结果:test.rb:6:in`gets':Nosuchfileordirectory-raghav-k(Errno::ENOENT)fromtes
我开始了一个新的Rails3.2.5项目,Assets管道不再工作了。CSS和Javascript文件不再编译。这是尝试生成Assets时日志的输出:StartedGET"/assets/application.css?body=1"for127.0.0.1at2012-06-1623:59:11-0700Servedasset/application.css-200OK(0ms)[2012-06-1623:59:11]ERRORNoMethodError:undefinedmethod`each'fornil:NilClass/Users/greg/.rbenv/versions/1
rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:
我有一个包含多个组件的存储库,其中大部分是用JavaScript(Node.js)编写的,一个是用Ruby(RubyonRails)编写的。我想要一个.travis.yml文件来触发一个运行每个组件的所有测试的构建。根据thisTravisCIGoogleGroupthread,目前还没有官方支持。我的目录结构是这样的:.├──构建服务器├──核心├──扩展├──网络应用├──流浪文件├──package.json├──.travis.yml└──生成文件我希望能够运行特定版本的Ruby(2.2.2)和Node.js(0.12.2)。我已经有了一个make目标,所以maketest在每
在我的schedule.rb文件中,我有以下几行:set:output,'/log/cron_log.log'every5.minutesdocommand'echo"hello"'end我按照这个问题Rails,usingwhenevergemindevelopment中的建议运行了whenever-w,并且我假设cronfile已编写并正在运行。(我也尝试重新启动Rails服务器。)当我运行$crontab-l时,我看到以下内容:0,5,10,15,20,25,30,35,40,45,50,55****/bin/bash-l-c'echo"hello">>/log/cron_log
我已经安装了DeviseonRails4.2.0,一切似乎都在工作,我使用了以下指南:http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/我的设计模块是:devise:database_authenticatable,:registerable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:omniauthable唯一的问题是,如果我尝试通过转到注册页面创建一个新帐户,然后在输入我的电子邮