A Julia module to render graphical objects, especially 3-D objects, using the ThreeJS abstraction over WebGL. Outputs Patchwork Elems of three-js custom elements. Meant to be used to help packages like Compose3D render 3D output.
Click on any of the above examples to see the code used to draw them.
Where can these be used?
WebGL lets you interact with the GPU in a browser. As long as you have a modern browser, and it supports WebGL (Check this link to see if it does!), the output of this package will just work.
Pkg.build("ThreeJS") fetches and installs the three-js
webcomponents. This will be done automatically if you install ThreeJS.jl using
However, if you clone ThreeJS.jl (with
Pkg.clone or otherwise), then these webcomponents
must be installed manually into
assets/bower_components. This is done to allow simultaneous
development of both repositories.
API documentation can be found here.
For use in IJulia notebooks,
using ThreeJS will set up everything including
NOTE: If you are restarting the kernel, and doing
using ThreeJS again, please
reload the page, after deleting the cell where you did
push!(window.assets,("ThreeJS","threejs")) in your Escher code,
will get the static files set up and you can do 3D Graphics in Escher!
General web servers
To use in a web server, you will need to serve the asset files found in the
assets/ directory. Then adding a HTML import to the
three-js.html file in
assets/bower_components/three-js will get you all set up! This is done
by adding the following line to your HTML file.
<link rel="import" href="assets/bower_components/three-js/three-js.html">
How to create a scene?
For rendering Three-JS elements, all tags should be nested in a
This can be done by using the
initscene function. An outer div to put this in
is also required and can be created by using the
The code snippet below should get a scene initialized.
using ThreeJS outerdiv() << initscene()
By default, a scene of
1000px x 562px is created. Support to change this will
be added soon.
In Three-JS, meshes are objects that can be drawn in the scene. These require a
geometry and a
material to be created. Meshes decide the properties as to the
position of where the object is drawn.
A mesh can be created using the
mesh function taking the coordinates
as its arguments.
geometry and a
material element should be nested inside this
Geometries hold all details necessary to describe a 3D model. These can be thought of as the shapes we want to display.
ThreeJS.jl provides support to render the following geometry primitives:
- Boxes -
box(width, height, depth)
- Spheres -
- Pyramids -
- Cylinders -
cylinder(topradius, bottomradius, height)
- Tori -
- Parametric Surfaces -
parametric(slices, stacks, xrange, yrange, function)
- Dodecahedron -
- Icosahedron -
- Octahedron -
- Tetrahedron -
- Planes -
These functions will return the appropriate
geometry tags that are to be nested
mesh along with a
material to render.
geometry function is able to render custom geometries, which are specified
by the vertices and the faces.
Materials are what decides how the model responds to light, color and such properties of the material.
material tag is created by using the
material function. Properties are
to be passed as a
Dict to this function.
Available properties are:
color- Can be any CSS color value.
kind- Can be
texture(for texture mapping)
texture- URL of image to be mapped as texture. Will be applied only if
kindis set to
false. Set to
trueto get proper rendering for transparent objects.
opacity- Number between 0.0 and 1.0 (fully opaque).
Some helper functions to get these key value pairs is given in
Putting them together
mesh(0.0, 0.0, 0.0) << [box(1.0,1.0,1.0), material(Dict(:kind=>"basic",:color=>"red")]
will create a cube of size 1.0 of red color and with the basic material.
Lines can be drawn by specifying the vertices of the line in the order to be
joined. Lines can either be of
"pieces" kinds, which decide how
the vertices should be joined.
"strip" lines join all vertices, while "pieces"
only joins the first and second, third and fourth and so on. Colors for the
vertices of the lines can also be specified.
Lines are also meshes and has the properties of a mesh too, like position and
rotation. Like meshes, they are a child of the
Lines also require a material to decide properties of a line.
linematerial function can be used to do this and specify some properties
for the line. The
linematerial should be a child of the
line function can be used to draw lines.
line([(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)]) << linematerial(Dict(:color=>"red"))
Drawing mesh grids can be achieved by using the
meshlines function. It creates
a set of lines to form the grid and assigns colors to the vertices based on the
If you are looking for a 2D grid, use the
grid function. It creates a grid on
the XY plane which can then be rotated as required.
No 3D scene can be properly displayed without a camera to view from. ThreeJS.jl
provides support for a Perspective Camera view using the
This sets the position of the camera, along with properties like
fov for field of view (in degrees), and
camera tag should be a child of the
ThreeJS.jl provides support for 3 kinds of lighting.
- Ambient -
- Point -
pointlight(x, y, z; color, intensity, distance)
- Spot -
spotlight(x, y, z; color, intensity, distance, angle, exponent, shadow)
These tags should also be a child of the
By default, ThreeJS adds TrackballControls to every scene drawn. This lets you interact with the scene by using the trackpad or mouse to rotate, pan and zoom.
You can use the reactive functionality
provided by Escher to create Signals of the 3D graphic elements produced.
These can let you create graphics that can be interacted with using UI elements
like sliders. Try launching
escher --serve (if you have Escher installed)
examples/ directory and heading to
localhost:5555/box.jl on the
browser. You can see a box whose width, depth, height and rotation about
each axes can be set and the box will update accordingly!
Currently, this functionality does not work in IJulia notebooks. Hopefully,
this will be fixed soon and you can use
to do the same in IJulia notebooks.
You can also do animations by using Reactive signals. See
examples/rotatingcube.jl as an example. It is implemented in Escher,
so running an Escher server from that directory and heading to
localhost:5555/rotatingcube.jl should give you a cube which is
NOTE: Adding new objects to a scene will force a redraw of the scene, resetting the camera.
using ThreeJS outerdiv() << (initscene() << [ mesh(0.0, 0.0, 0.0) << [ box(1.0,1.0,1.0), material(Dict(:kind=>"lambert",:color=>"red")) ], pointlight(3.0, 3.0, 3.0), camera(0.0, 0.0, 10.0) ])
Running the above in an IJulia notebook should draw a red cube, which is illuminated by a light from a corner.
For Escher, after the script above is run, the following code should give the same result.
using ThreeJS using Compat main(window) = begin push!(window.assets,("ThreeJS","threejs")) vbox( title(2,"ThreeJS"), outerdiv() << ( initscene() << [ mesh(0.0, 0.0, 0.0) << [ ThreeJS.box(1.0, 1.0, 1.0), material(Dict(:kind=>"lambert",:color=>"red")) ], pointlight(3.0, 3.0, 3.0), camera(0.0, 0.0, 10.0) ] ) ) end