Web Graphics of the present time,
and the near future

3c557c6103a4addc52f7b76ffd0a0f27?s=47 yomotsu
April 11, 2015

Web Graphics of the present time,
and the near future

3c557c6103a4addc52f7b76ffd0a0f27?s=128

yomotsu

April 11, 2015
Tweet

Transcript

  1. Web Graphics of the present time,
 and the near future

    Presented by Akihiro Oyamada (@yomotsu) 
 at WCAN on 11th Apr, 2015
  2. @yomotsu 小山田 晃浩

  3. Can we use these?

  4. SVG 9+ 3+ Canvas2D 9+ WebGL 11+ 8+ 8+ 37+

  5. None
  6. https://support.microsoft.com/gp/microsoft-internet-explorer

  7. Windows Vista IE 9 - Windows 7 IE 11 -

    Windows 8.1 IE 11 - Windows 10 Spartan ( IE11 )
  8. 8 → 11

  9. 1. SVG with SnapSVG 2. Canvas with EaselJS 3. WebGL

    with pixi.js and three.js 4. WebVR
  10. None
  11. http://pbskids.org/

  12. http://yourpower.panda.org/

  13. http://altspace.com/

  14. http://alkopedia.dareville.com/

  15. http://www.albinotonnina.com/

  16. Snap.svg

  17. path animation http://localhost:8000/snapsvg_1_pathAnimation.html

  18. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <button>Animate it!</button> ! <svg class="pathAnim2" width="512" height="300" viewBox="0 0 512 300"> <path d="M12.5,130c0,0,46.5-60.5,172-60.5S333,...." fill="none" stroke="#ffffff" stroke-opacity="0.5" strokeMiterLimit="10" stroke-width="4" stroke-dasharray="12, 6"
  19. ! <button>Animate it!</button> ! <svg class="pathAnim2" width="512" height="300" viewBox="0 0

    512 300"> <path d="M12.5,130c0,0,46.5-60.5,172-60.5S333,...." fill="none" stroke="#ffffff" stroke-opacity="0.5" strokeMiterLimit="10" stroke-width="4" stroke-dasharray="12, 6" stroke-dashoffset="100"/> <image xlink:href="truck.svg" width="128" height="128"> </svg> ! ! <script src="./lib/snap.svg-min.js"></script> class attribute guide path moving object
  20. ! ! <script src="./lib/snap.svg-min.js"></script> <script> ! var pathAnim = Snap(

    '.pathAnim2' ); var path = pathAnim.select( 'path' ); var truck = pathAnim.select( 'image' ); var pathLength = path.getTotalLength(); var duration = 5000; ! var playAnim = function () { ! Snap.animate( 0, 1, function( progress ) { ! var movePoint = path.getPointAtLength( pathLength * progress ); ! truck.transform( 't' + ( movePoint.x - 64 ) + ',' +
  21. var pathLength = path.getTotalLength(); var duration = 5000; ! var

    playAnim = function () { ! Snap.animate( 0, 1, function( progress ) { ! var movePoint = path.getPointAtLength( pathLength * progress ); ! truck.transform( 't' + ( movePoint.x - 64 ) + ',' + ( movePoint.y - 64 ) + 'r' + ( movePoint.alpha - 180 ) ); ! }, duration, mina.easeinout ); ! }; ! playAnim();
  22. ! playAnim(); ! var button = document.querySelector( 'button' ); button.addEventListener(

    'click', playAnim ); ! </script> ! </body> </html>
  23. morphing http://localhost:8000/snapsvg_2_morph.html

  24. None
  25. None
  26. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <svg width="128" height="128" viewBox="0 0 64 64" class="octoIcon"> ! <defs> ! <path class="default" d="M11.2,37.6c-0.1-...."/> <path class="hover" d="M7,39.8c0,0-0.1-0..."/> ! </defs> ! <path fill="#fff" class="main"/>
  27. </head> <body> ! <svg width="128" height="128" viewBox="0 0 64 64"

    class="octoIcon"> ! <defs> ! <path class="default" d="M11.2,37.6c-0.1-...."/> <path class="hover" d="M7,39.8c0,0-0.1-0..."/> ! </defs> ! <path fill="#fff" class="main"/> ! </svg> ! ! <script src="./lib/snap.svg-min.js"></script> <script> !
  28. <path fill="#fff" class="main"/> ! </svg> ! ! <script src="./lib/snap.svg-min.js"></script> <script>

    ! var icon = Snap( document.querySelector( '.octoIcon' ) ); var pathMain =icon.select('.main'); var pathDefault=icon.select('.default').attr('d'); var pathHover =icon.select(‘.hover').attr('d'); ! pathMain.attr( 'd', pathDefault ); ! icon.node.addEventListener('mouseover',function(){ ! pathMain.animate( { d: pathHover
  29. pathMain.attr( 'd', pathDefault ); ! icon.node.addEventListener('mouseover',function(){ ! pathMain.animate( { d:

    pathHover }, 500, mina.bounce ); ! }); ! icon.node.addEventListener('mouseout',function(){ ! pathMain.animate( { d: pathDefault }, 500, mina.bounce ); ! }); ! </script> !
  30. templating http://localhost:8000/snapsvg_3_graph.html

  31. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <svg class="graph" width="800" height="480" viewBox="0 0 800 480"></svg> ! ! <script src="./lib/snap.svg-min.js"></script> <script src="./lib/underscore-min.js"></script> <script> // // snapsvg ʹ΋؆୯ͳςϯϓϨʔτߏจΛαϙʔτ͍ͯ͠Δ͕ػ ೳ͸͔ͳΓগͳ͍ //
  32. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <svg class="graph" width="800" height="480" viewBox="0 0 800 480"></svg> ! ! <script src="./lib/snap.svg-min.js"></script> <script src="./lib/underscore-min.js"></script> <script> // // snapsvg ʹ΋؆୯ͳςϯϓϨʔτߏจΛαϙʔτ͍ͯ͠Δ͕ػ ೳ͸͔ͳΓগͳ͍ //
  33. } ! var template = _.template( [ '<% var gridBottom

    = ( data.cellLength.y - 1 ) * data.cellSize.height + data.cellOffset.y; %>', '<g class=“grid">', ! // grid holizontal '<% for ( var i = 0, l = data.cellLength.y; i < l; i ++ ) { %>’, ! '<% var x1 = data.cellOffset.x - 20; %>', '<% var y1 = data.cellOffset.y + data.cellSize.height * i; %>', '<% var x2 = data.cellOffset.x + data.cellSize.width * ( data.cellLength.x - 1 ); %>', '<% var y2 = y1; %>', '<line x1="<%= x1 %>" y1="<%= y1 %>" x2="<%= x2 %>" y2="<%= y2 %>" stroke="#ffffff" stroke- dasharray="6, 6" stroke-width="2"/>', '<text x="<%= x1 - 10 %>" y="<%= y1 %>" font-
  34. ].join( '\n' ) ); ! ! ! var svgSource =

    template( { data: data } ); var svgDOM = Snap.parse( svgSource ); graph.append( svgDOM ); ! ! var point = graph.selectAll( '.point' ); var points = graph.selectAll( '.points' ); var surface = graph.select( '.surface' ); ! _.each( point, function ( el ) { ! var mat1 = new Snap.Matrix(); var mat2 = new Snap.Matrix(); ! mat1.translate( +el.attr( 'data-cx1' ), +el.attr( 'data-cy1' ) );
  35. • K2VFSZͷΑ͏ͳ47(%0.ૢ࡞
 SVG DOM manipulation, like jQuery • Ξχϝʔγϣϯ
 Animations

    • ςϯϓϨʔτల։
 Templating • "KBYʹΑΔ֎෦47(ಡΈࠐΈ
 Import external SVG file with Ajax • 47(ಠࣗػೳͷαϙʔτ
 SVG features support, like masking, clipping, patterns etc...
  36. http://snapsvg.io/

  37. http://snapsvg.io/docs/

  38. + 8 Raphael.js

  39. <canvas>

  40. http://dreamplus.asia/en/

  41. http://kato-hosp.jp/

  42. http://wheel.dunlop.co.jp/simulator/2/

  43. http://martin-h.com/

  44. http://www.itsumokawaii.jp/en/

  45. None
  46. make a stage

  47. make display objects

  48. add them to the stage

  49. add them to the stage

  50. add them to the stage

  51. render the stage

  52. http://localhost:8000/easeljs_0_basic.html

  53. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <canvas width="640" height="360" id=“myCanvas"> </canvas> ! <script src=“./lib/createjs-2014.12.12.min.js"> </script> <script> ! var canvas = document.querySelector( '#myCanvas' ); var stage = new createjs.Stage( canvas ); !
  54. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <canvas width="640" height="360" id=“myCanvas"> </canvas> ! <script src=“./lib/createjs-2014.12.12.min.js"> </script> <script> ! var canvas = document.querySelector( '#myCanvas' ); var stage = new createjs.Stage( canvas ); ! make a canvas element
  55. <meta charset="utf-8"> <title>=^.^=</title> </head> <body> ! <canvas width="640" height="360" id=“myCanvas">

    </canvas> ! <script src=“./lib/createjs-2014.12.12.min.js"> </script> <script> ! var canvas = document.querySelector( '#myCanvas' ); var stage = new createjs.Stage( canvas ); ! var robot = new createjs.Bitmap( './img/ craftybot.png' ); robot.set( { x: 200, y: 100 load create.js
  56. <canvas width="640" height="360" id=“myCanvas"> </canvas> ! <script src=“./lib/createjs-2014.12.12.min.js"> </script> <script>

    ! var canvas = document.querySelector( '#myCanvas' ); var stage = new createjs.Stage( canvas ); ! var robot = new createjs.Bitmap( './img/ craftybot.png' ); robot.set( { x: 200, y: 100 } ); stage.addChild( robot ); ! var update = function() { make a stage
  57. </script> <script> ! var canvas = document.querySelector( '#myCanvas' ); var

    stage = new createjs.Stage( canvas ); ! var robot = new createjs.Bitmap( './img/ craftybot.png' ); robot.set( { x: 200, y: 100 } ); stage.addChild( robot ); ! var update = function() { ! stage.update(); ! } make a display object
  58. var canvas = document.querySelector( '#myCanvas' ); var stage = new

    createjs.Stage( canvas ); ! var robot = new createjs.Bitmap( './img/ craftybot.png' ); robot.set( { x: 200, y: 100 } ); stage.addChild( robot ); ! var update = function() { ! stage.update(); ! } ! createjs.Ticker.setFPS( 60 ); createjs.Ticker.addEventListener( 'tick', update ); add to the stage
  59. craftybot.png' ); robot.set( { x: 200, y: 100 } );

    stage.addChild( robot ); ! var update = function() { ! stage.update(); ! } ! createjs.Ticker.setFPS( 60 ); createjs.Ticker.addEventListener( 'tick', update ); </script> ! </body> </html> update to render
  60. None
  61. blend mode http://localhost:8000/easeljs_1_blend.html

  62. sprite animations http://localhost:8000/easeljs_2_sprite.html

  63. events http://localhost:8000/easeljs_3_event.html

  64. • อ࣋Ϟʔυ"1*ͷΑ͏ͳɺ
 ΦϒδΣΫτ؅ཧ
 Specific objects management, like retained mode APIs

     • 4QSJUF΍4QJOFͷΞχϝʔγϣϯ
 Sprite and Spine animations  • ϐΫηϧૢ࡞΍جຊతͳϑΟϧλʔ
 Pixel manipulation and basic filters  • Ϛ΢εͱλονΠϕϯτ
 Mouse and touch events
  65. http://www.createjs.com/#!/EaselJS

  66. http://www.createjs.com/Docs/EaselJS/modules/EaselJS.html

  67. SVG vs Canvas

  68. https://msdn.microsoft.com/en-us/library/ie/gg193983(v=vs.85).aspx#19graphicsInHtml5 canvas vs svg ύϑΥʔϚϯε

  69. None
  70. None
  71. http://archive.revolutionsinsound.com/

  72. http://www.wolverineunleashed.com/

  73. http://kaatje.ketnet.be/html/

  74. http://www.theboxtrolls.com/experience/the-cavern

  75. http://www.goodboydigital.com/runpixierun/

  76. http://localhost:8000/pixi_0_basic.html

  77. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <script src="./lib/pixi.js"></script> ! <script> var renderer=new PIXI.autoDetectRenderer(640,360); document.body.appendChild( renderer.view ); ! var stage = new PIXI.Stage( 0xffffff ); ! var robot = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 );
  78. <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> ! <script src="./lib/pixi.js"></script>

    ! <script> var renderer=new PIXI.autoDetectRenderer(640,360); document.body.appendChild( renderer.view ); ! var stage = new PIXI.Stage( 0xffffff ); ! var robot = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 ); stage.addChild( robot ); ! ( function animate() { load pixi.js
  79. <title>=^.^=</title> </head> <body> ! <script src="./lib/pixi.js"></script> ! <script> var renderer=new

    PIXI.autoDetectRenderer(640,360); document.body.appendChild( renderer.view ); ! var stage = new PIXI.Stage( 0xffffff ); ! var robot = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 ); stage.addChild( robot ); ! ( function animate() { ! requestAnimationFrame( animate ); renderer.render( stage ); make a renderer canvas
  80. ! <script src="./lib/pixi.js"></script> ! <script> var renderer=new PIXI.autoDetectRenderer(640,360); document.body.appendChild( renderer.view

    ); ! var stage = new PIXI.Stage( 0xffffff ); ! var robot = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 ); stage.addChild( robot ); ! ( function animate() { ! requestAnimationFrame( animate ); renderer.render( stage ); ! } )(); ! make a stage
  81. ! <script> var renderer=new PIXI.autoDetectRenderer(640,360); document.body.appendChild( renderer.view ); ! var

    stage = new PIXI.Stage( 0xffffff ); ! var robot = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 ); stage.addChild( robot ); ! ( function animate() { ! requestAnimationFrame( animate ); renderer.render( stage ); ! } )(); ! </script> ! make a display object
  82. document.body.appendChild( renderer.view ); ! var stage = new PIXI.Stage( 0xffffff

    ); ! var robot = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 ); stage.addChild( robot ); ! ( function animate() { ! requestAnimationFrame( animate ); renderer.render( stage ); ! } )(); ! </script> ! </body> </html> add to the stage
  83. var stage = new PIXI.Stage( 0xffffff ); ! var robot

    = new PIXI.Sprite.fromImage( './img/ craftybot.png' ); robot.position.set( 200, 100 ); stage.addChild( robot ); ! ( function animate() { ! requestAnimationFrame( animate ); renderer.render( stage ); ! } )(); ! </script> ! </body> </html> render it!
  84. None
  85. blend mode http://localhost:8000/pixi_1_blend.html

  86. sprite animations http://localhost:8000/pixi_2_sprite.html

  87. events http://localhost:8000/pixi_3_event.html

  88. shaders http://localhost:8000/pixi_4_shader.html

  89. custom shaders http://localhost:8000/pixi_5_shader2.html

  90. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> !

    <script src="./lib/pixi.js"></script> ! <script> ! var MyFilter = ( function () { ! var MyFilter = function() { ! PIXI.AbstractFilter.call( this ); ! this.passes = [ this ]; !
  91. ! var MyFilter = ( function () { ! var

    MyFilter = function() { ! PIXI.AbstractFilter.call( this ); ! this.passes = [ this ]; ! // types // '1f': scalar // '2f': vec2 // '3f': vec3 // '4f': vec4 // 'mat4': mat4 this.uniforms = { size: { type: '1f', value:0.01 } }; ! // http://www.html5gamedevs.com/topic/10585-list- of-available-filter-shader-uniforms/ extend Filter class
  92. // http://wp.applesandoranges.eu/?p=14 this.fragmentSrc = [ ! 'precision mediump float;', 'varying

    vec2 vTextureCoord;', 'varying vec4 vColor;', 'uniform sampler2D uSampler;', ! 'uniform float size;', ! 'void main( void ) {', ! 'vec4 sum = vec4( 0 );', ! 'for ( int i = -4; i < 4; i ++ ) {', ! 'for( int j = -4; j < 4; j++ ){', ! 'sum += texture2D( uSampler, vTextureCoord + vec2( j, i ) * size ) * 0.05;', ! '}', write your 
 fragment
 shader
  93. 'if ( alpha > 0.8 ) {', ! 'gl_FragColor =

    texColor;', ! '} else {', ! 'gl_FragColor = sum;', ! '}', ! '}' ! ]; ! }; ! MyFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); ! return MyFilter; ! } )();
  94. • &BTFM+4ͱΑ͘ࣅͨ"1*
 Very similar APIs to EaselJS  • 8FC(-Λར༻ͨ͠ߴ଎ॲཧ


    High speed pixel manipulation with WebGL  • ಠࣗγΣʔμʔͷ௥Ճ
 Custom shaders
  95. http://www.pixijs.com/

  96. http://www.goodboydigital.com/pixijs/docs/

  97. http://www.html5gamedevs.com/forum/15-pixijs/

  98. three.js

  99. http://www.apple.com/macbook/design/

  100. http://gravitymovie.warnerbros.com/#/home

  101. https://www.ana-flightconnections.com/

  102. http://fr.special-t.com/media/ogreen/en/

  103. https://yomotsu.github.io/walkthrough

  104. make a scene

  105. make a camera

  106. add a light

  107. add an object

  108. http://localhost:8000/threejs_0_basic.html

  109. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>=^.^=</title> </head> <body> <script

    src="./lib/three.min.js"></script> <script> var width = window.innerWidth, height = window.innerHeight; ! var scene = new THREE.Scene(); ! var camera = new THREE.PerspectiveCamera( 40, width / height, 1, 1000 ); camera.position.set( 0, 0, 3 ); ! var renderer = new
  110. var width = window.innerWidth, height = window.innerHeight; ! var scene

    = new THREE.Scene(); ! var camera = new THREE.PerspectiveCamera( 40, width / height, 1, 1000 ); camera.position.set( 0, 0, 3 ); ! var renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setSize( width, height ); document.body.appendChild( renderer.domElement ); ! var directionalLight = new THREE.DirectionalLight( 0xffffff ); directionalLight.position.set( 0, 1, 1 ).normalize(); scene.add( directionalLight ); ! var box = new THREE.Mesh(
  111. THREE.WebGLRenderer( { antialias: true } ); renderer.setSize( width, height );

    document.body.appendChild( renderer.domElement ); ! var directionalLight = new THREE.DirectionalLight( 0xffffff ); directionalLight.position.set( 0, 1, 1 ).normalize(); scene.add( directionalLight ); ! var box = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshPhongMaterial( { color: 0xff0000 } ) ); scene.add( box ); ! ( function renderLoop () { ! requestAnimationFrame( renderLoop ); box.rotation.y += 0.01;
  112. directionalLight.position.set( 0, 1, 1 ).normalize(); scene.add( directionalLight ); ! var

    box = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshPhongMaterial( { color: 0xff0000 } ) ); scene.add( box ); ! ( function renderLoop () { ! requestAnimationFrame( renderLoop ); box.rotation.y += 0.01; renderer.render( scene, camera ); ! } )(); </script> ! </body>
  113. new THREE.MeshPhongMaterial( { color: 0xff0000 } ) ); scene.add( box

    ); ! ( function renderLoop () { ! requestAnimationFrame( renderLoop ); box.rotation.y += 0.01; renderer.render( scene, camera ); ! } )(); </script> ! </body> </html>
  114. 3D Models http://localhost:8000/threejs_1_3dmodel.html

  115. skeletal animation http://localhost:8000/threejs_2_bone.html

  116. events http://localhost:8000/threejs_3_event.html

  117. None
  118. custom shader http://localhost:8000/threejs_4_shader.html

  119. None
  120. http://threejs.org/

  121. http://threejs.org/docs/

  122. • %ϞσϧಡΈࠐΈ
 Import 3D models  • Ξχϝʔγϣϯ
 Animations 

    • ܭࢉܥͷػೳ ϕΫτϧɺߦྻͳͲ 
 Math functions, like vector, matrix • ಠࣗγΣʔμʔͷ௥Ճ
 Custom shaders Post process, Debugging WebGL, Rapid update,  BOENPSF
  123. WebVR

  124. https://www.youtube.com/watch?v=pMrhaLb6UeQ

  125. d = navigator.
 getVRDevices()

  126. • d[ i ].VRDevice (Type of the device) • d[

    i ].VREyeParameters • FOV • eyeTranslation • d[ i ].VRPositionState • position • velocity • orientation • angularVelocity • othres… d = navigator.
 getVRDevices()
  127. vrHMD.getEyeTranslation( ‘left' ); vrHMD.getEyeTranslation( 'right' ); vrHMD.getRecommendedEyeFieldOfView( 'left' ); vrHMD.getRecommendedEyeFieldOfView(

    'right' );
  128. Chromium WebVR Builds Firefox Nightly Builds WebVR Oculus Rift Enabler

    as of Apr, 2015
  129. https://www.youtube.com/watch?v=cBvCS78ZC1c

  130. Virtuix Omni Locomotion HMD Cyberith Virtualizer OCULUS Rift SONY Morpheus

    HTC Vine • Leap Motion • PrioVR • Control VR • Sixense Stem • Razer Hydra Others
  131. https://www.youtube.com/watch?v=aTtfAQEeAJI

  132. Drop-in Phone
 Viewers

  133. Drop-in Phone
 Viewers • Different APIs
 (use DeviceOrientation API instead)

    • Limited performance
 (stereo rendering on mobile device)
  134. None
  135. None
  136. for more info,
 visit http://webvr.info/

  137. Conclusion

  138. ύϥϥοΫεޮՌ͸
 ΋͸΍લ࣌୅ Parallax Effects are no longer cool

  139. 47(΍$BOWBTΛ
 ࢖ͬͯΈΑ͏ Time to start using SVG and Canvas

  140. 47(ʹ͸4OBQ47(
 $BOWBTʹ͸&BTFM+4 SnapSVG for SVG, EaselJS for Canvas

  141. 8FC(-͸͞Βʹύϫϑϧʂ
 QJYJKT΍UISFFKTΛ࢖͓͏ WebGL is more powerful! Use pixi.js and three.js

  142. 8FC73͕Մೳʹ͢Δ8FCͰͷ
 όʔνϟϧɾϦΞϦςΟʔ WebVR Brings Virtual Reality to the Web

  143. Thanks! @yomotsu