I also wanted to make a camera orbit around a specific point also and MayaCameraSceneNode did not give me the mouse controls that I wanted. I decided to just wrap code(not sure if this is good programming) around a normal CameraSceneNode, since I didn't know enough c++ programming to make my own node and add it to the engine.
Here is my OrbitCamera. However, this uses IrrlichtNETCP, not Irrlict.Net.
Also this code is still a bit messy since this was based on the MayaCameraNode code and there are some stuff that arn't needed that I forgot to remove.
The camera orbits around a point through middle mouse click and zooms by the mouse wheel. Hope this helps:
Code: Select all
public class OrbitCamera
{
#region Members
private bool[] MouseKeys;
private bool zooming, rotating, moving;
private float zoomSpeed;
private float translateSpeed;
private float rotateSpeed;
private float rotateStartX, rotateStartY;
private float currentZoom;
private float rotX, rotY;
private Position2Df MousePos;
private Vector3D Pos;
private SceneManager scene;
private CameraSceneNode camera;
private float totalRotX;
private float totalRotY;
private Vector3D rotAdd;
private float delta;
//Limits on zoom and rotation
private float maxZoom = 400;
private float minZoom = 100;
private float maxYRot = 85;
//-5
private float minYRot = -5;
private AnimatedMeshSceneNode targetNode;
private bool handled;
private float totalTransZ;
private float totalTransY;
private float totalTransX;
private Vector3D center;
#endregion
#region Constructor
public OrbitCamera(SceneManager mgr,
float rs, float zs, float ts)
{
scene = mgr;
camera = scene.AddCameraSceneNode(null);
rotAdd = new Vector3D();
zooming = false;
rotating = false;
moving = false;
zoomSpeed = zs;
rotateSpeed = rs;
currentZoom = 70.0f;
//Pos.set(0.0f, 70.0f, 0.0f);
camera.Target = new Vector3D(0, 70, 0);
rotX = 0;
rotY = 0;
MouseKeys = new bool[3];
targetNode = null;
handled = false;
allKeysUp();
//RecalculateViewArea();
}
#endregion
#region Methods
public void setMoved(bool moved)
{
moving = moved;
}
public bool handleMouseEvents(Event e)
{
if (e.Type == EventType.MouseInputEvent)
{
switch (e.MouseInputEvent)
{
case MouseInputEvent.MMousePressedDown:
{
handled = true;
MouseKeys[0] = true;
}
break;
case MouseInputEvent.MMouseLeftUp:
{
handled = true;
MouseKeys[0] = false;
}
break;
case MouseInputEvent.MouseMoved:
{
if (scene.VideoDriver != null)
{
Dimension2D ssize = (Dimension2D)scene.VideoDriver.ScreenSize;
MousePos.X = (e.MousePosition.X / (float)ssize.Width);
MousePos.Y = (e.MousePosition.Y / (float)ssize.Height);
moving = true;
handled = true;
}
}
break;
case MouseInputEvent.MouseWheel:
{
delta = e.MouseWheelDelta;
MouseKeys[2] = true;
handled = true;
break;
}
}
if (handled)
{
handled = false;
return true;
}
}
return false;
}
// Updates the rotation
public Vector3D update()
{
//Update camera translation to move with
// a scene node
//updateTarget();
// Update Pos camera rotation and zoom
// Pos stores the new position of the camera
animate();
// Sets the camera position
camera.Position = Pos;
//camera.UpdateAbsolutePosition();
return camera.Position;
}
// Helper method
private bool isMouseKeyDown(int key)
{
return MouseKeys[key];
}
// Updates camera
public void animate()
{
//ViewFrustrum va = ViewFrustrum;
float nRotX = rotX;
float nRotY = rotY;
float nZoom = currentZoom;
if (isMouseKeyDown(2))
{
zooming = true;
if (delta > 0)
{
currentZoom = currentZoom + (delta * zoomSpeed);
}
else
{
currentZoom = currentZoom - (delta * -zoomSpeed);
}
if (currentZoom > maxZoom)
currentZoom = maxZoom;
else if (currentZoom < minZoom)
currentZoom = minZoom;
/*if (!zooming)
{
zoomStartX = MousePos.X;
zoomStartY = MousePos.Y;
zooming = true;
nZoom = currentZoom;
}
else
{
float old = nZoom;
nZoom += (zoomStartX - MousePos.X) * zoomSpeed;
float targetMinDistance = 0.1f;
if (nZoom < targetMinDistance)
nZoom = targetMinDistance;
if (nZoom < 0)
nZoom = old;
}*/
}
/*else
{
if (zooming)
{
float old = currentZoom;
currentZoom = currentZoom + (zoomStartX - MousePos.X) * zoomSpeed;
nZoom = currentZoom;
if (nZoom < 0)
nZoom = currentZoom = old;
}
zooming = false;
}*/
// Translation ---------------------------------
//core::vector3df translate(oldTarget);
/* Vector3Df translate = oldTarget;
Vector3Df tvectX = Pos - Target;
tvectX = tvectX.CrossProduct(UpVector);
tvectX.Normalize();
Vector3Df tvectY = (va.GetFarLeftDown() - va.GetFarRightDown());
tvectY = tvectY.CrossProduct(UpVector.Y > 0 ? Pos - Target : Target - Pos);
tvectY.Normalize();
if (isMouseKeyDown(2) && !zooming)
{
if (!translating)
{
translateStartX = MousePos.X;
translateStartY = MousePos.Y;
translating = true;
}
else
{
translate += tvectX * (translateStartX - MousePos.X) * translateSpeed +
tvectY * (translateStartY - MousePos.Y) * translateSpeed;
}
}
else
{
if (translating)
{
translate += tvectX * (translateStartX - MousePos.X) * translateSpeed +
tvectY * (translateStartY - MousePos.Y) * translateSpeed;
oldTarget = translate;
}
translating = false;
}*/
// Rotation ------------------------------------
if (isMouseKeyDown(0) && !zooming)
{
if (!moving)
{
rotateStartX = MousePos.X;
rotateStartY = MousePos.Y;
}
else
moving = false;
if (!rotating)
{
rotateStartX = MousePos.X;
rotateStartY = MousePos.Y;
rotating = true;
nRotX = rotX;
nRotY = rotY;
}
else
{
nRotX += (rotateStartX - MousePos.X) * rotateSpeed;
nRotY += (rotateStartY - MousePos.Y) * rotateSpeed;
}
}
else
{
if (rotating)
{
rotX = rotX + (rotateStartX - MousePos.X) * rotateSpeed;
rotY = rotY + (rotateStartY - MousePos.Y) * rotateSpeed;
nRotX = rotX;
nRotY = rotY;
}
rotating = false;
}
//Console.WriteLine("currentZoom: " + currentZoom);
// Set Pos ------------------------------------
// Sets the rotation of the camera around the target
if (isMouseKeyDown(0) || isMouseKeyDown(2))
{
MouseKeys[2] = false;
zooming = false;
// Rotate up and down first then
// rotate left to right
totalRotX += -nRotX;
totalRotY += nRotY;
if (totalRotY > maxYRot)
totalRotY = maxYRot;
else if (totalRotY < minYRot)
totalRotY = minYRot;
rotAdd.Set(0, 0, -currentZoom);
rotAdd.RotateYZBy(totalRotY, center);
rotAdd.RotateXZBy(-totalRotX, center);
//rotAdd.X = rotAdd.X + Pos.X;
//rotAdd.Y = rotAdd.Y + Pos.Y;
Pos = rotAdd;
updateTranslation();
}
else
{
nRotY = 0;
nRotX = 0;
rotX = 0;
rotY = 0;
}
// Rotation Error ----------------------------
// jox: fixed bug: jitter when rotating to the top and bottom of y
Vector3D upVec = camera.UpVector;
upVec.X = 0;
upVec.Y = 1;
upVec.Z = 0;
camera.UpVector = upVec;
camera.UpVector.RotateXYBy(-nRotY, camera.Target);
camera.UpVector.RotateXZBy(-nRotX + 180f, camera.Target);
}
private void updateTranslation()
{
Pos.X += totalTransX;
Pos.Y += totalTransY;
Pos.Z += totalTransZ;
}
// Initiate all keys
private void allKeysUp()
{
for (int i=0; i<3; ++i)
MouseKeys[i] = false;
}
// function added by jox: fix setPosition()
// Sets the position of the camera
public void setPosition(Vector3D pos)
{
Pos = pos;
updateAnimationState();
//camera.Position = pos;
}
// function added by jox: fix setTarget()
// Sets the target to look at
public void setTarget(Vector3D pos)
{
camera.Target = pos;
center = pos;
updateAnimationState();
}
// Sets which node to follow
public void setTargetNode(AnimatedMeshSceneNode node)
{
targetNode = node;
}
// Updates the camera position to follow a target
// This is based on the most recent target that
// was set by 'setTarget()'
public void updateTarget()
{
if (targetNode != null)
{
float zdiff = Math.Abs(camera.Target.Z) - Math.Abs(targetNode.Position.Z);
float ydiff = Math.Abs(camera.Target.Y) - Math.Abs(targetNode.Position.Y);
float xdiff = Math.Abs(camera.Target.X) - Math.Abs(targetNode.Position.X);
Vector3D camPos = camera.Position;
if (zdiff < 0)
camPos.Z = camPos.Z - zdiff;
else
camPos.Z = camPos.Z + zdiff;
if (ydiff < 0)
camPos.Y = camPos.Y - ydiff;
else
camPos.Y = camPos.Y + ydiff;
if (xdiff < 0)
camPos.X = camPos.X - xdiff;
else
camPos.X = camPos.X + xdiff;
camera.Position = camPos;
Pos = camera.Position;
camera.Target = targetNode.Position;
/*currentZoom = (float)Pos.DistanceFrom(camera.Target);
if (currentZoom > maxZoom)
currentZoom = maxZoom;
else if (currentZoom < minZoom)
currentZoom = minZoom;*/
}
}
public void updateTarget(float zdiff, float ydiff, float xdiff)
{
if (targetNode != null)
{
//float zdiff = Math.Abs(camera.Target.Z) - Math.Abs(targetNode.Position.Z);
//float ydiff = Math.Abs(camera.Target.Y) - Math.Abs(targetNode.Position.Y);
//float xdiff = Math.Abs(camera.Target.X) - Math.Abs(targetNode.Position.X);
Vector3D camPos = camera.Position;
//Z
/*if (zdiff < 0)
{
camPos.Z = camPos.Z - zdiff;
totalTransZ -= zdiff;
}
else
{
camPos.Z = camPos.Z + zdiff;
totalTransZ += zdiff;
}
//Y
if (ydiff < 0)
{
camPos.Y = camPos.Y - ydiff;
totalTransY -= ydiff;
}
else
{
camPos.Y = camPos.Y + ydiff;
totalTransY += ydiff;
}
//X
if (xdiff < 0)
{
camPos.X = camPos.X - xdiff;
totalTransX -= xdiff;
}
else
{
camPos.X = camPos.X + xdiff;
totalTransX += xdiff;
}*/
camPos.Z += + zdiff;
totalTransZ += zdiff;
camPos.Y += ydiff;
totalTransY += ydiff;
camPos.X += xdiff;
totalTransX += xdiff;
camera.Position = camPos;
Pos = camera.Position;
camera.Target = targetNode.Position;
/*currentZoom = (float)Pos.DistanceFrom(camera.Target);
if (currentZoom > maxZoom)
currentZoom = maxZoom;
else if (currentZoom < minZoom)
currentZoom = minZoom;*/
}
}
// function added by jox
// Determines the angle from the position to the target
// and sets them to 'totalRot' variables
private void updateAnimationState()
{
float zLen = Math.Abs(Pos.Z) - Math.Abs(camera.Target.Z);
float yLen = Math.Abs(Pos.Y) - Math.Abs(camera.Target.Y);
float xLen = Math.Abs(Pos.X) - Math.Abs(camera.Target.X);
// X rotation
rotY = (float)((Math.Atan(yLen / zLen) * 360) / (2 * Math.PI));
rotX = (float)((Math.Atan(xLen / zLen) * 360) / (2 * Math.PI));
totalRotY = rotY;
totalRotX = rotX;
// Zoom
currentZoom = (float)Pos.DistanceFrom(camera.Target);
rotAdd.Set(0, 0, -currentZoom);
rotAdd.RotateYZBy(totalRotY, center);
rotAdd.RotateXZBy(-totalRotX, center);
Pos = rotAdd;
camera.Position = rotAdd;
}
public CameraSceneNode getCamera()
{
return camera;
}
#endregion
}
The tranlation from IrrlichtNETCP to Irrlicht.Net shouldn't be too hard. Anyway, if u have any questions about my code, feel free to ask.