3D software developer at BioDigital
(Plus a sneak peek at xeoEngine)
Lindsay Kay
Berlin WebGL Meetup, 2 July, 2015
SceneJS
Applications
and
- WebGL-based 3D visualisation engine
- JSON scene definition
- Aims to abstractify
- Compiles to optimised internal render graph
- Little bit the way OpenSG and nVIDIA SceniX does it
- Started for fun on Canvas3D in 2009, now at V4.2
var scene = SceneJS.createScene({
nodes:[{
type:"material",
color: { r: .3, g: .3, b: 1 },
nodes:[{
type: "rotate",
id: "myRotate",
y: 1.0,
angle: 0,
nodes: [{
type:"geometry/teapot"
}]
}]
}]
});
scene.getNode("myRotate",
function(myRotate) {
var angle = 0;
scene.on("tick", function() {
myRotate.setAngle(angle += .5);
});
});
JSON-based 3D scene definition
{
type: "fresnel",
applyTo: "emit",
bias: 0.3,
power: 3.0,
topColor: {
r: 1.0, g: 1.0, b: 1.0
},
bottomColor: {
r: 0.0, g: 0.0, b: 0.0
},
nodes: [
{
type: "texture",
src: "crossGridColorMap.jpg",
nodes: [
{
type: "geometry/torus",
segmentsR: 60,
segmentsT: 40
}
]
}
]
}
Another example: Fresnel effect
SceneJS.Types.addType("myNodes/colorizer", {
construct: function(params){
this._material = this.addNode({
type: "material",
nodes: params.nodes
});
if(params.color){
this.setColor(params.color);
}
},
setColor: function(color){
this._material.setColor(color);
},
getColor: function(){
return this._material.getColor();
},
destroy: function(){
this._material.destroy();
}
});
Defining new scene node types
Define new node types in the plugins directory, then just include them in your scene
{
type: "myNodes/colorizer",
color: { r: 1, g: 0, b: 0 },
nodes: [
{
type: "geometry/teapot"
}
]
}
{
type: "postprocess/dof",
texelSize: 0.00022,
blurCoeff: 0.0084,
ppm: 10000,
autofocus: true,
nodes: [
{
type: "geometry/teapot"
}
]
}
Post-processing example: depth-of-field blur
- Roll your own posteffects from render target, texture and shader nodes
{
type: "texture",
src: "texture-atlas.jpg",
nodes: [
{
type: "translate", x: 1.5,
nodes: [{
type: "geometry",
positions: [1,1,0,-1,1,0,-1,-1,0,1,-1,0],
normals: [0,0,-1,0,0,-1,0,0,-1,0,0,-1],
// UV coords map to left half of texture image
uv: [1, 1, .5, 1, .5, 0, 1, 0],
indices: [0, 1, 2, 0, 2, 3]
}]
},
{
type: "translate", x: -1.5,
nodes: [{
type: "geometry",
positions: [1,1,0,-1,1,0,-1,-1,0,1,-1,0],
normals: [0,0,-1,0,0,-1,0,0,-1,0,0,-1],
// UV coords map to right half of texture image
uv: [.5, 1, 0, 1, 0, 0, .5, 0],
indices: [0, 1, 2, 0, 2, 3]
}]
}
]
}
Optimization: Texture Atlases
{
type: "geometry",
positions: [...],
normals: [...],
uv: [...],
nodes: [{
type: "texture",
src: "BrickWall.jpg",
nodes: [{
type: "geometry",
// Indices for first three faces
indices: [...]
}]
}, {
type: "texture",
src: "general-zod.jpg",
nodes: [{
type: "geometry",
// Indices for remaining three faces
indices: [...]
}]
}]
}]
}
Optimization: Vertex sharing
{
type: "cull/detail",
min: [-8,-3,-5],
max: [8,6, 5],
sizes: [50,250,350],
showBoundary: false,
frustumCull: true,
nodes: [
{
type: "geometry/box"
},
{
type: "geometry/sphere"
},
{
type: "geometry/teapot"
}
]
}
Optimization: Level-of-Detail
- Multiple culling engines in workers
- http://xeolabs.com/articles/scenejs-detail-culling/
{
type: "physics/body",
shape: "sphere",
radius: 1.0,
pos: [-5.0,-2.3,1.2],
velocity: [0,0,0],
mass: 1.0,
movable: true,
restitution: 1.0,
friction: 0.1,
nodes: [
{
type: "geometry/sphere"
}
]
}
Experimental physics
- Multiple JigLibJS systems in workers
- http://xeolabs.com/articles/scenejs-physics
Ray-picking using the depth buffer
- Uses depth buffer to find Z
- http://xeolabs.com/articles/scenejs-ray-picking-technique/
- Seems to work well for huge meshes
Automatic lost WebGL context recovery
- When context is recovered, rebuilds WebGL textures, vertex buffers etc. from scene state, without re-downloading anything
{
type: "clips",
clips: [
// Arbitrary clipping planes
{
x: -1.0,
y: 0.2,
z: 0.0,
dist: 1.0,
mode: "inside"
},
//...
],
nodes: [
{
type: "geometry/torus"
}
]
}
Cross-sections
{
type: "texture",
src: "earthDiffuse.jpg",
applyTo: "color",
nodes: [
{
type: "texture",
src: "earthNormal.jpg",
applyTo: "normals",
nodes: [
{
type: "texture",
src: "earthSpecular.png",
applyTo: "specular",
nodes: [
{
type: "texture",
src: "earthEmit.gif",
applyTo: "emit",
nodes: [
{
type: "geometry/sphere"
}
]}
]}
]}
]}
Multitexturing
{
type: "texture/procedural",
code: [
"uniform float time;",
"varying vec2 surfacePosition;",
"void main( void ) {",
" vec2 sp = surfacePosition;",
" vec2 p = sp*5.0 - vec2(10.0);",
" vec2 i = p;",
" float c = 1.0;",
" float inten = 0.10;",
" for (int n = 0; n < 10; n++) {",
" float t = time * (1.0 - (3.0 / float(n+1)));",
" i = p + vec2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x));",
" c += 1.0/length(vec2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten)));",
" }",
" c /= float(10);",
" c = 1.5-sqrt(c);",
" gl_FragColor = vec4(vec3(c*c*c*c), 999.0) + vec4(0.0, 0.3, 0.5, 1.0);",
"}"
],
nodes: [{
type: "geometry/box"
}]
}
Procedural textures
In the wild: BioDigital Human
- Running Mechanics
In the wild: BIMVie.ws
- Open-source IFC model viewer
- Running on BIMServer
- https://github.com/opensourceBIM/bimvie.ws-viewer
What's next?
xeoEngine
- Game objects
- Dynamically-editable, JSON-persistable scene
- Multiple lighting models (Phong, PBR etc.)
- Still in development
- API docs (what? no way!) : xeoengine.org/docs
Because there still aren't enough WebGL engines, right? ;)
xeoEngine
var scene = new XEO.Scene();
var material = new XEO.PhongMaterial(scene, {
id: "myMaterial",
diffuse: [ 0.6, 0.6, 0.7 ],
specular: [ 1.0, 1.0, 1.0 ]
});
var geometry = new XEO.Geometry(scene, {
primitive: "triangles",
positions: [...],
normals: [...],
uvs: [...],
indices: [...]
});
var camera = new XEO.Camera(scene);
var object = new XEO.GameObject(scene, {
material: material,
geometry: geometry,
camera: camera
});
Component-object graph
- Inspired by engines like Unity and Goo Engine
material.on("diffuse",
function(value) {
console.log(
"material diffuse is now: " + value);
});
material.diffuse = [0.9, 0.9, 0.6];
Updating scene state
Register change listener
Update scene state
- Everything in a scene fires change events
- en.wikipedia.org/wiki/Open/closed_principle
xeoEngine
var texture = new XEO.Texture(scene, {
src: "myTexture.jpg"
});
material.diffuseMap = texture;
Dynamically editable scenes
Eg. create a texture and add to the material
- Designed to be editable with a graphical UI
- Also nice for live coding
xeoEngine
var json = scene.json;
var scene2 = new XEO.Scene({ json: json });
JSON persistable
Save scene to JSON
Create scene from JSON
{
className: "XEO.Scene",
components: [
{
className: "XEO.PhongMaterial",
id: "myMaterial",
diffuse: [ 0.6, 0.6, 0.7 ],
specular: [ 1.0, 1.0, 1.0 ]
},
{
className: "XEO.Geometry",
id: "c0",
primitive: "triangles",
positions: [...],
normals: [...],
uvs: [...],
indices: [...]
},
{
className: "XEO.GameObject",
material: "myMaterial",
geometry: "c0",
//..
}
]
}
xeoEngine
Danke!
Shouts out to
SceneJS and xeoEngine
By xeolabs
SceneJS and xeoEngine
SceneJS and xeoEngine - a brief intro
- 6,489