Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPEN DISCUSSION: event-driven material assignment? #84

Open
sinisterchipmunk opened this issue Mar 10, 2013 · 2 comments
Open

OPEN DISCUSSION: event-driven material assignment? #84

sinisterchipmunk opened this issue Mar 10, 2013 · 2 comments

Comments

@sinisterchipmunk
Copy link
Owner

This is only a thought and I have no clue what the actual implementation would look like.

I have never been happy with the way Jax assigns uniform variables and attributes to the shaders. It is pretty easy for a developer (and we've come a long way toward making it as simple as possible), but there are significant performance penalties coming from the current approach.

Currently, all variables are assigned to each shader in use, every frame. This results in a predictably huge amount of time wasted on redundant assignments. Since Jax.Material#setVariables is called so many times, there is also significant CPU waste in the form of recalculating intermediate variables on the JavaScript side.

(Note: I haven't done any profiling. These are just my observations when looking at the way the code works.)

I'd like to try to remove as much of this overhead as possible. My proposal is to make changes event-based, so that they are only assigned when some dependent attribute is modified.

We'd leave the Jax.Material#setVariables method in place as it exists today. This way, legacy code would not be broken, and variables could still be recalculated every frame if needed.

This proposal comes in the form of an additional hook method (here called register), which would become the new "best practice" for shader variable assignment.

It could look something like this:

class Jax.Material.Layer.Position extends Jax.Material.Layer
  register: (context, mesh, model, vars) ->
    model.camera.on 'change', ->
      vars['MODEL_MATRIX'] = model.camera.getTransformationMatrix()
    # ...

Fringe benefits include less internal reliance on the matrix stack, and consequently less matrix concatenation on the CPU. We'd let the dependent matrices be calculated on the GPU, which is pretty much always faster than on the CPU, and I would be willing to bet that since the matrix calculations would usually be based on uniforms, they'd be very well optimized.

The vars object would be a collection of variables with the same API as today, but would not function as we know them today. Today, an assignment to the vars object is essentially global to the shader. The above model wouldn't quite work, otherwise a change based on any mesh using this material, would make the same change for all meshes using this material -- not what we want. So instead, vars would have to be managed, at a minimum, per-mesh: an assignment to the vars of one mesh would not alter the assignment to vars of another, because there would be multiple separate internally-managed vars objects. Thus, there would be a multitude of event listeners, each operating on various different meshes as materials are added to them.

We could also implement an unregister method for unhooking events when materials are removed. This would give the developer greater control, but I'd also be in fan of somehow being aware of which event listeners were registered by which materials on which meshes; and then Jax could just unregister all listeners when a material is removed from a mesh. This would nearly always be the expected result, after all.

@Goutte
Copy link
Contributor

Goutte commented Mar 14, 2013

This looks great ! (except the first line)
I can't really be constructive, not knowing much about how jax and others handle GLSL, but I see the point of event-based assigning.

What event do you think of ?
I could only come up with :

Model Camera

  • change
  • direction change
  • position change

Context Active Camera

  • roll, yaw, pitch

@sinisterchipmunk
Copy link
Owner Author

For this to work, I think there need to be plenty of hooks for event listeners throughout Jax. Fortunately, a lot of these are already in place, though they may need some tweaking. We also would need to make triggering custom events much easier to do, so people can trigger changes based on things we can't foresee. I'm thinking of something like jQuery's trigger(evtName[, evtData]) method available to all Jax objects.

Some built-in events off the top of my head:

  • Context
    • camera count changed
    • controller instance changed (redirect)
    • controller action fired (before, after)
  • Camera
    • changed / moved / rotated
  • World
    • model added / removed
    • light added / removed
    • ambient color changed
  • Model
    • camera changed / moved / rotated
    • mesh changed
    • sub-model added / removed (sub-models are not implemented at this time, just a separate idea I've been kicking around)
  • Mesh
    • Material changed / replaced
    • Mesh vertices / normals / tangents / colors / etc changed
  • Material
    • Property or attribute changed -- these would vary on a per-material basis
  • Light
    • Position / direction / color / intensity / etc changed
    • Enabled / disabled

I'm sure there are many more to be considered, but that's the list of what strikes me as immediately obvious.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants