-
Notifications
You must be signed in to change notification settings - Fork 6
Tutorial 1. Hello scene
We can't render anything without an HTML page to put it in. The renderer will require a canvas as a target, which we'll drop in there too. For all the documentation, we'll use this HTML template:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Helix tutorial 1</title>
<script src="helix.js"></script>
<style>
body {
background-color: black;
color: gainsboro;
margin: 0;
}
#webglContainer {
width: 100%;
height: 100%;
position: absolute;
border: none;
}
</style>
</head>
<body>
<canvas id="webglContainer">
Canvas tag not supported by the browser!
</canvas>
<script src="script.js"></script>
</body>
</html>
To get started from scratch, we'll create a script.js file containing, all the things we need. Add some global variables:
var canvas;
var renderer;
var camera;
var scene;
I know, global variables are an affront to the pope and his cat, but it's just to show how things work. You can write clean code on your own time. Next up: initializing the engine.
window.onload = function()
{
canvas = document.getElementById('webglContainer');
HX.init(canvas);
scene = new HX.Scene();
camera = new HX.PerspectiveCamera();
renderer = new HX.Renderer();
scene.attach(camera);
initScene();
HX.onFrame.bind(update);
}
function initScene()
{
// we'll put some stuff here later
}
function update(dt)
{
renderer.render(camera, scene, dt);
}
window.onresize = function()
{
var dpr = window.devicePixelRatio || 1;
var canvas = document.getElementById('webglContainer');
canvas.width = canvas.clientWidth * dpr;
canvas.height = canvas.clientHeight * dpr;
};
This will create a Scene, which will contain all our 3D objects, a perspective camera through which we'll look at the scene while rendering, and the Renderer which will take care of putting all your hard work on the screen.
The last line in the onload function is what's called "binding to a Signal". A Signal is Helix's way of broadcasting events, because let's face it, JavaScript Events are horrible. Every time a Signal is "dispatched", the bound functions will be called. The HX.onFrame Signal gets dispatched whenever a frame needs to be updated and drawn. It also passes in the amount of milliseconds passed since last frame, so we can update time-based animations accordingly.
(Note: a Signal can also accept a second "this" parameter, which will allow you to bind class methods without losing scope).
Finally, the onresize code is some boilerplate to assure the canvas contents resizes along with its DOM element, taken into account the device's screen to logical pixel ratio.
If you run this, Helix will initialize and render every frame. Nothing will obviously be visible because there's nothing to render yet!
To get something rendered, we need to add things to the Scene. The Scene is the root of the scene graph (ie: it's the object that contains the entire hierarchy of 3D objects: models, cameras, lights, containers ...). Renderable objects consist of four aspects, each represented by their own classes:
- The mesh: a triangle mesh that form up the geometric shape of the object. This is represented by the
HX.Meshclass and subclasses defining primitives. - The material: this defines how the mesh is rendered; for now let's just limit ourselves to the fact that it defines the object's reflective parameters. Represented by the class
HX.Materialand subclasses such asHX.BasicMaterial. - The mesh instance (
HX.MeshInstance): this links a mesh and a material. It's a Component that needs to be added to the Entity. - The entity: This defines the place and orientation of the object in the 3D world. By itself, an Entity doesn't do much, but it's defined by the components added to it (in this case
HX.MeshInstancemakes it a renderable).
Multiple MeshInstance objects can share a single mesh and/or material. Since meshes and materials and the textures they use take up most memory in a project, this can save a lot. Just think of creating that army of Fonzie clones you've always wanted!
Helix provides some basic meshes in the form of primitives: simple common shapes such as spheres, boxes, cylinders, ... Filling in the project initScene function, this creates a sphere with radius 0.25 and adds it to the scene:
function initScene()
{
var material = new HX.BasicMaterial();
material.color = 0xff0000;
var primitive = new HX.SpherePrimitive(
{
radius:.25
});
var meshInstance = new HX.MeshInstance(primitive, material);
var entity = new HX.Entity(meshInstance);
scene.attach(entity);
};
HX.BasicMaterial is Helix's default material and should provide all the most common functionality a basic material can offer (including changing reflectivity, texturing, transparency, refraction, emission, etc).
Creating a new HX.SpherePrimitive will a create a HX.Mesh object with a sphere mesh inside which we can attach to the scene for rendering.
Run it, and be amazed with your beautiful red unshaded sphere! The gods shall be appeased.