Nikola Brežnjak blog - Tackling software development with a dose of humor
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Home
Daily Thoughts
Ionic
Stack Overflow
Books
About me
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Nikola Brežnjak blog - Tackling software development with a dose of humor
Miscellaneou$

100th post

Nothing, just saying 🙂

Ok, jokes aside, this has been a nice journey for me. It all started with the post Carcassonne scoring board application which I decided to post after reading James Clear’s post on why we should make things.

Top 10  popular posts until now:

  • How to get started on the MEAN stack (written for HackHands.com and featured in NodeWeekly)
  • Delving into Node.js and Express web framework (written for HackHands.com)
  • MEAN.io VS MEAN.js and deploying the latter on DigitalOcean (written for HackHands.com)
  • Deploying MongoDB and Node.js application on OpenShift (written for CodeProject.com)
  • How I built my own testable The Answer To Life The Universe And Everything npm module (written for CodeProject.com)
  • Build a font viewer application in WPF without writing any C# code (written for CodeProject.com)
  • Using CasperJS on Webfaction to automatically send emails with attached images via Gmail (written for CodeProject.com)
  • How to delete node_modules folder on Windows machine
  • Enable continuous scrolling by default in Adobe Reader
  • Git push origin master could not read username for http://github.com

 

Programming

Notes from the book Game development with Three.js by Isaac Sukin

My notes from the book Game development with Three.js by Isaac Sukin:

Three.js is usually used with a new technology called WebGL, a JavaScript API for rendering graphics without plugins. The API is based on OpenGL, a desktop graphics API (GL stands for graphics library).

Because it uses the client’s graphics processing unit to accelerate rendering, WebGL is fast! However, many mobile browsers as well as Internet Explorer 10 and below do not support WebGL. Luckily, Three.js supports rendering with the HTML5 Canvas API as well as other technologies such as Scalable Vector Graphics instead.

<!DOCTYPE html>
<html>
	<head>
		<script src="http://cdnjs.cloudflare.com/ajax/libs/three.js/r57/three.min.js"></script>
	</head>
	<body>
		
		<script>
			var camera, scene, renderer;
			var geometry, material, mesh;

			var init = function () {

				renderer = new THREE.CanvasRenderer();
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.body.appendChild( renderer.domElement );

				camera = new THREE.PerspectiveCamera( 95, window.innerWidth / window.innerHeight, 1, 5000 );
				camera.position.z = 900;

				scene = new THREE.Scene();

				geometry = new THREE.CubeGeometry( 100, 100, 100 );
				material = new THREE.MeshNormalMaterial( { color: 0x000000, wireframe: true, wireframeLinewidth: 2 } );

				mesh = new THREE.Mesh( geometry, material );
				scene.add( mesh );
			}

			var animate = function () {

				requestAnimationFrame( animate );

				mesh.rotation.x = Date.now() * 0.001;
				mesh.rotation.y = Date.now() * 0.001;

				renderer.render( scene, camera );

			}

			init();
			animate();
		</script>
	</body>
</html>

The renderer creates a new <canvas> element by default that should be added to the DOM. Avoid changing the canvas’ size with CSS; use the renderer’s setSize method instead, which sets the width and height HTML attributes on the canvas element.

This is because CSS describes the display size but not the render size. That is, if the canvas is rendered at 800 x 600, but the CSS shows it at 1024 x 768, the rendering will be stretched to fill the space just like if you specified the CSS size of an image to be larger than its true size. This can result in distortion and difficulty converting between “screen space” and “canvas space.”

The one last thing we need is a camera object as shown in the following code snippet, which is something Three.js uses to tell the renderer from what perspective the scene should be displayed. If the player was standing in your virtual world and their screen represented what they could see, camera would be their eyes, renderer would be their brain, and scene would be their universe.

All objects are initialized at the position (0, 0, 0), also called the origin. The key here is requestAnimationFrame(), which executes the function passed to it when the browser is ready to paint a new frame. Geometries are instances of THREE.Geometry that define the shape of an object in a scene. They are made up of vertices and faces (which are themselves objects and are accessible through the vertices and faces array properties). Vertices are the THREE.Vector3 objects representing points in three-dimensional space, while faces are the THREE.Face3 objects representing triangular surfaces.

Triangle:

var geo = new THREE.Geometry();
geo.vertices = [
    new THREE.Vector3(0, 0, 0),
    new THREE.Vector3(0, 100, 0),
    new THREE.Vector3(0, 0, 100)
];

