I'm trying to make a sort of a camera in HTML5 Canvas using 2D rendering context. As you see in the picture I've drawn below, here's what I'm trying to achieve:
- Say that the black one is the eye of the camera, I want it to be able to move around (edit:) WITH the canvas (as the green arrows in the picture) and able to look like AS IF it is travel around the objects, like the red one (I believe this is parallax stuff).
- Whenever I travel around the objects, when I make a rotation of the camera, I want it to rotate by the center of the camera (see the blue rotation).
I have done this up to where the red box can rotate on the center of the camera whenever I move the camera around, [EDIT] and here's a simplified a example:
*Within the requestAnimationFrame (game loop)*
...
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
ctx.save();
// draw camera eye.
ctx.lineWidth = 3;
ctx.fillStyle = "black";
ctx.beginPath();
ctx.moveTo(ctx.canvas.width / 2 - 50, ctx.canvas.height / 2);
ctx.lineTo(ctx.canvas.width / 2 + 50, ctx.canvas.height / 2);
ctx.moveTo(ctx.canvas.width / 2, ctx.canvas.height / 2 - 50);
ctx.lineTo(ctx.canvas.width / 2, ctx.canvas.height / 2 + 50);
ctx.stroke();
// Rotate by camera's center.
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
ctx.rotate(worldRotate);
ctx.translate(worldPos.x, worldPos.y);
//
// ADD WORLD ENTITIES BELOW to be viewed by the camera.
//
ctx.fillStyle = "red";
ctx.fillRect(-5, -5, 10, 10);
ctx.restore();
...
(EDIT: changed transform object into ctx to further simplify the code.)
variable worldRotate and worldPos are changeable via input for a test.
EDIT: Here's the real live example with the problem as drawn to make it even clearer on what I'm trying to achieve.
Try moving it to right or left and see what happens. And try to rotate right the camera so that the red box aligned with x-axis, then move the camera and see how it perfectly works like a camera I wanted.
(Note: Remended browser to test it is IE10, latest chrome, latest firefox, latest opera, and desktop safari 5+).
The problem is, when I move the camera (by changing the worldPos, makes the red box move away from the camera), make a rotation (using worldRotate), and then move the camera again, the red object always move towards the purple arrows instead of the orange arrows. I want the red box to move toward the orange arrows regardless of any rotation by the camera's center.
Edit: As far as I can tell, it is obvious that the rotation causes the translation to mess up because the rotation changes the coordinate system for the red box, but I still don't know how to deal with it, at least to let the translation goes like the orange arrows regardless of its current rotated coordinate system for the red box.
Any solution on this? Thank you.
I'm trying to make a sort of a camera in HTML5 Canvas using 2D rendering context. As you see in the picture I've drawn below, here's what I'm trying to achieve:
- Say that the black one is the eye of the camera, I want it to be able to move around (edit:) WITH the canvas (as the green arrows in the picture) and able to look like AS IF it is travel around the objects, like the red one (I believe this is parallax stuff).
- Whenever I travel around the objects, when I make a rotation of the camera, I want it to rotate by the center of the camera (see the blue rotation).
I have done this up to where the red box can rotate on the center of the camera whenever I move the camera around, [EDIT] and here's a simplified a example:
*Within the requestAnimationFrame (game loop)*
...
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
ctx.save();
// draw camera eye.
ctx.lineWidth = 3;
ctx.fillStyle = "black";
ctx.beginPath();
ctx.moveTo(ctx.canvas.width / 2 - 50, ctx.canvas.height / 2);
ctx.lineTo(ctx.canvas.width / 2 + 50, ctx.canvas.height / 2);
ctx.moveTo(ctx.canvas.width / 2, ctx.canvas.height / 2 - 50);
ctx.lineTo(ctx.canvas.width / 2, ctx.canvas.height / 2 + 50);
ctx.stroke();
// Rotate by camera's center.
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
ctx.rotate(worldRotate);
ctx.translate(worldPos.x, worldPos.y);
//
// ADD WORLD ENTITIES BELOW to be viewed by the camera.
//
ctx.fillStyle = "red";
ctx.fillRect(-5, -5, 10, 10);
ctx.restore();
...
(EDIT: changed transform object into ctx to further simplify the code.)
variable worldRotate and worldPos are changeable via input for a test.
EDIT: Here's the real live example with the problem as drawn to make it even clearer on what I'm trying to achieve.
Try moving it to right or left and see what happens. And try to rotate right the camera so that the red box aligned with x-axis, then move the camera and see how it perfectly works like a camera I wanted.
(Note: Remended browser to test it is IE10, latest chrome, latest firefox, latest opera, and desktop safari 5+).
The problem is, when I move the camera (by changing the worldPos, makes the red box move away from the camera), make a rotation (using worldRotate), and then move the camera again, the red object always move towards the purple arrows instead of the orange arrows. I want the red box to move toward the orange arrows regardless of any rotation by the camera's center.
Edit: As far as I can tell, it is obvious that the rotation causes the translation to mess up because the rotation changes the coordinate system for the red box, but I still don't know how to deal with it, at least to let the translation goes like the orange arrows regardless of its current rotated coordinate system for the red box.
Any solution on this? Thank you.
Share Improve this question edited Mar 18, 2013 at 16:33 asked Mar 16, 2013 at 15:33 user905864user905864 2- Some code would be enlightening, but absent that sounds like you need to context.save() before doing transforms (move,rotate,etc) and then context.restore() after the transforms are plete. – markE Commented Mar 16, 2013 at 16:51
- Pardon me markE, I've updated the code per your request to consider. Yes it's related to those stuff. – user905864 Commented Mar 17, 2013 at 2:58
3 Answers
Reset to default 4[Edited given further clarification by OP]
OK, I have better understanding of your question now. You want to give your camera lens perspective on the objects in your world.
If your camera looks only in the X directions in relation to your world objects, you can simply use parallax. You do this by applying 2 layers to your canvas that are scrolling at different speeds in X directions. This is panorama parallax. So for every frame, draw 2 layers like this pseudo-code:
// Move the back layer
backLayerX += 3;
ctx.save();
ctx.translate(backLayerX,backLayerY);
// draw the objects in your back layer now
ctx.translate(-backLayerX,-backLayerY);
ctx.restore();
// Move the front layer faster than the back layer
frontLayerX += 10;
ctx.save();
ctx.translate(frontLayerX,frontLayerY);
// draw the objects in your front layer now
ctx.translate(frontLayerX,frontLayerY);
ctx.restore();
And if you move the camera itself in an X direction, you must also alter the speed at which the front and back layers are translated.
If your camera also looks in the Z directions (camera closer) in relation to your world objects, the process is much more plicated.
For example, if you move closer to a statue, the statue appears to get bigger—ctx.scale(2,2). The background scenery also gets bigger, but not as fast—ctx.scale(1.25,1.25).
Then if you also take a step to the left, then the left side of the statue is slightly larger than the right side of the statue—the context skews. The background skews also, but very, very slightly.
Then if you also stand on a chair (change the Y direction) you get a different kind of skewing.
Your camera can never move even with the statue because your statue is 2D—just a cardboard cutout of the statue. From the camera’s perspective, the statue will actually disappear!
I hope I’ve given you a start to your project, but a full answer is waaaaaaaaaay beyond a Stackoverflow answer—it’s a college course on puter graphics.
I do have an online tutorial remendation for you. There is an excellent lecture on Perspective by Wolfgang Hurst. This is lecture#7 in his 13 part online college course. You can view his lecture two ways. View broadly to get the concepts involved in giving your camera perspective. Or view deeply and get the mathematical algorithms: http://www.youtube./watch?v=q_HA-x5AujI&list=PLDFA8FCF0017504DE
Good Luck and Learning… :)
[What follows addresses the OP's original question]
Here’s a quick tutorial on how to successfully rotate anything in canvas
The whole world rotates around an X/Y “registration point”.
You set the registration point by doing ctx.translate(X,Y) just before the ctx.rotate(angle).
After you draw your “world” objects in this rotated space, you must re-set the registration point by doing translate(-X,-Y).
So world rotation goes like this:
- Context.save();
- Context.translate( registrationX, registrationY );
- Context.rotate(angle);
- Draw stuff.
- Context.translate( -registrationX, -registrationY );
- Context.restore();
Here’s an excellent way of understanding rotation and registration points:
- Get a piece of paper and draw a single letter on the page.
- Get a pencil and hold it down at any point on the page.
- --The pencil point is the registration point.
- --The pencil point is the translate(X,Y).
- Rotate the paper around the pencil point.
- --The rotation of the paper is rotate(angle)
- --Notice how the letter rotates as the paper moves.
- --Your red box will rotate just like the letter (around your camera registration point)
- Reset the paper to straight-up rotation.
- --This “un-rotation” is like the translate(-X, -Y)
- Move the pencil to another point on the paper
- --Again, this is like translate(newX,newY)
- Rotate the paper again and notice how the letter rotates in a different pattern.
Here is code and a Fiddle: http://jsfiddle/m1erickson/nj29x/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery./jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:30px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var camX=100;
var camY=100;
var camRadius=40;
var camDegrees=0;
draw();
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawWorldRect(75,75,30,20,0,"blue","A");
drawWorldRect(100,100,30,20,15,"red","B");
drawCamera();
}
function drawWorldRect(x,y,width,height,angleDegrees,fillstyle,letter){
var cx=x+width/2;
var cy=y+height/2;
ctx.save();
ctx.translate(cx, cy);
ctx.rotate( (Math.PI / 180) * angleDegrees);
ctx.fillStyle = fillstyle;
ctx.fillRect(-width/2, -height/2, width, height);
ctx.fillStyle="white";
ctx.font = '18px Verdana';
ctx.fillText(letter, -6, 7);
ctx.restore();
}
function drawCamera(){
ctx.save();
ctx.lineWidth = 3;
ctx.beginPath();
// draw camera cross-hairs
ctx.strokeStyle = "#dddddd";
ctx.moveTo(camX,camY-camRadius);
ctx.lineTo(camX,camY+camRadius);
ctx.moveTo(camX-camRadius,camY);
ctx.lineTo(camX+camRadius,camY);
ctx.arc(camX, camY, camRadius, 0 , 2 * Math.PI, false);
ctx.stroke();
// draw camera site
ctx.fillStyle = "#222222";
ctx.beginPath();
ctx.arc(camX, camY-camRadius, 3, 0 , 2 * Math.PI, false);
ctx.fill()
ctx.restore();
}
function rotate(){
ctx.save();
ctx.translate(camX,camY);
ctx.rotate(Math.PI/180*camDegrees);
ctx.translate(-camX,-camY);
draw();
ctx.restore();
}
$("#rotateCW").click(function(){ camDegrees+=30; rotate(); });
$("#rotateCCW").click(function(){ camDegrees-=30; rotate(); });
$("#camUp").click(function(){ camY-=20; draw(); });
$("#camDown").click(function(){ camY+=20; draw(); });
$("#camLeft").click(function(){ camX-=20; draw(); });
$("#camRight").click(function(){ camX+=20; draw(); });
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=300></canvas><br/>
<button id="camLeft">Camera Left</button>
<button id="camRight">Camera Right</button>
<button id="camUp">Camera Up.</button>
<button id="camDown">Camera Down</button><br/>
<button id="rotateCW">Rotate Clockwise</button>
<button id="rotateCCW">Rotate CounterClockwise</button>
</body>
</html>
The x and y points to move the center of the world to are calculated using the tangent of the angle of rotation. I have an example exhibiting the concept, it is not a final solution, but a starting point you can work from. Think of it as as a "rough cut" (don't have time to polish it pletely). For instance as you can see, the pivot point of rotation is not moved to the point directly beneath the camera lenses, so the rotation doesn't occur directly beneath the camera.
Here is a diagram explaining how the geometry / trigonometry works:
Here is the code snippets and a link to the fully functional jsfiddle. The keyboard mands are the same as in your example.
http://jsfiddle/ricksuggs/X8rYF/
//s (down)
if (keycode === 83) {
event.preventDefault();
canvas.getContext('2d').clearRect(-200,-200,400,400);
canvas.getContext('2d').translate(2*Math.tan(rotationSum), -2);
drawGrid();
drawCamera();
}
// <-- (rotate left)
if (keycode === 37) {
event.preventDefault();
canvas.getContext('2d').clearRect(-200,-200,400,400);
rotationSum += rotation;
console.log('rotationSum: ' + rotationSum);
canvas.getContext('2d').rotate(-rotation);
drawGrid();
drawCamera();
}
The order should be like this:
Ctx.save()
Ctx.translate(x, y) //to the center (Or top left of object to rotate)
Ctx.rotates(radian)
Ctx.translate(-x, -y) //important to move the context back!
Ctx.draw(...)
Ctx.restore()
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742378931a4432751.html
评论列表(0条)