aboutsummaryrefslogtreecommitdiff
path: root/files/fi/web/api/webvr_api/using_the_webvr_api
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:41:45 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:41:45 -0500
commit1109132f09d75da9a28b649c7677bb6ce07c40c0 (patch)
tree0dd8b084480983cf9f9680e8aedb92782a921b13 /files/fi/web/api/webvr_api/using_the_webvr_api
parent4b1a9203c547c019fc5398082ae19a3f3d4c3efe (diff)
downloadtranslated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.tar.gz
translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.tar.bz2
translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.zip
initial commit
Diffstat (limited to 'files/fi/web/api/webvr_api/using_the_webvr_api')
-rw-r--r--files/fi/web/api/webvr_api/using_the_webvr_api/index.html438
1 files changed, 438 insertions, 0 deletions
diff --git a/files/fi/web/api/webvr_api/using_the_webvr_api/index.html b/files/fi/web/api/webvr_api/using_the_webvr_api/index.html
new file mode 100644
index 0000000000..b4cf17e315
--- /dev/null
+++ b/files/fi/web/api/webvr_api/using_the_webvr_api/index.html
@@ -0,0 +1,438 @@
+---
+title: Using the WebVR API
+slug: Web/API/WebVR_API/Using_the_WebVR_API
+translation_of: Web/API/WebVR_API/Using_the_WebVR_API
+---
+<div>{{APIRef("WebVR API")}}</div>
+
+<p class="summary">WebVR API on hieno lisä webkehittäjän työkaluihin. Sen avulla WebGL- näkymä (scene) voidaan esittää Oculus Riftin and HTC Viven tapaisissa VR-näytöissä. Mutta miten pääset alkuun VR appsien tekemiseen webbiin? Tämä juttu opastaa sinut perusteisiin.</p>
+
+<div class="note">
+<p><strong>Huom</strong>: WebVR APIn vakain versio — 1.1 — on vasta implementoitu Firefox 55:een (Windowsin release-versio, Mac OS X :ssa vain 'Nightly'), ja sen saa myös Chrome:en käytettäessä Google Daydream -laitteistoa. Speksistä on myös tuoreempi versio — 2.0 — mutta se on kovin keskeneräinen. Lisätietoja viimeisimmästä speksistä löytyy linkistä <a href="https://w3c.github.io/webvr/">WebVR Spec Version List</a>.</p>
+</div>
+
+<h2 id="Aloitus">Aloitus</h2>
+
+<p>Päästäksesi alkuun tarvitset:</p>
+
+<ul>
+ <li>Tuetun VR-laitteiston.
+ <ul>
+ <li>halvin vaihtoehto on mobiililaite, tuettu selain, ja silmikkonäyttö, johon mobiililaitteen saa asetettua (esim. Google Cardboard). Tämä ei vastaa käyttökokemukseltaan aivan tarkoitukseen suunniteltua laitteistoa, mutta selviät ostamatta teho-PC:tä tai erityistä VR-näyttöä.</li>
+ <li>VR-laitteisto saattaa olla hinnakas, mutta sillä saadaan parempi käyttökokemus. Parhaiten WebVR-yhteensopivia laitteita ovat tällä hetkellä HTC VIVE ja The Oculus Rift. <a href="https://webvr.info/">webvr.info</a> :n etusivulla on lisätietoa laitteiden tarjonnasta ja selaintuesta niille.</li>
+ </ul>
+ </li>
+ <li>Mahdollisesti vaaditun riittävän tehokkaan tetokoneen VR-näkymien prosessointiin ja näyttämiseen VR-laitteistollesi. Koneen speksejä varten tutki sen VR-laitteiston vaatimuksia (e.g. <a href="https://www.vive.com/us/ready/">VIVE READY Computers</a>), jonka aiot hankkia.</li>
+ <li>Tuettu selain tulee olla asennettu — uusin <a href="https://www.mozilla.org/en-US/firefox/channel/desktop/">Firefox Nightly</a> tai <a href="https://www.google.com/chrome/index.html">Chrome</a> ovat parhaat vaihtoehdot tällä hetkellä, PC:lle tai mobiiliin.</li>
+</ul>
+
+<p>Kun laitteisto ja ohjelmistot on asennettu, voit testata, toimiiko kokoonpanosi WebVR:n kanssa tästä linkistä - <a href="https://mdn.github.io/webvr-tests/aframe-demo/">simple A-Frame demo</a>, ja näet, saadaanko näkymä näkyviin ja pääsetkö VR-moodiin oikean alareunan painikkeella.</p>
+
+<p><a href="https://aframe.io/">A-Frame</a> on paras vaihtoehto päästä tekemään nopeasti WebVR-yhteensopivia 3D-näkymiä, ilman että tarvitsee ymmärtää rivikaupalla uutta JavaScript -koodia. Se ei kuitenkaan opeta, kuinka raaka WebVR API toimii ja siihen paneudummekin seuraavaksi.</p>
+
+<h2 id="Demon_esittely">Demon esittely</h2>
+
+<p>WebVR API :n toiminnan esdittelemiseksi tutustumme puhtaasti webgl:ää sisältävään esimerkkiimme, joka näyttää vähän tältä:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15121/Capture1.png" style="display: block; height: 761px; margin: 0px auto; width: 1341px;"></p>
+
+<div class="note">
+<p><strong>Huom</strong>: Demon lähdekoodi - <a href="https://github.com/mdn/webvr-tests/tree/master/raw-webgl-example">source code</a> - löytyy GitHubista ja livelinkki siihen on tässä: <a href="https://mdn.github.io/webvr-tests/raw-webgl-example/">view it live</a>.</p>
+</div>
+
+<div class="note">
+<p><strong>Huom</strong>: Ellei WebVR ei ala toimia selaimessa, varmista, että sitä ajetaan grafiikkakortin kautta. Esimerkiksi NVIDIA :lla sen omassa ohjauspaneelissa on pikavalikkovalinta <em><strong>Firefox</strong></em>, josta valitaan <em>Run with graphics processor &gt; High-performance NVIDIA processor</em>.</p>
+</div>
+
+<p>Demossa on kaikkien WebGL-demojen äiti — pyörivä  3D-kuutio. Toteutimme sen puhtaasti <a href="/en-US/docs/Web/API/WebGL_API">WebGL API</a> :n koodilla. Tässä ei käsitellä perus JavaScriptiä tai WebGL:ää, vaan pelkästään WebVR osia.</p>
+
+<p>Demosta löytyy myös:</p>
+
+<ul>
+ <li>Painike, jolla näkymä saadaan päälle VR-näyttöön (ja pois).</li>
+ <li>Painike, joka näyttää (ja piilottaa) VR:n 'pose' -tiedot - eli silmikon sijainnin ja suunnan - reaaliajassa.</li>
+</ul>
+
+<p>Kun tutustut lähdekoodin päätiedostoon -<a href="https://github.com/mdn/webvr-tests/blob/master/raw-webgl-example/webgl-demo.js"> main JavaScript file</a> - löydät WebVR-osat koodista kommenttien "WebVR" tekstien avulla.</p>
+
+<div class="note">
+<p><strong>Huom</strong>: JavaScriptin ja WebGL:n perusteista lisätietoja löytyy tutoriaaleista <a href="/en-US/docs/Learn/JavaScript">JavaScript learning material</a> ja <a href="/en-US/docs/Web/API/WebGL_API/Tutorial">WebGL Tutorial</a>.</p>
+</div>
+
+<h2 id="Miten_se_toimii">Miten se toimii?</h2>
+
+<p>Tässä vaiheessa katsotaan koodin WebVR-osien toiminta.</p>
+
+<p>Tyypillinen (yksinkertainen) WebVR sovellus toimii näin:</p>
+
+<ol>
+ <li>{{domxref("Navigator.getVRDisplays()")}} hakee viittauksen VR-näyttöösi.</li>
+ <li>{{domxref("VRDisplay.requestPresent()")}} :ä käytetään käynnistämään esittäminen VR-näytölle.</li>
+ <li>WebVR:n omaa {{domxref("VRDisplay.requestAnimationFrame()")}} -metodia käytetään suorittamaan sovelluksen renderöintisilmukkaa näytölle sopivalla virkistystaajuudella.</li>
+ <li>Renderöintisilmukassa haet ruudun näyttämiseen vaaditun datan ({{domxref("VRDisplay.getFrameData()")}}), piirrät näytettävän skenen kahdesti — molemmille silmille — ja toimitat renderöidyn näkymän näytölle käyttäjälle näytettäväksi metodilla ({{domxref("VRDisplay.submitFrame()")}}).</li>
+</ol>
+
+<p>Alla olevissa kappaleissa tutustutaan webgl-demoihimme yksityiskohtaisemmin ja nähdään tarkemmin, missä edellä mainittuja ominaisuuksia käytetään.</p>
+
+<h3 id="Aloitetaan_muuttujilla">Aloitetaan muuttujilla</h3>
+
+<p>Ensimmäinen esimerkki WebVR:n käytöstä näkyy alla olevassa koodissa:</p>
+
+<pre class="brush: js">// WebVR variables
+
+var frameData = new VRFrameData();
+var vrDisplay;
+var btn = document.querySelector('.stop-start');
+var normalSceneFrame;
+var vrSceneFrame;
+
+var poseStatsBtn = document.querySelector('.pose-stats');
+var poseStatsSection = document.querySelector('section');
+poseStatsSection.style.visibility = 'hidden'; // hide it initially
+
+var posStats = document.querySelector('.pos');
+var orientStats = document.querySelector('.orient');
+var linVelStats = document.querySelector('.lin-vel');
+var linAccStats = document.querySelector('.lin-acc');
+var angVelStats = document.querySelector('.ang-vel');
+var angAccStats = document.querySelector('.ang-acc');
+var poseStatsDisplayed = false;</pre>
+
+<p>Lyhyet selitykset ovat siis tarpeen:</p>
+
+<ul>
+ <li><code>frameData</code> sisältää {{domxref("VRFrameData")}} olion, joka on tehty {{domxref("VRFrameData.VRFrameData", "VRFrameData()")}} -muodostimella. Tämä on alkuaan tyhjä, mutta sisältää myöhemmin VR-näytölle näytettävien ruutujen renderöintiin tarvittavat tiedot, ja ne päivitetään aina renderöintisilmukassa uudelleen.</li>
+ <li><code>vrDisplay</code> on alkuun alustamaton, mutta siinä on myöhemmin viittaus VR-silmikkoomme ({{domxref("VRDisplay")}} — joka on API:n keskeinen ohjattava kohde).</li>
+ <li><code>btn</code> ja <code>poseStatsBtn</code> viittaavat sovelluksen ohjaamiseen käytettyihin painikkeisiin.</li>
+ <li><code>normalSceneFrame</code> ja <code>vrSceneFrame</code> ovat aluksi alustamattomia, mutta myöhemmin viittaavat {{domxref("Window.requestAnimationFrame()")}} ja {{domxref("VRDisplay.requestAnimationFrame()")}} metodeihin — nämä alustavat normaalin ja WebVR-spesifisen renderöintisilmukan suorittamisen; niiden välisestä erosta selitetään hieman jäljempänä.</li>
+ <li>Muut muuttujat sisältävät viittauksia käyttöliittymän oikeassa alakulmassa näkyvän VR-sijainnin ja suuntauksen näyttävän tietolaatikon eri osiin.</li>
+</ul>
+
+<h3 id="VR-näytön_hakeminen">VR-näytön hakeminen</h3>
+
+<p>Koodimme tärkeimpiä metodeja on <code>start()</code> — tämä suoritetaan, kun sivun body-osa on ladattu valmiiksi:</p>
+
+<pre class="brush: js">// start
+//
+// Called when the body has loaded is created to get the ball rolling.
+
+document.body.onload = start;</pre>
+
+<p>Aluksi<code>start()</code> hakee webbisivumme - <a href="https://github.com/mdn/webvr-tests/blob/master/raw-webgl-example/index.html">our HTML</a> - {{htmlelement("canvas")}} -osaan renderöitävään 3D-grafiikkaan tarvitun WebGL -ympäristön. Sitten tarkistetaan, että <code>gl</code> -ympäristö on käytettävissä — jos on, suoritetaan muutama metodi näytettävän skenen alustamiseksi.</p>
+
+<pre class="brush: js">function start() {
+ canvas = document.getElementById("glcanvas");
+
+ initWebGL(canvas); // Initialize the GL context
+
+ // WebGL setup code here</pre>
+
+<p>Seuraavaksi aloitetaan varsinainen näyttöprosessi. Siinä asetetaan canvas-elementti näyttämään selaimen koko näytettävä ala ja suorittamalla renderöintisilmukka(<code>drawScene()</code>) ensimmäisen kerran. Tässä siis ei-WebVR osuus— se normaali renderöintisilmukka.</p>
+
+<pre class="brush: js"> // draw the scene normally, without WebVR - for those who don't have it and want to see the scene in their browser
+
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ drawScene();</pre>
+
+<p>Seuraavaksi tulee sitten ensimmäinen pala WebVR-koodia. Aluksi tarkistetaan, onko VR-näyttöjä edes käytettävissä {{domxref("Navigator.getVRDisplays")}}  — tästä alkaa API:n käyttö ja tämä on hyvä paikka WebVR:n ominaisuuksien tarkistamiseen. Koodilohkon lopussa (<code>else</code> -osassa) näkyy, että ellei sopivia näyttöjä ole, näytetään viesti, ettei selain tue WebVR 1.1 :ää.</p>
+
+<pre class="brush: js"> // WebVR: Check to see if WebVR is supported
+ if(navigator.getVRDisplays) {
+ console.log('WebVR 1.1 supported');</pre>
+
+<p><code>if() { ... }</code> koodilohkossa suoritetaan {{domxref("Navigator.getVRDisplays()")}} metodi. Tämä palauttaa <a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">promise</a>-olion, jonka sisältönä on lista tietokoneeseen kytketyistä VR-näytöistä. Se on tyhjä, ellei näyttöjä ole..</p>
+
+<pre class="brush: js"> // Then get the displays attached to the computer
+ navigator.getVRDisplays().then(function(displays) {</pre>
+
+<p>Promise-olion <code>then()</code> -lohkossa tarkistetaan, että listan pituus on suurempi kuin 0; näin ollessa asetetaan <code>vrDisplay</code> -muuttujamme arvoksi listan ensimmäisen -indeksistä 0 löytyvän - alkion arvo. <code>vrDisplay</code> sisältää nyt {{domxref("VRDisplay")}} olion, joka vastaa laitteeseen liitettyä näyttöä!</p>
+
+<pre class="brush: js"> // If a display is available, use it to present the scene
+ if(displays.length &gt; 0) {
+ vrDisplay = displays[0];
+ console.log('Display found');</pre>
+
+<div class="note">
+<p><strong>Huom</strong>: On epätavallista, että tietokoneeseen olisi kytketty useita VR-näyttöjä, joten tätä yksinkertaista demoa varten usean näytön vaihtoehtoa ei huomioida.</p>
+</div>
+
+<h3 id="VR-esityksen_käynnistys_ja_pysäytys">VR-esityksen käynnistys ja pysäytys</h3>
+
+<p>Nyt kun käytössä on {{domxref("VRDisplay")}} olio, sen avulla voidaan tehdä useita juttuja. Seuraavaksi haluamme käynnistää toiminnot WebGL-sisällön näyttämisen aloittamiseksi ja lopettamiseksi.</p>
+
+<p>Jatkaaksemme edellisestä koodilohkosta, lisäämme käynnistys/pysäytys -painikkeeseemme (<code>btn</code>) tapahtumankuuntelijan (event listener) — ja painiketta klikattaessa halutaan tarkistaa, joko esitys näytölle on käynnissä (toteutus tälle on hieman kökkö ja perustuu painikkeen tekstin, <code><a href="/en-US/docs/Web/API/Node/textContent">textContent</a></code>, tutkimiseen).</p>
+
+<p>Ellei esitys näyttöön ole vielä käynnissä, käytetään {{domxref("VRDisplay.requestPresent()")}} -metodia pyytämään selainta käynnistämään esitys näytölle. Parametrinä metodille annetaan lista {{domxref("VRLayerInit")}} olioita, jotka vastaavat näytettäväksi haluttuja näyttötasoja.</p>
+
+<p>Koska tällä hetkellä on mahdollista esittää vain yksi näyttötaso, ja ainoa vaadittu olion jäsen on {{domxref("VRLayerInit.source")}} -ominaisuus (joka viittaa tuossa näyttötasossa näytettäväksi tarkoitettuun {{htmlelement("canvas")}} :iin; annetaan muille parametreille järkevät oletusarvot — kts. {{domxref("VRLayerInit.leftBounds", "leftBounds")}} ja {{domxref("VRLayerInit.rightBounds", "rightBounds")}})), parametri on yksinkertaisesti [{ source: canvas }].</p>
+
+<p><code>requestPresent()</code> palauttaa promise-olion, joka saa sisällön, kun esittäminen käynnistyy onnistuneesti.</p>
+
+<pre class="brush: js"> // Starting the presentation when the button is clicked: It can only be called in response to a user gesture
+ btn.addEventListener('click', function() {
+ if(btn.textContent === 'Start VR display') {
+ vrDisplay.requestPresent([{ source: canvas }]).then(function() {
+ console.log('Presenting to WebVR display');</pre>
+
+<p>Nyt kun esittämispyyntö oli ok, halutaan seuraavaksi asettaa renderöintisisältö esitettäväksi VR-näytölle. Aivan ensimmäiseksi asetetaan canvas samankokoiseksi VR-näytön näyttöalueen kanssa. Tämä onnistuu hakemalla {{domxref("VREyeParameters")}} molemmille silmille käyttäen metodia {{domxref("VRDisplay.getEyeParameters()")}}.</p>
+
+<p>Sen jälkeen lasketaan yksinkertaisesti VR-näytön kokonaisala silmän ominaisuuksien {{domxref("VREyeParameters.renderWidth")}} ja {{domxref("VREyeParameters.renderHeight")}} avulla.</p>
+
+<pre class="brush: js"> // Set the canvas size to the size of the vrDisplay viewport
+
+ var leftEye = vrDisplay.getEyeParameters('left');
+ var rightEye = vrDisplay.getEyeParameters('right');
+
+ canvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2;
+ canvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight);</pre>
+
+<p>Seuraavaksi pysäytetään renderöintisilmukka {{domxref("Window.cancelAnimationFrame()", "cancel the animation loop")}}, joka aiemmin käynnistyi {{domxref("Window.requestAnimationFrame()")}} kutsulla <code>drawScene()</code> -metodista ja sen sijaan kutsutaan<code>drawVRScene()</code>:ä. Tämä metodi renderöi saman skenen kuin aiempikin käyttäen nyt VR-kohtaisia temppuja. Tämän renderöintisilmukan hallinta on nyt vastaavalla WebVR-versiolla, {{domxref("VRDisplay.requestAnimationFrame")}} -metodilla.</p>
+
+<pre class="brush: js"> // stop the normal presentation, and start the vr presentation
+ window.cancelAnimationFrame(normalSceneFrame);
+ drawVRScene();</pre>
+
+<p>Lopuksi päivitetään painikkeen teksti, jolloin seuraavalla klikkauskerralla painike tuleekin pysäyttämään esityksen VR-näytöllä.</p>
+
+<pre class="brush: js"> btn.textContent = 'Exit VR display';
+ });</pre>
+
+<p><br>
+ VR-näytöllä esittämisen pysäyttämiseksi painikkeen seuraavalla klikkauksella kutsutaan {{domxref("VRDisplay.exitPresent()")}} -metodia. Painikkeen teksti vaihdetaan taas toiseksi ja <code>requestAnimationFrame</code> -kutsut vaihdetaan taas keskenään. Tästä näkyy, että käytetään metodia {{domxref("VRDisplay.cancelAnimationFrame")}} VR-renderöintisilmukan pysäyttämiseen ja normaalin skenen renderöinti käynnistyy <code>drawScene()</code>-metodilla.</p>
+
+<pre class="brush: js"> } else {
+ vrDisplay.exitPresent();
+ console.log('Stopped presenting to WebVR display');
+
+ btn.textContent = 'Start VR display';
+
+ // Stop the VR presentation, and start the normal presentation
+ vrDisplay.cancelAnimationFrame(vrSceneFrame);
+ drawScene();
+ }
+ });
+ }
+ });
+ } else {
+ console.log('WebVR API not supported by this browser.');
+ }
+ }
+}</pre>
+
+<p>Kun esittäminen käynnistyy, selaimessa näkyy stereoskooppinen näkymä:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15123/Capture2.png" style="display: block; margin: 0 auto;"></p>
+
+<p>Seuraavasta opitaan, miten stereonäkymä varsinaisesti tehdään.</p>
+
+<h3 id="Miksi_WebVRllä_on_oma_requestAnimationFrame()">Miksi WebVR:llä on oma requestAnimationFrame()?</h3>
+
+<p>Tämä on hyvä kysymys. Perussyy on sulava renderöinti VR-näytössä, joka saadaan aikaan käyttämällä VR-näytön omaa näytönpäivitysnopeutta eikä tietokoneen. VR-näytön päivitysnopeudet ovat tietokonetta suurempia, yleisesti jopa  90fps. Tämä poikkeaa tietokoneen peruspäivitysnopeudesta.</p>
+
+<p>Huomaa, että kun VR-näytössä ei esitetä, {{domxref("VRDisplay.requestAnimationFrame")}} toimii identtisesti {{domxref("Window.requestAnimationFrame")}}:n kanssa, joten halutessasi voisit käyttää vain yhtä renderöintisilmukkaa tekemämme sovelluksen kahden silmukan sijaan. Sovelluksessa käytetään kahta, koska VR-esityksen ollessa päällä halutaan tehdä hieman eri asioita kuin ilman sitä, ja nämä halutaan selkeyden vuoksi erottaa.</p>
+
+<h3 id="Renderöinti_ja_näyttäminen">Renderöinti ja näyttäminen</h3>
+
+<p>Tässä vaiheessa on nähty kaikki koodi, mikä tarvitaan VR-laitteiston hakemiseen, skenen näyttöpyynnön lähettämiseen ja renderöintisilmukan käynnistämiseen. Seuraavaksi kurkataan renderöintisilmukan sisälle ja selitetään, miten sen WebVR-spesifiset osat toimivat.</p>
+
+<p>Aluksi tarkastellaan renderöintisilmukkametodin  — <code>drawVRScene()</code> määrittelyä. Ensimmäinen tehtävä on kutsua {{domxref("VRDisplay.requestAnimationFrame()")}} -metodia silmukan toiston jatkamiseksi ensimmäisen kutsukerran jälkeen (tämä tehtiin aiemmin koodissa, kun VR-näytölle esittäminen aloitettiin). Tämä metodikutsu asetetaan globaalin <code>vrSceneFrame</code> -muuttujan arvoksi, jotta silmukka saadaan keskeytettyä {{domxref("VRDisplay.cancelAnimationFrame()")}} -metodilla, kun VR-esitys loppuu.</p>
+
+<pre class="brush: js">function drawVRScene() {
+ // WebVR: Request the next frame of the animation
+ vrSceneFrame = vrDisplay.requestAnimationFrame(drawVRScene);</pre>
+
+<p>Seuraavaksi kutsutaan metodia {{domxref("VRDisplay.getFrameData()")}}, joka saa parametriksi muuttujanimen, johon ruudun tiedot halutaan. Tämähän alustettiin jo aiemmin nimellä  <code>frameData</code>. Metodin suorittamisen jälkeen tässä muuttujassa on tarpeelliset tiedot seuraavan ruudun renderöintiin VR -laitteelle pakattuna {{domxref("VRFrameData")}} -olioon. Mukana on tieto projektio- ja näkymämatriiseista, joiden avulla skene saadaan renderöityä oikein vasemmalle ja oikealle silmälle sekä ajantasainen {{domxref("VRPose")}} -olio, jossa on mm. VR-näytön suunta- ja sijaintitiedot.</p>
+
+<p>Tätä tulee kutsua joka ruudun kohdalla, jotta renderöity näkymä olisi ajantasainen.</p>
+
+<pre class="brush: js"> // Populate frameData with the data of the next frame to display
+ vrDisplay.getFrameData(frameData);</pre>
+
+<p>Seuraavaksi haetaan senhetkinen {{domxref("VRPose")}} ominaisuudesta {{domxref("VRFrameData.pose")}}, tallennetaan sijainti ja suunta myöhempää käyttöä varten ja lähetetään pose-tieto näytettäväksi sivun tilatietoruutuun, siis mikäli <code>poseStatsDisplayed</code> -muuttuja on saanut arvon true.</p>
+
+<pre class="brush: js"> // You can get the position, orientation, etc. of the display from the current frame's pose
+
+ var curFramePose = frameData.pose;
+ var curPos = curFramePose.position;
+ var curOrient = curFramePose.orientation;
+ if(poseStatsDisplayed) {
+ displayPoseStats(curFramePose);
+ }</pre>
+
+<p>  Seuraavaksi canvas:in sisältö tyhjennetään ennen uuden piirron aloittamista, jotta seuraava ruutu piirrettäisiin puhtaalle pohjalle, eikä aiempi ruutu olisi alla sotkemassa:</p>
+
+<pre class="brush: js"> // Clear the canvas before we start drawing on it.
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);</pre>
+
+<p>Nyt renderöidään molempien silmien näkymä. Aluksi tarvitaan projektion ja näkymän sijainti renderöintiä varten. Nämä ovat {{domxref("WebGLUniformLocation")}} -olioita, jotka on luotu {{domxref("WebGLRenderingContext.getUniformLocation()")}} -metodilla käyttäen parametreinä shader-ohjelman tunnusta ja nimitunnistetta.</p>
+
+<pre class="brush: js"> // WebVR: Create the required projection and view matrix locations needed
+ // for passing into the uniformMatrix4fv methods below
+
+ var projectionMatrixLocation = gl.getUniformLocation(shaderProgram, "projMatrix");
+ var viewMatrixLocation = gl.getUniformLocation(shaderProgram, "viewMatrix");</pre>
+
+<p>Seuraava renderöintivaihe sisältää:</p>
+
+<ul>
+ <li>Viewportin koon määrittäminen vasemmalle silmälle  {{domxref("WebGLRenderingContext.viewport")}} -metodilla — tämä on tietenkin canvas:in leveyden ensimmäinen puolikas kertaa sen täysi korkeus.</li>
+ <li>Vasemmalle silmälle renderöintiin käytettävät näkymä- ja projektiomatriisien arvojen määrittäminen — tämä tehdään käyttämällä {{domxref("WebGLRenderingContext.uniformMatrix", "WebGLRenderingContext.uniformMatrix4fv")}} -metodia, joka saa parametrikseen yllä haetut sijaintitiedot ja {{domxref("VRFrameData")}} -oliolta saatavat vasemman puolen matriisit.</li>
+ <li><code>drawGeometry()</code> funktion suorittaminen, joka suorittaa varsinaisen skenen renderöinnin — ja edellisistä vaiheista johtuen siis vain vasemmalle silmälle.</li>
+</ul>
+
+<pre class="brush: js"> // WebVR: Render the left eye’s view to the left half of the canvas
+ gl.viewport(0, 0, canvas.width * 0.5, canvas.height);
+ gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.leftProjectionMatrix);
+ gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.leftViewMatrix);
+ drawGeometry();</pre>
+
+<p>Ja sama oikealle silmälle:</p>
+
+<pre class="brush: js"> // WebVR: Render the right eye’s view to the right half of the canvas
+ gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height);
+ gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.rightProjectionMatrix);
+ gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.rightViewMatrix);
+ drawGeometry();</pre>
+
+<p>Seuraavaksi määritellään<code>drawGeometry()</code> funktio. Suurin osa siitä koostuu tavallisesta WebGL -koodista, jolla saadaan piirrettyä 3D-kuutio. WebVR-spesifisiä osia löytyy <code>mvTranslate()</code> ja<code>mvRotate()</code> funktiokutsuista — ne välittävät matriisit WebGL-ohjelmalle, joka määrittää sen hetkiselle ruudulle kuution sijainnin ja kierron.</p>
+
+<p>Kuten huomaat, näitä arvoja muokataan {{domxref("VRPose")}} -oliolta saaduilla VR-näytön sijainti- (<code>curPos</code>) ja kiertotiedoilla (<code>curOrient</code>). Sen seurauksena esimerkiksi päätä vasemmalle käännettäessä kuvassa näkyvä kuutio siirtyy aivan odotetustikin oikealle, kun  x-sijaintitieto (<code>curPos[0]</code>) ja y-kiertotieto (<code>[curOrient[1]</code>) lisätään x-translaatioarvoon.</p>
+
+<p>Tämä on 'quick and dirty' -tapa käyttää VR pose-tietoa, mutta se näyttänee kuitenkin perusidean.</p>
+
+<pre class="brush: js"> function drawGeometry() {
+ // Establish the perspective with which we want to view the
+ // scene. Our field of view is 45 degrees, with a width/height
+ // ratio of 640:480, and we only want to see objects between 0.1 units
+ // and 100 units away from the camera.
+
+ perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0);
+
+ // Set the drawing position to the "identity" point, which is
+ // the center of the scene.
+
+ loadIdentity();
+
+ // Now move the drawing position a bit to where we want to start
+ // drawing the cube.
+
+ mvTranslate([
+ 0.0 - (curPos[0] * 25) + (curOrient[1] * 25),
+ 5.0 - (curPos[1] * 25) - (curOrient[0] * 25),
+ -15.0 - (curPos[2] * 25)
+ ]);
+
+ // Save the current matrix, then rotate before we draw.
+
+ mvPushMatrix();
+ mvRotate(cubeRotation, [0.25, 0, 0.25 - curOrient[2] * 0.5]);
+
+ // Draw the cube by binding the array buffer to the cube's vertices
+ // array, setting attributes, and pushing it to GL.
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ // Set the texture coordinates attribute for the vertices.
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ // Specify the texture to map onto the faces.
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+ gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
+
+ // Draw the cube.
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
+ setMatrixUniforms();
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+
+ // Restore the original matrix
+
+ mvPopMatrix();
+ }
+</pre>
+
+<p>Seuraava koodipalanen ei liity mitenkään WebVR:ään — siinä vain kierretään kuutiota joka ruudun osalta:</p>
+
+<pre class="brush: js"> // Update the rotation for the next draw, if it's time to do so.
+
+ var currentTime = (new Date).getTime();
+ if (lastCubeUpdateTime) {
+ var delta = currentTime - lastCubeUpdateTime;
+
+ cubeRotation += (30 * delta) / 1000.0;
+ }
+
+ lastCubeUpdateTime = currentTime;</pre>
+
+<p>Renderöintisilmukan viimeiseen osaan kuuluu {{domxref("VRDisplay.submitFrame()")}} -metodin kutsuminen — kaikki tarpeellinen on nyt tehty ja näyttö on renderöity {{htmlelement("canvas")}} :iin, tämä metodi sitten toimittaa ruudun VR-näytölle, jolloin se ruutu näkyy myös siinä.</p>
+
+<pre class="brush: js"> // WebVR: Indicate that we are ready to present the rendered frame to the VR display
+ vrDisplay.submitFrame();
+}</pre>
+
+<h3 id="Pose_(sijainti_kierto_ym.)_-tiedon_näyttäminen">Pose (sijainti, kierto, ym.) -tiedon näyttäminen</h3>
+
+<p>Tässä osassa tutustutaan <code>displayPoseStats()</code> -funktioon, joka näyttää kunkin ruudun päivitetyt pose-tiedot. Kyseinen funktio on melko yksinkertainen.</p>
+
+<p>Aluksi tallennetaan {{domxref("VRPose")}}-oliolta saadut kuusi ominaisuutta omiin muuttujiin — ne ovat tyyppiä {{domxref("Float32Array")}}.</p>
+
+<pre class="brush: js">function displayPoseStats(pose) {
+ var pos = pose.position;
+ var orient = pose.orientation;
+ var linVel = pose.linearVelocity;
+ var linAcc = pose.linearAcceleration;
+ var angVel = pose.angularVelocity;
+ var angAcc = pose.angularAcceleration;</pre>
+
+<p>Sitten tiedot kirjoitetaan tietolaatikkoon ja päivitetään ne joka ruudun kohdalla. Arvot on pyöristetty <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed">toFixed()</a></code> -metodilla luettavuuden vuoksi.</p>
+
+<p>Huomaa ehtolause lineaarisen ja kulmakiihtyvyyden vektorien arvojen tarkastamisessa - siinä varmistetaan ennen näyttämistä, että arvot on tosiaan saatu luettua. Useimmilta VR-laitteistolta näitä arvoja ei vielä saada, joten ilman tarkistamista seuraisi virhetoiminta (ellei arvoja saada, vektorien arvoksi tulee <code>null</code>).</p>
+
+<pre class="brush: js"> posStats.textContent = 'Position: x ' + pos[0].toFixed(3) + ', y ' + pos[1].toFixed(3) + ', z ' + pos[2].toFixed(3);
+ orientStats.textContent = 'Orientation: x ' + orient[0].toFixed(3) + ', y ' + orient[1].toFixed(3) + ', z ' + orient[2].toFixed(3);
+ linVelStats.textContent = 'Linear velocity: x ' + linVel[0].toFixed(3) + ', y ' + linVel[1].toFixed(3) + ', z ' + linVel[2].toFixed(3);
+ angVelStats.textContent = 'Angular velocity: x ' + angVel[0].toFixed(3) + ', y ' + angVel[1].toFixed(3) + ', z ' + angVel[2].toFixed(3);
+
+ if(linAcc) {
+ linAccStats.textContent = 'Linear acceleration: x ' + linAcc[0].toFixed(3) + ', y ' + linAcc[1].toFixed(3) + ', z ' + linAcc[2].toFixed(3);
+ } else {
+ linAccStats.textContent = 'Linear acceleration not reported';
+ }
+
+ if(angAcc) {
+ angAccStats.textContent = 'Angular acceleration: x ' + angAcc[0].toFixed(3) + ', y ' + angAcc[1].toFixed(3) + ', z ' + angAcc[2].toFixed(3);
+ } else {
+ angAccStats.textContent = 'Angular acceleration not reported';
+ }
+}</pre>
+
+<h2 id="WebVR_-tapahtumat">WebVR -tapahtumat</h2>
+
+<p>The WebVR spesifikaatiossa on määritetty useita liipaistavia tapahtumia (event), ja näin koodilla voidaan reagoida VR-näytön tilan muutoksiin (vrt. <a href="/en-US/docs/Web/API/WebVR_API#Window_events">Window events</a>). Esimerkiksi:</p>
+
+<ul>
+ <li>{{event("vrdisplaypresentchange")}} — Liipaistaan, kun VR-näytön esittämistila muuttuu — esim. esitetään -&gt; ei esitetä, ja päinvastoin.</li>
+ <li>{{event("vrdisplayconnect")}} — Saadaan, kun yhteensopiva VR-näyttö on liitetty tietokoneeseen.</li>
+ <li>{{event("vrdisplaydisconnect")}} — Tapahtuma VR-näytön irrotuksesta.</li>
+</ul>
+
+<p>Demossa on seuraava esimerkki tapahtumista:</p>
+
+<pre class="brush: js">window.addEventListener('vrdisplaypresentchange', function(e) {
+ console.log('Display ' + e.display.displayId + ' presentation has changed. Reason given: ' + e.reason + '.');
+});</pre>
+
+<p>Kuten näet {{domxref("VRDisplayEvent", "event object")}} tarjoaa kaksi hyödyllistä ominaisuutta — {{domxref("VRDisplayEvent.display")}}, joka viittaa {{domxref("VRDisplay")}} tapahtuman tuottajaan, ja {{domxref("VRDisplayEvent.reason")}}, jossa on selkokielinen syy tapahtumaan.</p>
+
+<p>Tämä on hyvin käyttökelpoinen tapahtuma; sitä voidaan käyttää huomaan yllättävä näytön irrotus, joka estäää tarpeettomat virheviestit ja kertoo tilanteen käyttäjälle. Googlen Webvr.info -esitysdemossa tapahtumaa käytetään suorittamaan <a href="https://github.com/toji/webvr.info/blob/master/samples/03-vr-presentation.html#L174"><code>onVRPresentChange()</code> funktio</a>, joka päivittää käyttöliittymän kontrollit tilannetta vastaaviksi ja muuttaa canvasin kokoa.</p>
+
+<h2 id="Yhteenveto">Yhteenveto</h2>
+
+<p>Tässä artikkelissa kerrottiin hyvin yksinkertaisen WebVR 1.1 sovelluksen tekemisestä, jonka avulla pääset alkuun sovellusten kehittämisessä.</p>