geo.faces.push(new THREE.Face3(0, 1, 2));
geo.computeBoundingSphere();

3D:

THREE.Sphere(radius, horizontalSegments = 8, verticalSegments = 6)

THREE.Icosahedron(radius, detail = 0);
THREE.Octahedron(radius, detail = 0);
THREE.Tetrahedron(radius, detail = 0);

THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments = 8, heightSegments = 1, openEnded= false)

THREE.TorusGeometry(radius, tubeWidth = 40, radialSegments = 8, tubularSegments = 6)

THREE.TorusKnotGeometry(radius, tubeWidth = 40, radialSegments, tubularSegments, p = 2, q = 3, heightScale = 1)

2D:

Plane THREE.PlaneGeometry(width, height, widthSegments = 1, heightSegments = 1)

Circle THREE.CircleGeometry(radius, numberOfSides = 8)

Ring THREE.RingGeometry(innerRadius, outerRadius, radialSegments = 8, ringSegments = 8)

Extruding:

var triangle = new THREE.Shape([
new THREE.Vector2 (0, 50),
new THREE.Vector2 (50, 50),
new THREE.Vector2 (50, 0)
]);
var geometry = new THREE.ExtrudeGeometry(triangle, {
bevelEnabled: false,
amount: 30
});

Custom fonts must be in the typeface.js format (you can convert OpenType and TrueType fonts to Typeface format at http://typeface.neocracy.org/fonts.html). Use the following code to create text geometry:

new THREE.TextGeometry("Text message goes here", {
    size: 30,
    height: 20, // extrude thickness
    font: "helvetiker", // font family in lower case
    weight: "normal", // or e.g. bold
    style: "normal", // or e.g. italics
    bevelEnabled: false
});

Procedural city:

var camera, scene, renderer;

function setup() {
    document.body.style.backgroundColor = '#d7f0f7';
    setupThreeJS();
    setupWorld();
    requestAnimationFrame(function animate() {
        renderer.render(scene, camera);
        requestAnimationFrame(animate);
    });
}

function setupThreeJS() {
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.y = 400;
    camera.position.z = 400;
    camera.rotation.x = -45 * Math.PI / 180;
    renderer = new THREE.CanvasRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
}

function setupWorld() {
    // Floor
    var geo = new THREE.PlaneGeometry(2000, 2000, 20, 20);
    var mat = new THREE.MeshBasicMaterial({color: 0x9db3b5, overdraw:true});
    var floor = new THREE.Mesh(geo, mat);
    floor.rotation.x = -90 * Math.PI / 180;
    scene.add(floor);
    // Original building
    var geometry = new THREE.CubeGeometry(1, 1, 1);
    geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0.5,0));

    var material = new THREE.MeshDepthMaterial({overdraw: true});
    // Cloned buildings
    for (var i = 0; i < 300; i++) {
        var building = new THREE.Mesh(geometry.clone(), material.clone());
        building.position.x = Math.floor(Math.random() * 200 - 100) * 4;
        building.position.z = Math.floor(Math.random() * 200 - 100) * 4;
        building.scale.x = Math.random() * 50 + 10;
        building.scale.y = Math.random() * building.scale.x * 8 + 8;
        building.scale.z = building.scale.x;
        scene.add(building);
    }
}

// Run it!
setup();

Fog:

scene.fog = new THREE.FogExp2(0x9db3b5, 0.002);

Only the DirectionalLight and PointLight objects can cast shadows. Casting shadows first requires that we enable shadows on the renderer:

renderer.shadowMapEnabled = true;

For our city scene, we’ll enable shadow receiving for our floor and both casting and receiving for our buildings:

floor.receiveShadow = true;
city.castShadow = true;
city.receiveShadow = true;

Finally, we configure our DirectionalLight object to use shadows:

light.castShadow = true;
light.shadowDarkness = 0.5;
light.shadowMapWidth = 2048;
light.shadowMapHeight = 2048;
light.position.set(500, 1500, 1000);
light.shadowCameraFar = 2500;

// DirectionalLight only; not necessary for PointLight
light.shadowCameraLeft = -1000;
light.shadowCameraRight = 1000;
light.shadowCameraTop = 1000;
light.shadowCameraBottom = -1000;

