Closed sinisterchipmunk closed 11 years ago
Hello !
Sorry for the long delay, I was knee-deep in maths these past days and forgot a bit about jax. I also don't get email notifications when an issue is added, even though I'm watching the repo. Weird.
I found the @define
voodoo a bit puzzling ; I agree that not being able to mutate camera.direction
or camera.position
calls for bad practice and yells one or two WTF. I did not expose this behavior in tests because I was not sure I was using it the right way.
I really like the Jax.Camera
API, all in all ; roll, pitch, yaw, everything I need is there.
camera.direction
and camera.rotation
would need integrity checks. Slowing things ? rotateQuat
is a good idea.setPosition
is the way to go.Also, I saw the other day that you refactored controls. I hacked a trackball camera by coupling its direction and position. The camera keeps pointing to a model's position while moving in a constrained sphere around the model.
Making such controls super-easy for new devs wanting to hack a quick demo would be nice.
Also, multiple ~states for the Camera (looking at menus, going back looking at a model, zooming on a part of a model, going back, etc.)
This is not really the Camera's job, though, as it involves controls. And it would need a really flexible animate
.
(i like the name, but don't like jquery's function signature, it's not jaxy)
Also, most of the easings are already well-coded, which is nice.
As long as we're visiting this, I'd like to see events play a more significant role throughout the API -- as I've mentioned before in other discussions.
So, have you any thoughts about this kind of general usage (putting aside animations and transitions and whatnot for the time being):
_movementDirection = vec3.fromValues 0, 1, 0
index: ->
tmp = vec3.create()
@activeCamera.on 'change:position', =>
vec3.subtract tmp, @model.camera.get('position'), @activeCamera.get('position')
@activeCamera.set 'direction', tmp
update: (tc) ->
pos = @activeCamera.get 'position'
vec3.add pos, pos, _movementDirection
@activeCamera.set 'position', pos
This would produce a camera that is moving along a vector [0, 1, 0]
and every time it moves, it triggers a change:position
event. This event is caught by the code in index
so that the active camera is always "looking at" some model's current position.
I've stolen some (all?) of the syntax from Backbone.js, though I am open to other suggestions as well. The general idea is that you could listen for "change"
to be notified of any change on the camera, or "change:property" to be notified of changes to a specific property.
One caveat is that you can still get away with the original issue, like so:
pos = @activeCamera.get 'position'
vec3.add pos, pos, _movementDirection
# the camera has not actually moved yet
However, the same could be accomplished with getPosition
and setPosition
et al, so at some point I suppose we just have to rely on documentation. I feel that this approach is, at least, a little more intuitive than the property assignments that were brought to us by @define
.
One really nice benefit to be gained from this approach is that properties could be defined willy-nilly by anyone on anything. For example, there's nothing to prevent me from listening for change:highScore
. Jax won't be assigning any value to highScore
on its own, of course, but subsequently setting that property's value in your own code would work as expected.
It also sort of normalizes the setters and getters APIs, allowing Jax to listen to relevant events internally to decide when the time is right to re-calculate the various matrices and whatnot.
I tried the Jax.EventEmitter
mixin. I don't know how much events impact perfs, but I like the idea of managing the camera's automatic behaviors as listeners.
It's more... tidy. It will help a lot to create super-smart cameras.
I'm a tad wary of the #get 'position'
in favor of #getPosition
, as explicit works better with IDEs.
On the other hand, I really like the change:highScore
benefit ! And it's no good relying too much on IDEs.
Another benefit of the set
approach will be for animations, I suppose.
I hacked together a small webgl game using Jax, btw.
I've rewritten Jax.Camera
according to this discussion. It uses get('property')
to return a property value, but the built-in ones are documented as read-only, and modifying them in-place is not recommended. (Custom properties can be set and gotten as normal.) For now I've also implemented other methods for manipulation, e.g. setPosition
. Over the next few days I'm considering whether to replace these with an overridden set('position', ...)
method. Still on the fence.
Performance is good, about on par with the previous implementation but with less overall confusion in the API (I hope).
Also implemented the animate
method. I think it still has some small bugs, which will shake loose through usage, but I'm pretty impressed with the initial result. I'm using tween.js because its low-level approach allows me to animate only on specific, custom-defined fields, and not waste cycles animating vectors we don't need.
This allows us to expose some very powerful options. Tween's easing and interpolation functions can also be set as options, and the animation:start
, animation:update
and animation:complete
events all fire as expected.
Coolest thing about the animations is, since pretty much every object has a camera, every object can be animated just as easily as the active camera -- and the events should make it easy for the model to react, such as by starting a "Walking" animation when its camera starts moving and returning to a "Standing" animation when its camera stops moving.
Though I know it'll never be perfect, I was really pretty happy with the new implementation of
Jax.Camera
until I saw this:This makes me sad. :(
Now I'm on the verge of officially releasing 3.0.0, and this raises significant design questions. Suddenly I'm hesitant to release this API, as it obviously encourages bad habits (temporary variables, no way to directly
vec3.transform cam.direction
).It's best to get compatibility-breaking API changes, if there are to be any, out of the way here and now, before a major-version release. I'd hate to get halfway to 3.1 and realize we have to make significant API changes that would make the 3.1 API incompatible with 3.0. That's why I'm OK with holding off on a release of 3.0 until we get this thing squared away.
I've been mulling this over for some time now, and still haven't reached a decision. The only thing I've come to thus far is: totally rewrite
Jax.Camera
.Rewriting
Jax.Camera
would not be as arduous a task as it implies. I have not decided to do this yet, but hypothetically, if I rewriteJax.Camera
, what should be added/changed?My thoughts right now:
Jax.Camera
from a quaternion. It should be equally easy to replace its current state with a quaternion (cam.rotation = [...]
). Finally, it should exposerotateQuat
(or a similarly-named method) so that it can be rotated by a quaternion. This also applies to Euler angles, angle/axis rotation (which is basically what is exposed right now), and 4x4 and 3x3 matrices.vec3.scale cam.position, [1,1,1], 2
wouldn't work in practice, it should not be possible within the API to try. If this means pulling out properties such ascam.position
and replacing them with functions such ascam.setPosition
, then so be it.cam.animate
, analogous to jQuery's$.animate
. Basically the camera should be able to transition smoothly from one state to another, so that the developer doesn't have to deal with such implementation details.Ponder This
How have your experiences with
Jax.Camera
been to date? Can you think of anything that should be addressed? What do you think about the above changes?