Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Camera! #28

Closed
wants to merge 3 commits into from

2 participants

@lharding

So here's that camera system I promised, more or less. How it works and where it's going in my mind should be mostly self-explanatory.

@funkaster
Owner

great! thanks a lot. I'll review it later today.

One question: would it be possible for you to add an example on how to use this? maybe you could just duplicate test_single_block.html and create a simple example... That would be awesome :)

@lharding

That's probably a good idea. I'll send you a pull request for it when I've made one.

@funkaster
Owner

thanks!

@lharding

Alrighty, here's a super-simple camera example. Enjoy!

@funkaster
Owner

cool! thanks ^_^
I'll give it a look this weekend

@funkaster
Owner

Ok, tested it and looks good (some parts can be improved, but it looks ok). This change breaks all other tests though, so I'll keep this open for a while.

I'll add my comments to the diff.
Again, thanks a lot!

@funkaster funkaster commented on the diff
chesterGL/core.js
((14 lines not shown))
* main draw function, will call the root block
* @ignore
*/
chesterGL.drawScene = function () {
+ //Setup camera transformation
+ var par = chesterGL.camera;
+ var parents = [];
@funkaster Owner

I agree with you that this is somewhat inefficient, also creating new elements on every frame is not so good for GC.
One way we could avoid this (calculation of the camera transform) is with lazy evaluation... not sure how to achieve this yet, but seems like a good idea

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@funkaster funkaster commented on the diff
chesterGL/core.js
((25 lines not shown))
+ parents.push(par);
+ par = par.parent;
+ }
+
+ // We go backwards so that we start at the root and finish with the camera.
+ for(var i=parents.length-1; i >= 0; i--) {
+ parents[i].updateTransform();
+ }
+
+ // Invert and multiply onto the view transform.
+ // this looks a little wonky when using a camera that is a child of a normal block
+ // because we end up using the previous frame's transform for that block.
+ // TODO: refactor Block.visit into separate update and transform steps so we can
+ // use the current frame's transform here. This would also let us have multiple
+ // cameras each with their own viewport in the main port, picture in picture style.
+ chesterGL.pMatrix = goog.vec.Mat4.createFloat32();
@funkaster Owner

Same here. If you're doing this every frame, ideally you want to have a temp vector/matrix around just to reuse it and avoid creation every frame, that's more friendly with GC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@funkaster
Owner

I'll close this for now, since I'm also rewriting the rendering code (separating the scene graph from the rendering list)

@funkaster funkaster closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 20, 2012
  1. @lharding

    Super basic camera system.

    lharding authored
  2. @lharding

    Documented Camera, sort of.

    lharding authored
Commits on Apr 28, 2012
  1. @lharding

    Camera Example.

    lharding authored
This page is out of date. Refresh to see the latest.
Showing with 171 additions and 12 deletions.
  1. +17 −12 chesterGL/block.js
  2. +46 −0 chesterGL/core.js
  3. +108 −0 html/test_camera.html
