diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:41:45 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:41:45 -0500 |
commit | 1109132f09d75da9a28b649c7677bb6ce07c40c0 (patch) | |
tree | 0dd8b084480983cf9f9680e8aedb92782a921b13 /files/fi/web/api/webvr_api/using_the_webvr_api | |
parent | 4b1a9203c547c019fc5398082ae19a3f3d4c3efe (diff) | |
download | translated-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.html | 438 |
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 > 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 > 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 -> 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> |