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

threejs-3d-a-weben

By Zoltán Tóth