Forge3D
Forge3D is a library to make 3D desktop apps within rew
. Forge3D is built on top of the node-3d project.
Installing
You can install Forge3d from github:kevinJ045/rew.forge3d
with either pimmy or rew
.
# pimmy
pimmy -Sa rew.forge3d
# rew
rew install github:kevinJ045/rew.forge3d
# rewpkgs
rew install @rewpkgs/rew.forge3d
Basic Usage
Forge3D comes as a Usage by default, but by using the Weld function, you can use it naturally.
import * as Forge3D from "rew.forge3d";
{ Mesh, BoxGeometry, Scene } = Forge3D.Weld()
{ scene, camera, animate } = Scene::create()
box = new Mesh(new BoxGeometry)
scene.add box
animate()
Using with directives
By default, to use Forge you need 3 using directives.
using imp('rew.forge3d'), (Forge3D) ->
using namespace Forge3D, ->
using Scene, ->
box = new Mesh(new BoxGeometry)
@scene.add box
@animate()
Explanation
First, we import forge3d
and use it as a usage. when we use it, it returns the Forge3D Context we get when we call Weld
.
First, we import
forge3d
and use it as a usage, when we use it, it returns the Forge3D Context we get when we callWeld
, we also pass a function as a callback to pickup the Forge3D Context.coffeeusing imp('rew.forge3d'), (Forge3D) ->
Using the Forge3D namespace, we will not need to write Forge3D everytime we want to do something involving the Forge3D Context, like
Forge3D.Mesh
orForge3D.BoxGeometry
. We then pass the function which is where we can use our namespace.coffeeusing namespace Forge3D, ->
Next, instead of doing
Scene::create
as we did in the above example, we use theScene
from Forge3D, and since we are using a namespace, this meansForge3D.Scene
. TheScene
usage requires a function to be passed, which is where we will be able to access our scene context, likecamera
,renderer
,animate
.coffeeusing Scene, ->
Finally, we can use everything we have so far to make a basic box and render it.
coffeebox = new Mesh(new BoxGeometry) @scene.add box @animate()
Forge3D Context
The Forge3D Context provides every single class from three.js, in addition to the returns from 3d-core-raub's init function.
document: Document
window: Window
requestAnimationFrame: Function
gl: GL
... More raub stuff
... More three stuff
The Scene
Context.
The scene context is the one you get when you either Scene::create
or using Scene
.
camera: THREE.PerspectiveCamera
renderer: THREE.WebGLRenderer
scene: THREE.Scene
animate: Function
# with Scene::create
listener:
on: Function
off: Function
emit: Function
# with using Scene
on: Function
off Funciton
emit: Function
Conditional Methods
If you're using the Scene::create
method, you will have an additional listener
object with an emitter type, while if you use the using Scene
method, you will get the listener as a part of the context.
Using Scene
When you use Scene
with the using directive, the function you pass is called with the scene's context as a caller. Therefore; You can use @
or this.
to access the context's properties.
using Scene, ->
@camera.far = 1000
@on 'animate:render', (time) ->
print 'One frame'
@scene.add ...
@animate()
Scene events
So far, there is only one event, which is the animate:render
event which is emitted on each frame. It gives you the current time which is a Date.now()
value
@on 'animate:render', (time) ->
print time
The With
function
The With
function can be used to merge other properties to your Forge3D Context.
Forge3D.With(
{ myProperty: 'something' }
)
Forge3D.myProperty # 'something'
Importing threejs modules
To import three.js modules, you can use the With
function on your context.
Forge3D.With(
'controls/OrbitControls.js'
'loaders/GLTFLoader.js'
)
Using With
You can use it with Weld
if you are using the normal approach to get your Forge3D Context
import * as Forge3D from "rew.forge3d";
{ OrbitControls, Mesh, BoxGeometry, Scene, document } = Forge3D.Weld().With 'controls/OrbitControls.js'
{ scene, camera, animate } = Scene::create()
new OrbitControls camera, document
box = new Mesh(new BoxGeometry)
scene.add box
animate()
Using With
with using
Once you get access to your Forge3D Context, you can use the context with With
since it returns the context itself.
using imp('rew.forge3d'), (Forge3D) ->
using namespace Forge3D.With(
'controls/OrbitControls.js',
{ myBoxName: 'Boxy' }
), ->
using Scene, ->
box = new Mesh(new BoxGeometry)
box.name = myBoxName
print box.name
@scene.add box
@animate()
Using Weld
with using
When you nest using
s, it becomes more and more annoying to deal with it, so you can use a welded forge context instead. This way, you save up on one line and indentation level.
using namespace imp('rew.forge3d').Weld().With(
'controls/OrbitControls.js'
), ->
using Scene, ->
box = new Mesh(new BoxGeometry)
box.name = myBoxName
print box.name
@scene.add box
@animate()
Why use namespace
?
The reason we are using namespace
here is because we are instantly imporing Forge3D
, initating a context with other modules, then passing it as a namespace so we don't have to access the context through Forge3D
.
The Compose
function
It's not a necessary function but rather more useful when you are trying to beautify your code, it returns either a namespace group or a usage group based on what you pass.
using namespace imp('rew.forge3d').Weld().Compose ->
using Compose(Scene) ->
box = new Mesh(
new BoxGeometry 1, 1, 1
new MeshStandardMaterial color: 0xff1234
)
@scene.add new AmbientLight 0xd1d1d1, 1
@scene.addAt [100, 50, 50], new DirectionalLight 0xffffff, 0.4
@on 'animate:render', (time) ->
box.rotation.x = time * 0.0005;
box.rotation.y = time * 0.001;
@scene.add box
@animate()
Example
using namespace Forge3D = imp('rew.forge3d').Weld().With(
'controls/OrbitControls.js'
).Compose ->
using Compose(Scene) ->
new OrbitControls @camera, document
box = new Mesh(
new BoxGeometry 1, 1, 1
new MeshStandardMaterial color: 0xff1234
)
@scene.add box
@scene.add new AmbientLight 0xd1d1d1, 1
@scene.addAt [100, 50, 50], new DirectionalLight 0xffffff, 0.4
@on 'animate:render', (time) ->
box.rotation.x = time * 0.0005;
box.rotation.y = time * 0.001;
@animate()