jared-hughes / desthree Goto Github PK
View Code? Open in Web Editor NEWDesmos bindings for three.js
Desmos bindings for three.js
Extrusion and Shape take a 2-d Path as input. This could simple be a list of line segments, but it could also support Quadratic curves and Cubic Bezier curves. Simplest option would be to use splineThru to get a smooth cubic spline through the list of points.
Note: Desmos points are not currently exposed in the API, so this would require a 2d point function similar to Vector3.
Lathe takes a list of points for some reason and does not support paths.
This would be a variation on the Mesh
function that supports styling a single geometry with a list of materials instead of broadcasting over the material argument.
It appears that https://threejs.org/docs/#api/en/core/BufferGeometry.addGroup exposes this natively.
Since all other geometries (box, sphere, etc.) are subclasses of BufferGeometry, this could apply to all geometries in DesThree.
Sample use case: styling a corner of a Rubik's cube with four different colors and using a BoxGeometry for it.
A few issues here that are related:
graphChanged
event); purely visual. For example, try pressing ctrl+A in expression 2 of https://www.desmos.com/calculator/ghjdxovcyjTwo possible fixes to consider:
[expr-id=24] > ...
to control style. This would be convenient, but it has the downside of not updating autoOperatorNames
MutationObserver
on the expressions list to observe when expressions are changed, then check if the data property expr-id
falls within the set of DesThree expressionsI'm leaning toward the second because it might fix #9 too.
To prevent confusion between different versions of DesThree and related graphs, store the DesThree version somewhere in the state.
For 1.0+ release, include automatic migration to higher versions.
For now (0.x.x releases), just warn user that version is incorrect. Say "loaded graph will probably will not work" if minor versions differ. Give a milder warning if only patch versions differ. Include a link to https://github.com/jared-hughes/DesThree/releases/ (the correct release if possible).
If possible, give an extra warning in the save menu (if duplicate graph is unchecked) to avoid overwriting old graphs.
When trying to type "PointLight,"
the "int"
gets converted to an integral in MathQuill. The current workaround is to copy-paste the function name from elsewhere.
I see a few ways of proceeding:
"Po\\intL"
with "PointL"
in graphChanged
The third approach will probably work the best as it allows integrals inside arguments.
This would be epic if this works.
I see two ways to load textures:
By default SphereGeometry
(and others like Cone, Torus, etc.) is not smooth enough for most people's standards.
I propose a function DefaultSmooth(n)
(or a variable might work better with implementation and dependencies) as a graph configuration setting to allow users to consider the tradeoff with speed. This should multiply values like widthSegments
by n
when not given. The value n=1
could be the current low-poly number of segments, and n=4
should be the default. Most people would not want to exceed far past n=30
(which has 900 times the number of triangle faces) for speed concerns.
Also, a TorusKnotGeometry
with high p
or q
(maybe lcm(p,q)
determines this?) should have many more tubular segments.
Expressions get too long, too quickly. Changing functions like ColorRGB
to RGB
, IcosahedronGeometry
→ Icosahedron
, MeshBasicMaterial
→BasicMaterial
, etc. would improve this situation.
This should happen soon to allow for better backwards compatibility.
(u,v) ∊ [0,1]²
and returns a Vector3t ∊ [0,1]
and returns a Vector3.The difficulty here is in taking Desmos functions as arguments to DesThree functions.
The global Calc
object does expose the generated functions (to some degree). For example, in https://www.desmos.com/calculator/l0dcnucrrh (with the expression f(x)=x^2
), Calc.controller.grapher.graphSketches[3].branches[0].compiled.fn(5)
returns 5^2=25.
Perhaps values can be interpolated between generated segments from Calc.controller.grapher.graphSketches[3].branches[0].segments
.
EdgesGeometry (renders all edges: includes diagonals on a BoxGeometry)
WireframeGeometry (renders only edges on faces with different normals: excludes diagonals on a BoxGeometry)
This would be a large task because these are handled differently than meshes:
THREE.LineSegments
instead of THREE.Mesh
LineBasicMaterial
or LineDashedMaterial
instead of the existing mesh materials.THREE.Points
instead of THREE.Mesh
PointsMaterial
instead of the existing mesh materials.Suggested by Idealistic Introvert in the Discord. This would be helpful for showcases and possibly for documentation similar to #55. A limited version could even possibly be used for tests to verify that produced visuals are consistent across versions.
Unfortunately Gifsmos does not expose its calculator object, so modification through userscript would not be simple.
Either:
calculator.asyncScreenshot
I would prefer going with the first option after the DesThree 1.0 release so that this is a stable project to point to.
DesThree sometimes uses @3
, sometimes desThree-
, sometimes three-
, with no semantic difference. Should unify it all as desThree
while still allowing @3
or three
to be typed to insert a DesThree expression.
Right now, only color is supported as an argument for LambertMaterial, PhongMaterial, etc.
More are supported; https://www.desmos.com/calculator/zgibydvrou has specular highlights (from the spotlight) that are way too bright for my taste, and PhongMaterial allows adjusting the specular multiplier. Probably more can be allowed and used.
The autoOperatorNames
property is set to include the DesThree custom expressions only after the first graph load, so function names are not italicized at first. See https://www.desmos.com/calculator/pdhfz3bq07 — expect Show
, Mesh
, and BoxGeometry
to be in the upright font. Simply deleting and retyping the last letter of each function is an annoying workaround.
Unfortunately the latex and graph state does not save \operatorname
commands.
The three
expression type in the add expression context menu stops showing up after toggling the edit list feature in Desmos once.
I went ahead and inspected elements and it seems the element referenced here:
Line 18 in 13a791d
Maybe a slight modification to the observer could fix the issue. However, do note that this replacement/removal of nodes happens up to three parents above the element previously referenced when hiding and showing the expression panel. This means the safest option would be to track .dcg-exppanel-container
with a following query to make sure the context menu has appeared.
Having nearly half the program's code in one file is not great.
DesThree.js
should be split into separate files for Model, View, Controller, and parser.
This is a major performance issue. Something is wrong with dependency management, so many more renders are executed than necessary. Try changing the W
variable in https://www.desmos.com/calculator/hhvvj3zyat — that should be fast, but the model is rerendered 75 (?) times instead of 1.
The cause is likely that rerender()
is called every time each element of each list is changed.
A few remedy ideas:
requestAnimationFrame
or a timer-based system akin to lodash's throttle function. This would be simple but has issues with ensuring the last update of a batch is always includedgraphChanged
call. This would reduce the number of startup renders but have no effect on HelperExpression
changesHelperExpression
value change. This would help if multiple arguments (in one function or spread across several) are linked to a single helper expression, but oftentimes (like in camera spherical coordinates), the Desmos variable affects several helper expressions.I will likely not go with option 4 since it doesn't seem worth the effort. Option 1 might conceal the effects of improperly implementing the other options, so I'll implement it last.
This would use the Raycaster from three.js and a click handler.
Might want to hold off on this until clickable objects are officially released in vanilla Desmos, but that could be a year or two.
The error is not catastrophic. It is an uncaught exception that occurs when a graph is loaded with a DesThree expression inside a collapsed folder. Upon expanding the collapsed folder the script continues execution as normal. Test graph https://www.desmos.com/calculator/16szwajkgv
Error message is Uncaught TypeError: this.getExprElement(...) is null
and occurs within setExprError
.
Current test cases 11 ("All passthrough geometries") and 12 ("All materials") use the same variables and definitions for the camera position. When the test runner calls Calc.setState()
to switch between them, the camera position does not update. My hunch is that the helper expressions do not update, especially because those sliders become unresponsive.
Honestly, I never expected to get this far in the project.
Obviously a single 1200+ line userscript file will not be sustainable.
Also, @SlimRunner mentioned that syntax highlighting and cold folding are not quite working in Atom.
It's time to set up a build system and ESLint.
Who would use this? I have no idea.
Can define left/right/top/bottom same as Desmos's graphpaperBounds.mathCoordinates
Buffer geometry takes a list of points in 3D, along with face normals.
The face normals could be calculated like in dcaeb54, or they could be a second argument.
I'm thinking the best way to implement this is to create a Face(Vector3, Vector3, Vector3)
function, and take a list of faces as argument to BufferGeometry
function.
This would require rewrite of many parts of FunctionApplicationList
to allow for a custom type that does not automatically broadcast over each element of the argument's list.
Automatically Show
geometries, meshes, and lights that are not assigned to a variable, e.g. treat AmbientLight(0.2)
(which seems like it would add a light, but doesn't) as Show(AmbientLight(0.2))
. Leave the behavior of light1 = AmbientLight(0.2)
unchanged.
Sample changes:
Before → After
Show(AmbientLight(0.2)) → AmbientLight(0.2)
Show(Mesh(Sphere(0.5))) → Sphere(0.5)
Show(Mesh(Sphere(0.5), MeshLambertMaterial())) → Mesh(Sphere(0.5), MeshLambertMaterial())
The current state of specifying camera (and soon fog & grid lines) in separate expressions has a few disadvantages:
It would make much more sense to put these options in to replace the 2D options. Backend could be similar to existing approach.
Sample use case: making a barbell with two spheres and a cylinder. The user would want to make a list with these three objects, then use all three in a Mesh
call to share the material.
Suggested syntax: geoms = [SphereGeometry(2), CylinderGeometry(1, 5), SphereGeometry(2)]
(Unfortunately, position can only be specified right now on Mesh
es)
Also a use case: colors = [RGB(0,0,0), RGB(100,100,100), RGB(250,250,250)]
instead of colors = RGB([0,100,250], [0,100,250], [0,100,250])
This would also be a prerequisite before creating a Group
function.
In vanilla Desmos, various expressions' results are shown in a preview in the expressions list (https://www.desmos.com/calculator/ufiwm7unbp).
This could be useful to implement for some DesThree types. Example path:
PerspectiveCamera((Rcos(a)cos(b), Rsin(b), Rsin(a)cos(b))
It would be helpful to see the three coordinates in the expressions list.
It's annoying to control the view with a pair of sliders. Makes more sense to use something like OrbitControls to drag directly on the canvas.
Could be tricky to implement because view can also be controlled from PerspectiveCamera
.
A few ideas:
PerspectiveCamera
arguments from the OrbitControls values. This is super complicated for little gain, and there could even be race conditions if view is controlled by a slider that is playing.PerspectiveCamera
values with the OrbitControls valuesOrbitCamera
that allows specifying fov
, near
, and far
, avoiding the need for all this mess.This is a very simple solution to many problems.
Main difficulty with this would be changing the expression id in place without (a) moving the expression or (b) recalculating everything. setExpression
would not work because that keeps id constant. Could probably just remove the expression then tap into Calc.controller
pretty easily to dispatch a new expression event.
Alternatively, use some other property of expressions (like colorLatex
or pointOpacity
or something else that supports arbitrary strings) to store all metadata, including being a DesThree expression.
We currently have the Position
function to move meshes around, but Object3D supports so much more, main ones being rotation and scale.
I envision the following four additional functions:
Rotate(object3d, rotateX, rotateY, rotateZ)
— difficult for users bc EulerAnglesRotateQuaternion(object3d, quaternion)
— need to implement quaternion function. Maybe save for later.LookAt(object3d, vector3)
— parents of object3d must be uniformly-scaledScale(object3d, scaleX, scaleY, scaleZ)
— default scaleY and scaleZ to be same as scaleX.Currently, we clone the object for each Position
call, which would cause 4× memory usage (and increased CPU usage) if an object is positioned, rotated, and scaled. Before implementing this, should restrict each object to only one Position
call, only one Rotate
call, etc., and implement a Group
function that can create a new local axis system to reset this restriction.
Observe on https://www.desmos.com/calculator/p5kkfjzxr7. After using the graph for a few minutes, it seems to slow down a ton.
Can probably determine the cause in development mode. Most likely, the graph is rerendered several times or an object is re-created several times when a single variable changes.
I can't reproduce this very quickly though.
In PerspectiveCamera\left(1,2,5\right)
(see https://www.desmos.com/calculator/z4fn1drk3n), the first two numbers end up ignored, and 5
is treated as the fov
.
Expected behavior: give an error because 1
and 2
are not Vector3
s.
Shouldn't be too difficult — can fetch a list of graph states to test from URLs like http://saved-work.desmos.com/calc-states/production/znvwjvv8wg from the README then call Calc.setState(state)
on each. Generate test rig code that can be pasted into the browser console or maybe load desmos.com in an iframe.
Main desire would be to get 100% line coverage from tests. A few days back, I pushed a commit that accidentally renamed Dodecahedron
to Dodeahedron
; that would be caught by a test that covers the DodecahedronGeometry
class by drawing a dodecahedron.
Fog looks so cool, see https://threejs.org/examples/#misc_controls_orbit as an example.
Would implement FogExp2 and Fog
LinearFog(near, far, color=black)
Fog(density, color=black)
The shadow settings need to be tweaked to be enabled.
Also add ShadowMaterial, which allows for some cool effects; see the ground on https://threejs.org/examples/#webgl_geometry_spline_editor.
Probably want to implement planes first to get a similar effect as that example.
I believe this is the final mesh material available easily in three.js without using shader materials (#23).
These could serve two purposes:
This would involve uploading screenshots (and videos?) to a /docs
directory and linking those from the markdown files.
This will be hard to figure out.
TextGeometry exists, as does Sprite (always faces towards the camera). These seem overcomplicated though.
Might be able to make use of Desmos's existing label functionality or just draw text on the canvas without three.js or Desmos's help.
I think I figured out how to implement re-render throttling without having the issue mentioned in #27:
Show
and Camera
functions directly re-rendering, let them mark a variable to state that the scene/camera changedrequestAnimationFrame()
This would help with performance on first graph load and a few other cases, but is not especially critical.
Lots of new objects and other changes recently.
I already added tests for #37, #21, and #24, but still need to add tests for:
All of the above need documentation added. While doing this, consider if order of arguments make sense. E.g. lights should really have position/direction before color because color is white most of the time.
Currently, warnings are logged only to the console. For example, https://www.desmos.com/calculator/v22cbxnv7v logs "ParseError: too many arguments in call to BoxGeometry." Hovering over the yellow warning sign gives the tooltip "Sorry, I don't understand the @ symbol."
Expected behavior: tooltip says "ParseError: too many arguments in call to BoxGeometry" and no need for the console log.
Why no GLSL shaders in DesThree? Very sad.
This would require modifying the parser to allow strings like "buckets"
Would probably want to keep it simple and only allow Arial font, same as vanilla Desmos.
DirectionalLight - like daylight
SpotLight - light along cone
HemisphereLight - color along gradient from sky color to ground color
RectAreaLight is not included because it is very limited — no shadows, and only physically-based materials are supported.
Seems like there should be some easy way to draw coordinate axes and the x-y plane. ArrowHelper with a text sprite and GridHelper should be able to help.
One solution would be to use a single function to answer both of these questions for each component: SetArrowScale(Num s)
(and analogous SetGridScale
) could toggle off display if s ≤ 0
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.