View
29 chesterGL/block.js
@@ -106,7 +106,8 @@ chesterGL.Block.TYPE = {
'SCENE': 2,
'TMXBLOCK': 3,
'PARTICLE': 4,
- 'PRIMITIVE': 5
+ 'PRIMITIVE': 5,
+ 'CAMERA': 6
};
/**
@@ -484,6 +485,18 @@ chesterGL.Block.prototype.removeChild = function (block) {
}
};
+chesterGL.Block.prototype.updateTransform = function () {
+ this.mvMatrix = /** @type {Float32Array} */(goog.vec.Mat4.makeIdentity(this.mvMatrix));
+ goog.vec.Mat4.translate(this.mvMatrix, this.position[0], this.position[1], this.position[2]);
+ goog.vec.Mat4.rotate(this.mvMatrix, this.rotation * -1, 0, 0, 1);
+ goog.vec.Mat4.scale(this.mvMatrix, this.scale, this.scale, 1);
+ // concat with parent's transform
+ var ptransform = (this.parent ? this.parent.mvMatrix : null);
+ if (ptransform) {
+ goog.vec.Mat4.multMat(ptransform, this.mvMatrix, this.mvMatrix);
+ }
+}
+
/**
* actually performs the transformation
* @ignore
@@ -492,19 +505,11 @@ chesterGL.Block.prototype.transform = function () {
var gl = chesterGL.gl;
var transformDirty = (this.isTransformDirty || (this.parent && this.parent.isTransformDirty));
if (transformDirty) {
- this.mvMatrix = /** @type {Float32Array} */(goog.vec.Mat4.makeIdentity(this.mvMatrix));
- goog.vec.Mat4.translate(this.mvMatrix, this.position[0], this.position[1], this.position[2]);
- goog.vec.Mat4.rotate(this.mvMatrix, this.rotation * -1, 0, 0, 1);
- goog.vec.Mat4.scale(this.mvMatrix, this.scale, this.scale, 1);
- // concat with parent's transform
- var ptransform = (this.parent ? this.parent.mvMatrix : null);
- if (ptransform) {
- goog.vec.Mat4.multMat(ptransform, this.mvMatrix, this.mvMatrix);
- }
+ this.updateTransform();
}
- // bail out if we're a block group or a primitive block
- if (this.type == chesterGL.Block.TYPE['BLOCKGROUP'] || this.type == chesterGL.Block.TYPE['PRIMITIVE']) {
+ // bail out if we're a block group or a primitive block, or a camera
+ if (this.type == chesterGL.Block.TYPE['BLOCKGROUP'] || this.type == chesterGL.Block.TYPE['PRIMITIVE'] || this.type == chesterGL.Block.TYPE['CAMERA']) {
return;
}
View
46 chesterGL/core.js
@@ -810,6 +810,8 @@ chesterGL.setupPerspective = function () {
} else {
throw "Invalid projection: " + chesterGL.projection;
}
+
+ chesterGL.basePMatrix = chesterGL.pMatrix;
};
/**
@@ -823,10 +825,53 @@ chesterGL.setRunningScene = function (block) {
};
/**
+ * Sets the current camera. The scene will be rendered as if seen from a camera attached to the block.
+ * @param {chesterGL.Block} A Block of type Camera, created thusly: new chesterGL.Block(null, chesterGL.Block.TYPE.CAMERA)
+ */
+chesterGL.setCamera = function(block) {
+ if (block.type == chesterGL.Block.TYPE['CAMERA']) {
+ chesterGL.camera = block;
+ }
+}
+
+/**
* main draw function, will call the root block
* @ignore
*/
chesterGL.drawScene = function () {
+ //Setup camera transformation
+ var par = chesterGL.camera;
+ var parents = [];
@funkaster Owner

I agree with you that this is somewhat inefficient, also creating new elements on every frame is not so good for GC.
One way we could avoid this (calculation of the camera transform) is with lazy evaluation... not sure how to achieve this yet, but seems like a good idea

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ // Work up the camera's chain of parents. This is somewhat inefficient, as they'll also get
+ // transformed as part of rendering the scene, but it's worth having the ability to just
+ // attach a camera to some block and have it follow the block, etc.
+ while(par) {
+ parents.push(par);
+ par = par.parent;
+ }
+
+ // We go backwards so that we start at the root and finish with the camera.
+ for(var i=parents.length-1; i >= 0; i--) {
+ parents[i].updateTransform();
+ }
+
+ // Invert and multiply onto the view transform.
+ // this looks a little wonky when using a camera that is a child of a normal block
+ // because we end up using the previous frame's transform for that block.
+ // TODO: refactor Block.visit into separate update and transform steps so we can
+ // use the current frame's transform here. This would also let us have multiple
+ // cameras each with their own viewport in the main port, picture in picture style.
+ chesterGL.pMatrix = goog.vec.Mat4.createFloat32();
@funkaster Owner

Same here. If you're doing this every frame, ideally you want to have a temp vector/matrix around just to reuse it and avoid creation every frame, that's more friendly with GC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ var camTransform = goog.vec.Mat4.createFloat32();
+ if(goog.vec.Mat4.invert(chesterGL.camera.mvMatrix, camTransform)) {
+ goog.vec.Mat4.multMat(chesterGL.basePMatrix, camTransform, chesterGL.pMatrix);
+ }
+ else {
+ if(console) console.log("Inverse of camera transform is undefined!");
+ }
+
+ chesterGL.runningScene.isTransformDirty = true;
+
var gl = undefined;
if (chesterGL.webglMode) {
gl = chesterGL.gl;
@@ -1103,3 +1148,4 @@ goog.exportSymbol('chesterGL.togglePause', chesterGL.togglePause);
goog.exportSymbol('chesterGL.isPaused', chesterGL.isPaused);
goog.exportSymbol('chesterGL.addMouseHandler', chesterGL.addMouseHandler);
goog.exportSymbol('chesterGL.removeMouseHandler', chesterGL.removeMouseHandler);
+goog.exportSymbol('chesterGL.setCamera', chesterGL.setCamera);
View
108 html/test_camera.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <link rel="stylesheet" type="text/css" href="test.css"/>
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
+ <!-- <script type="text/javascript" src="externals/webgl-debug.js"></script> -->
+ <script type="text/javascript" src="chester.js"></script>
+ <!-- audio!! -->
+ <script type="text/javascript">
+
+$(document).ready(function () {
+ setupGame();
+ function setupGame() {
+ chesterGL.settings['useGoogleAnalytics'] = true;
+ chesterGL.setup("demo-canvas");
+ var size = chesterGL.viewportSize();
+ var oneDeg = Math.PI / 180.0;
+
+ chesterGL.loadAsset("texture", "images/test.png");
+ chesterGL.loadAsset("texture", "images/star.png");
+ chesterGL.assetsLoaded("texture", function () {
+ // $("#loading").html("Test Single Block");
+ // finish with the setup and run the game
+ chesterGL.setupPerspective();
+
+ var sceneBlock = new chesterGL.Block(null, chesterGL.Block.TYPE['SCENE']);
+ sceneBlock.title = "Test::Single Block";
+ chesterGL.setRunningScene(sceneBlock);
+
+ // create a block
+ var someBlock = new chesterGL.Block();
+ someBlock.setTexture("images/test.png")
+ // someBlock.rotateBy(-45);
+ someBlock.setPosition([size.width/2, size.height/2, 0]);
+
+ var someBlock2 = new chesterGL.Block();
+ someBlock2.setTexture("images/star.png");
+ someBlock2.setPosition([60, 0, 0]);
+ someBlock.addChild(someBlock2);
+
+ sceneBlock.addChild(someBlock);
+
+
+ var someBlock3 = new chesterGL.Block();
+ someBlock3.setTexture("images/star.png");
+ someBlock3.setPosition([30, 60, 0]);
+
+ // === CAMERA EXAMPLE ===
+ // create a camera:
+ var camera = new chesterGL.Block(null, chesterGL.Block.TYPE.CAMERA);
+ // Misfeature: the camera's position is actually the location of the lower-left
+ // corner of the viewport. So, if you want the camera's parent in the center,
+ // you have to set the offset yourself. This should be fixed in a later update.
+ camera.setPosition([-200, -200, 220]);
+
+ // attach the camera to some block:
+ someBlock3.addChild(camera);
+
+ sceneBlock.addChild(someBlock3);
+
+ // VERY IMPORTANT: actually set the camera.
+ chesterGL.setCamera(camera);
+ // === END CAMERA CODE ===
+
+ // add some action
+ var bouncyFn = function () {
+ if(typeof this.dz === "undefined") this.dz = 10;
+ //this.setRotation(this.rotation + oneDeg);
+ this.setPosition([this.position[0], this.position[1], this.position[2] + this.dz]);
+ if (this.position[2] >= 200) { this.dz = -this.dz; }
+ if (this.position[2] <= -200) { this.dz = -this.dz; }
+ }
+
+ someBlock.setUpdate(bouncyFn);
+ someBlock2.setUpdate(bouncyFn);
+ someBlock3.setUpdate(function () {
+ this.setRotation(this.rotation - oneDeg/10);
+ });
+
+ chesterGL.run();
+ // draw a single frame (for debug purposes)
+ // chesterGL.drawScene();
+ });
+ } // setupGame()
+});
+ </script>
+ <script type="text/javascript">
+var _gaq = _gaq || [];
+_gaq.push(['_setAccount', 'UA-77863-9']);
+_gaq.push(['_trackPageview']);
+
+(function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+})();
+ </script>
+</head>
+<body>
+ <div id="loading" style="position: absolute; z-index: 100;"></div>
+ <div id="game-container">
+ <canvas id="demo-canvas" width="640" height="480"></canvas>
+ <div>
+ <span id="debug-info">00</span> ms per frame
+ </div>
+ </div>
+</body>
+</html>
Something went wrong with that request. Please try again.