Better customization of the Threejs env
To make a lib a better Threejs player we should allow Threejs primitives to be customized via the public api. Care need to be taken not to be merely passing many options.
This includes:
- Scene
- Renderer
- Camera
- Controls
- Lighting settings
- Fog
We can either
- expose these objects as props
- allow a primitive to be injected via the constructor
- allow them to be customized via new constructor arguments (ex 'sceneOpts')
We can define an approach per case.
Some examples:
1 exposing as prop
If we expose the scene, it can be customized
const preview = new GCodePreview({ ... });
preview.scene.fog = new THREE.Fog( 0xcccccc, 10, 15 );
2 inject
For something like fog it makes sense to allow it to be injectable by itself
const preview = new GCodePreview({
fog: new THREE.Fog( 0xcccccc, 10, 15 )
});
3
const preview = new GCodePreview({
sceneOpts: {
fog: new THREE.Fog( 0xcccccc, 10, 15 )
}
});
I tend to like the simplicity of exposing the scene.
We don't want to add an abstraction layer on top of Three for almost everything, and support upgrade breaking changes.
The problem with that option is that we don't have control over cleanly disposing of things that would be added to the scene in external context of the renderer class. We also remove all children at each call of render(), which would be incredibly annoying. It's a false promise of flexibility.
I have partial ideas that complete each other out.
4 Inject a prebuilt scene, we control it
const scene = new THREE.scene();
scene.fog = new THREE.Fog( 0xcccccc, 10, 15 )
const light = new THREE.AmbientLight( 0x404040 );
const preview = new GCodePreview({
scene: scene,
sceneAppend: [light]
});
Of course, we'd have to override anything on the scene we must set. I'm not sure how risky that approach is.
sceneAppend could accept an array of anything that is addable to the scene. We can manage the lifecyle.
The better option might be something entirely different: allowing users to use a gcode object in their own scene (BYO Scene). This avoids all of the above complexity / risk while users have all the freedom.
The way to enable this would be to encapsulate all gcode processing logic into a 3d object. Basically, parser + interpreter -> geometry. geometry + material -> mesh. With a wrapper that has getters and setters to update the gcode object with color, linewidth, everything.
..I'm thinking about (the so many ways of) splitting webgl-preview.ts and this might help.. and it will ensure better decoupling.
I like the idea of this as a scene so the other threejs parts of my app could live in the same canvas and just swap scenes to improve perf. @remcoder Are there any notes you have on making this as a patch?
I could see this being non-braking but a bit less elegant
Hi @TimTheBig, the ticket was just an idea about customization although I can totally understand the perf aspect.
IFAIK a common way for sharing a canvas between scenes is the scissor technique. But it doesn't seem to be a generic solution.
You might also want it check first how much perf you gain. Most of the memory is tied up with specific resources. So unless you share the gcode mesh between the canvases, there might not be much gain.
I guess it really depends on your usecase. I think it can become quite complex and specific to the usecase and I cannot say this is a solution we want to adopt actually.
But if you can find a clean solution we will consider adopting it and this might be a good time because we're in the middle (towards the end) of a breaking refactor.
A way to put the g-code preview in the same canvas with the same plate and lighting as my model preview is the main thing I'm looking for, to improve my visual consistency. Maybe a simple lower level init function that places the g-code in the canvas with no other stuff would work better. Maybe with an offset and someother options.
Do you think that would work better?
I think your idea would be to layer 2 canvases on top of each other if I'm not mistaken? If that's what you mean than that's already possible by disabling the build volume (just set to undefined).
What about using gcode preview to create the geometry and then render it in your own canvas? This could be done by creating a method that executes the gcode and converts the paths to their geometries. (Paths have a .geometry() method)
You then have the full control over rendering the geometry and applying lighting.
If that's what you mean than that's already possible by disabling the build volume (just set to
undefined).
I thought that option just disabled the 3d box around the plate not all of it, maybe that should get a doccomment.
What about using gcode preview to create the geometry and then render it in your own canvas? This could be done by creating a method that executes the gcode and converts the paths to their geometries. (Paths have a .geometry() method)
You then have the full control over rendering the geometry and applying lighting.
Perfect, thanks for the help.