Earlier, we switched from CanvasRenderer to WebGLRenderer in order to support shadows and fog. As a rule of thumb, WebGLRenderer is faster and has the most features, while CanvasRenderer has fewer features but broader browser support. One particularly nice feature of WebGLRenderer is that it supports antialiasing to smooth out jagged edges. We can enable this for our cityscape by passing the option in to the renderer constructor:

renderer = new THREE.WebGLRenderer({antialias: true});

Already written navigation from examples:

<script src="FirstPersonControls.js"></script>

Add timer:

clock = new THREE.Clock();
controls = new THREE.FirstPersonControls(camera);
controls.movementSpeed = 100;
controls.lookSpeed = 0.1;

Add this to requestAnimationFrame:

controls.update(clock.getDelta());

Clicking on the screen in order to select or interact with something is a common requirement, but it’s somewhat harder than it sounds because of the need to project the location of the click in the 2D plane of your screen into the 3D world of Three.js. To do this, we draw an imaginary line, called a ray, from the camera toward the position where the mouse might be in 3D space and see if it intersects with anything. In order to project, we first need a projector:

projector = new THREE.Projector();

Then we need to register a listener on the click event for the canvas:

renderer.domElement.addEventListener('mousedown', function(event) {
var vector = new THREE.Vector3(
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) /
this.width * 2 - 1,
-renderer.devicePixelRatio * (event.pageY - this.offsetTop) /
this.height * 2 + 1,
0
);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(
camera.position,
vector.sub(camera.position).normalize()
);
var intersects = raycaster.intersectObjects(OBJECTS);
if (intersects.length) {
// intersects[0] describes the clicked object
}
}, false);

The last thing you want when your player is clicking madly to shoot at enemies is for the whole screen to suddenly turn blue because the browser thinks the user is trying to select something. To avoid this, you can either cancel the select event in JavaScript with document.

onselectstart = function() { return false; }

or disable it in CSS:

* {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

Colission libraries:

  • Ammo.js is a large but complete library compiled to JavaScript from C++. It is available at https://github.com/kripken/ammo.js/
  • Cannon.js is a smaller library written from scratch in JavaScript and inspired in part by concepts from Three.js. It is available at https://github.com/schteppe/cannon.js
  • Physi.js is a bridge between Ammo or Cannon and Three.js that also runs the physics simulation in a separate thread to avoid blocking the rendering. It is available at https://github.com/chandlerprall/Physijs

Well, tbh, stopped at page 61/100 as the examples from the book didn’t quite work for me so all in all very disappointed with the book in that department. But, as far as the writing and explanations up till this point go I think it was good. Grade: 2.7/5  

Books

Legion: Skin deep – Brandon Sanderson

My favourite quotes from the book Legion: Skin deep by Brandon Sanderson:

Always tell your captives they have more time than they do. It makes them relaxed. Sets them to planning instead of trying to break out immediately. The last thing you want to do is to make them desperate, since desperate people are unpredictable.

Anything that is possible is actually a reality given infinity.

Recent posts

  • Discipline is also a talent
  • Play for the fun of it
  • The importance of failing
  • A fresh start
  • Perseverance

Categories

  • Android (3)
  • Books (114)
    • Programming (22)
  • CodeProject (35)
  • Daily Thoughts (77)
  • Go (3)
  • iOS (5)
  • JavaScript (127)
    • Angular (4)
    • Angular 2 (3)
    • Ionic (61)
    • Ionic2 (2)
    • Ionic3 (8)
    • MEAN (3)
    • NodeJS (27)
    • Phaser (1)
    • React (1)
    • Three.js (1)
    • Vue.js (2)
  • Leadership (1)
  • Meetups (8)
  • Miscellaneou$ (77)
    • Breaking News (8)
    • CodeSchool (2)
    • Hacker Games (3)
    • Pluralsight (7)
    • Projects (2)
    • Sublime Text (2)
  • PHP (6)
  • Quick tips (40)
  • Servers (8)
    • Heroku (1)
    • Linux (3)
  • Stack Overflow (81)
  • Unity3D (9)
  • Windows (8)
    • C# (2)
    • WPF (3)
  • Wordpress (2)

"There's no short-term solution for a long-term result." ~ Greg Plitt

"Everything around you that you call life was made up by people that were no smarter than you." ~ S. Jobs

"Hard work beats talent when talent doesn't work hard." ~ Tim Notke

© since 2016 - Nikola Brežnjak