我正试图在“THREE.JS”中制作星际争霸游戏。
我在'Y轴上旋转物体面向新方向时遇到问题,然后改变位置。
并且通过旋转我的意思是动画/所以请停止使用糟糕的lookAt()函数
如果有人告诉我如何加工一些魔法物品_MatrixRotationY(角度),我会很感激,我希望从Vector3计算出这个角度
这是我到目前为止所做的:
http://f.cl.ly/items/3J3R0X2q2R1h1J203C1V/drone.jpg
我从Vector3中获取新位置,如下所示。
// scene
var container;
var camera, scene, renderer;
// intersect with objects in this array
var intersectObjects = [];
// materials
var material = new THREE.MeshNormalMaterial();
var cristal_texture = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("models/JSON/textures/cristal.jpg") });
var destination;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 15000 );
camera.rotation.x = - 90 * ( Math.PI / 180 );
camera.position.set( 800 , 1000 , 0 );
scene = new THREE.Scene();
plane = new THREE.Mesh( new THREE.PlaneGeometry( 3000, 3000 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) );
plane.rotation.x = - 90 * ( Math.PI / 180 );
plane.position.set(0,0,0);
plane.overdraw = true;
scene.add( plane );
intersectObjects.push(plane);
loader = new THREE.JSONLoader();
loader.load( "models/JSON/driller.js", function( geometry ) {
driller = new THREE.Mesh( geometry, material );
driller.position.set(0,50,0);
matr = new THREE.Matrix4();
driller.matrixAutoUpdate = false;
driller.geometry.applyMatrix( matr.makeRotationY( 0 ) );
driller.scale.set(0.5,0.5,0.5);
scene.add( driller );
});
loade = new THREE.JSONLoader();
loade.load( "models/JSON/cristal.js", function( geometry ) {
cristal = new THREE.Mesh( geometry, cristal_texture );
cristal.position.set(-1450,0,1450);
matre = new THREE.Matrix4();
cristal.matrixAutoUpdate = false;
cristal.geometry.applyMatrix(matre.makeRotationY( 0 ));
cristal.scale.set(0.5,0.5,0.5);
scene.add( cristal );
intersectObjects.push(plane);
});
// lightning properties
var ambientLight = new THREE.AmbientLight(0xFFFFFF);
scene.add(ambientLight);
scene.matrixAutoUpdate = false;
// render engine
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
container.appendChild( renderer.domElement );
// event listeners
document.addEventListener('mouseup', onMouseUp, false);
}
function onMouseUp(event) {
event.preventDefault();
x_pos = (event.clientX / window.innerWidth) * 2 - 1;
y_pos = -(event.clientY / window.innerHeight) * 2 + 1;
z_pos = 0.5;
var vector = new THREE.Vector3( x_pos , y_pos , z_pos );
var projector = new THREE.Projector();
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(intersectObjects);
if (intersects.length > 0) {
xp = intersects[0].point.x.toFixed(2);
yp = intersects[0].point.y.toFixed(2);
zp = intersects[0].point.z.toFixed(2);
destination = new THREE.Vector3( xp , 50 , zp );
var se23k = Math.random() * 4 * 4 ;
new TWEEN.Tween( driller.rotation ).to( { y: se23k }, 1000 ).easing( TWEEN.Easing.Linear.None).start();
}
else {
console.log('outside boundaries');
}
};
function update(){
camera.lookAt( plane.position );
renderer.render( scene, camera );
}
function animate() {
requestAnimationFrame( animate );
update();
render();
}
function render() {
driller.updateMatrix();
cristal.updateMatrix();
TWEEN.update();
renderer.render( scene, camera );
}
答案 0 :(得分:1)
这是一些代码,它可以在指向Z轴并平滑地指向X轴之间旋转船只。
上有一个演示视频我已经删除了渲染器设置的大部分内容,专注于四元数拼写。
以下代码在咖啡脚本中,并使用S3age中的一些自定义类;我尽可能地评论他们。如果这有问题,请在评论中提及它,我会将其重写为VanillaJS。
# RequireJS preamble, not important.
define ["util/stage", "game/clock"],
(Stage, Clock)->
###
# Ship is a constructor.
# It uses no ctor arguments, but does pass them to Object3D.
###
Ship = (Object3DArgs)->
# Ship directly extends Object3D
THREE.Object3D.apply @, arguments
@build()
# The critical piece - use the model's quaternion, not its rotation
@useQuaternion = yes
@
# Finish subclassing, by creating a new prototype chain.
Ship:: = Object.create THREE.Object3D::
###
# Create some geometry, materials, etc. Not important, could be from
# Collada/JSON/etcLoader
# Important part is noticing the rotation and position are set relative to
# the Ship object itself; moving or rotating @ will move/rotate the
# geometry inside it implicitly.
###
Ship::build = ->
geom = new THREE.CylinderGeometry 0, 3, 1.5, 20, 1
mat = new THREE.MeshLambertMaterial
@hull = new THREE.Mesh geom, mat
@hull.scale.set(0.3, 1, 0.1)
@hull.rotation.set(Math.PI / 2, 0, 0)
@hull.position.set(0, 0, 0.33)
@add @hull
@
###
# An easing function, to go from ticks on a frame counter to some
# percentage between zero and one, over the course of some time.
###
ease = do ->
seconds = 4
d = time = (seconds * 60)
b = 0.0
c = 1.0
#easeInOutQuad from http://www.robertpenner.com/easing/
(t) ->
# Constrain `t` between `0` and the animation's duration
t %= d
if ((t /= d/2 ) < 1)
c/2*t*t + b
else
-c/2 * ((--t)*(t-2) - 1) + b
# Y is the axis to rotate through. In this instance, it is the Y axis.
# In general, it should be the "Up" vertex of the model.
# You will calculate this when the user clicks.
y = new THREE.Vector3(0, 1, 0)
# r0 is the initial direction when the animation starts;
# that is, the "up" vector at theta=0
r0 = new THREE.Quaternion()
r0.setFromAxisAngle(y, 0)
# r1 is the desired direction. Calculate theta from the dot product of the
# ship's normal with the vector pointing from the ship to the target (eg
# target.position - ship.position)
r1 = new THREE.Quaternion()
r1.setFromAxisAngle(y, Math.PI / 2)
###
# The update function will get called every physics update.
# Clock has time, delta, and frame.
# Frame is number of ticks, time is total time elapsed,
# delta is time since last update.
###
Ship::update = (clock)->
# Get the prct between zero and one of how far through
# the animation the clock is
prct = ease clock.frame
# Use the static slerp, storing the result directly
# in the ship's quaternion.
THREE.Quaternion.slerp r0, r1, @quaternion, prct
# A convention in my loader, not important.
# Creates a S3age, gets the scene, etc.
play: (selector)->
stage = new Stage selector
stage.scene = new THREE.Scene()
stage.scene.add ship = new Ship()
# Some lights, controls, an axis.
stage.scene.add new THREE.AmbientLight 0x404040
stage.scene.add light = new THREE.PointLight 0xF0F0F0, 1, 100
light.position.set(20, 30, 50)
stage.controls = new THREE.Trackball stage.camera, stage.container
stage.camera.position.set(2, 5, -5)
stage.scene.add new THREE.AxisHelper(2)
# Call the update function every time the clock goes tick-tock
(new Clock()).addEventListener 'tick', (event)->
clock = event.clock
ship.update clock
stage.start()
答案 1 :(得分:0)
我认为这个问题听起来很熟悉 - 也许three.js parent child target tracking的问题和答案会有所帮助吗?
答案 2 :(得分:0)
实际上,我找到了更快的解决方案;)
xp = intersects[0].point.x.toFixed(2);
yp = intersects[0].point.y.toFixed(2);
zp = intersects[0].point.z.toFixed(2);
destination = new THREE.Vector3( xp , yp , zp );
radians = Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp));
radians += 90 * (Math.PI / 180);
var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start();