Tóth Zoltán @totya24
A KEZDETEK
1994 : VRML 1.0
Virtual Reality Markup Language
- szöveges leíró fájl (.wrl)
- nem volt natív böngészőtámogatás
- JAVA alapú pluginek
- korlátozott lehetőségek
#VRML V1.0 ascii
DirectionalLight {
direction 0 0 -1
}
PerspectiveCamera {
position -8.6 2.1 5.6
orientation -0.1 -0.9 -0.1 1.1
focalDistance 10.84
}
Separator {
Material {
diffuseColor 0 0 1
}
Transform {
translation -2.4 .2 1
rotation 0 1 1 .9
}
Cube {}
}
A KEZDETEK
1997 : VRML 2.0 (VRML97)
Virtual Reality Modeling Language
- utf-8
- teljesítményoptimalizálás
- bővíthetőség
- még mindig nincs natív támogatás
- 3D editorok ma is használt fájlformátuma
A KEZDETEK
2004 : X3D
- a VRML 2.0 utódja
- XML alapú leíró nyelv
- még ma is fejlesztik (Web3D Konzorcium)
- támogatják az ismertebb szerkesztők
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.2//EN" "http://www.web3d.org/specifications/x3d-3.2.dtd">
<X3D profile="Interchange" version="3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance"
xsd:noNamespaceSchemaLocation="http://www.web3d.org/specifications/x3d-3.2.xsd">
<Scene>
<Shape>
<IndexedFaceSet coordIndex="0 1 2">
<Coordinate point="0 0 0 1 0 0 0.5 1 0"/>
</IndexedFaceSet>
</Shape>
</Scene>
</X3D>
2011 - WebGL
- JavaScript API
- HTML5 canvas
- Nem igényel fordítást
- A JavaScript memóriakezelését használja
- Közel 90%-os támogatottság
- Eléri az operációs rendszer OpenGL driverét
- A GPU-t is használja a CPU mellett
GYAKORLATI PÉLDA
GLSL*
CSAK EGY KOCKA
GLSL*
var cube = [
// Front face
0, 0, 0,
0, 1, 0,
1, 1, 0,
1, 0, 0,
// Back face
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
// Top face
0, 1, 0,
0, 1, 1,
1, 1, 1,
1, 1, 0,
// Bottom face
0, 0, 0,
1, 0, 0,
1, 0, 1,
0, 0, 1,
// Right face
1, 0, 0,
1, 1, 0,
1, 1, 1,
1, 0, 1,
// Left face
0, 0, 0,
0, 0, 1,
0, 1, 1,
0, 1, 0
];
HOGY IS NÉZ EZ KI?
GLSL*
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*============ Defining and storing the geometry =========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== Shaders =========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/* ====== Associating attributes to vertex shader =====*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ;
// Position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// Color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*==================== MATRIX =====================*/
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
// translating z
view_matrix[14] = view_matrix[14]-6;//zoom
/*==================== Rotation ====================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1]=c*m[1]+s*mv0;
m[5]=c*m[5]+s*mv4;
m[9]=c*m[9]+s*mv8;
}
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*================= Drawing ===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.005);//time
rotateY(mov_matrix, dt*0.002);
rotateX(mov_matrix, dt*0.003);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
MI IS TÖRTÉNT?
GLSL*
- WebGL inicializálása
- A megjelenítendő objektum paraméterei JavaScript tömbbe
- Bufferobjektumok létrehozása és összekötése
- Shaderek definiálása, bekötése
- Shader attribútumok beállítása
- Transzformációs mátrix generálása
- Forgatás megvalósítása
- Kirajzolás
KERETRENDSZEREK
GLSL*
*https://en.wikipedia.org/wiki/List_of_WebGL_frameworks
3D-S OBJEKTUM
GLSL*
-
vertex
-
edge
-
face
-
geometry
-
mesh
-
material
3D-S TÉR
GLSL*
-
mesh
-
scene
-
camera
-
light
FELÉPÍTÉS (THREE.JS)
THREE.JS
- 2010-ben kezdték fejleszteni
- ma már a 82 stabil kiadásnál jár
- többféle renderelő motor (WebGL, Canvas, SVG)
- nem tipikusan játékok fejlesztésére akarták
- számos bővítmény
- rengeteg beépített objektum,
kamera, fényforrás, anyag - shaderek
- loaderek (JSON, obj, stb)
- részletes dokumentáció
- könnyen tanulható
- debug eszközök
EMLÉKEZTETŐÜL
GLSL*
THREE.JS MEGOLDÁS
<!DOCTYPE html>
<html>
<body>
<script src="three.min.js"></script>
<script>
var camera, scene, renderer, geometry, material, mesh;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
geometry = new THREE.BoxGeometry( 200, 200, 200 );
for (var i = 0; i < Math.floor(geometry.faces.length / 2); i++) {
var color = Math.random() * 0xffffff;
geometry.faces[ i*2 ].color.setHex( color );
geometry.faces[ i*2+1 ].color.setHex( color );
}
geometry.colorsNeedUpdate = true;
material = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors :THREE.FaceColors } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.04;
mesh.rotation.y += 0.05;
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
*http://codepen.io/totya24/pen/oYwWNL
A FONTOSABB RÉSZEK
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( fov, aspectRatio, near, far );
geometry = new THREE.BoxGeometry( 200, 200, 200 );
material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ););
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
function animate() {
requestAnimationFrame( animate );
mesh.rotation.y += 0.05;
renderer.render( scene, camera );
}
animate();
THREE.JS A WEBEN
THREE.JS A WEBEN
- Könnyen integrálható (HTML5 canvas)
- Canvas 2D fallback
- Futásidőben módosítható
- "One Page" oldalak
- Dinamikus hátterek
- Renderelt headerek
- Képgalériák
- Loaderek
- 3D model webshopok
- Adatvizualizáció
- Mini játékok
- Codepen ;)
THREE.JS A WEBEN
Pöttyös McFlurry
minijáték
- reszponzív
- touch kompatibilis
- több, mint ezer játékos
- < 2% canvas 2D
- optimális sebesség
(a visszajelzések szerint)
- blogposzt: goo.gl/ygS7HG
THREE.JS A WEBEN
"One Page" sites, hátterek
http://www.stedesign.com/
THREE.JS A WEBEN
Adatvizualizáció
http://armsglobe.chromeexperiments.com/
LOW-POLY JÁTÉKOK
http://codepen.io/Yakudoo/full/YGxYZj/
LOW-POLY JÁTÉKOK
http://tympanus.net/codrops/2016/04/26/the-aviator-animating-basic-3d-scene-threejs/
HA MÁR JÁTÉKOK
THREEx
- fizika
- ütközések kezelése
- loaderek
- vezérlés
- effektek
- stb.
http://www.threejsgames.com/
JÁTÉKOK
HEXGL
GL QUAKE
Hello Racer
Waste Water
EXPERIMENTS
https://workshop.chromeexperiments.com/
THREE.JS VR
https://vr.chromeexperiments.com/
A Google is three.js-t használ a hivatalos példakódjában!
THREEJS INSPECTOR
VÉGEZETÜL
- Könnyű erőforrászabáló kódot írni
- Fontos az optimalizálás
- Frissítsd fel a matektudásod :)
- Sok-sok példa és snippet + stackoverflow
- 1-2 óra alatt látványos dolgot lehet produkálni
- Fejlesztés & tanulás & élvezet
KÖSZÖNÖM A FIGYELMET!
slides: goo.gl/u7sccm
twitter: @totya24
web: blog.fps.hu