La capacité d'exécuter la réalité virtuelle au sein d'un navigateur mobile est stimulante et excitante. Google Cardboard et d'autres appareils VR similaires le rendent incroyablement simple, placez simplement votre téléphone dans le support et partez! J'ai précédemment couvert en apportant VR sur le Web avec Google Cardboard et Three.js, où j'ai discuté des bases de la création d'un environnement VR qui tire des données Web. Les gens ont vraiment apprécié cet article (et j'ai vraiment aimé construire cette démo), alors j'ai pensé que je dirais avec une idée différente. Plutôt que d'apporter des API Web, pourquoi ne pas apporter la caméra de votre téléphone et transformer cela en une expérience de réalité augmentée?
Dans cet article, je vais explorer comment nous pouvons tirer les données de la caméra, la filtrer et l'afficher en utilisant HTML5 et JavaScript. Nous le ferons tout au long d'un effet de vision stéréoscopique pour créer une expérience de réalité augmentée pour Google Cardboard et d'autres appareils VR. Nous appliquerons quelques filtres différents sur notre flux de caméras - un filtre à niveaux de gris caricatural, un filtre de style film sépia, un filtre pixélé (mon préféré) et un filtre de couleur inverse.
Si vous êtes complètement nouveau dans le filtrage des images avec HTML5, la balise Canvas et JavaScript, j'ai un cours entier sur le sujet sur l'apprentissage appelé JavaScript in Motion! J'approcherai cet article en supposant que vous comprenez le canevas et les balises vidéo, ainsi que comment diffuser des vidéos dans la balise Canvas. Ou avec l'hypothèse que vous êtes assez confiant pour le résoudre au fur et à mesure que vous allez!
Si vous souhaitez entrer directement dans le code et l'essayer, vous pouvez le trouver ici sur github.
Vous voulez l'essayer en action? J'ai une version en cours d'exécution hébergée ici: Reality Filter.
Remarque: Un changement récent dans la façon dont Chrome gère l'entrée de l'appareil photo nécessite l'exécution de la page via HTTPS pour que cela fonctionne!
Nous allons prendre la même configuration initiale de l'article précédent de Google Cardboard - une scène Three.js que nous affichons via un effet stéréoscopique. Cet effet nous permet d'avoir un affichage pour chaque œil, ce qui rend les choses merveilleusement 3D en VR. Cependant, plutôt que des particules flottantes et telles de l'article précédent, nous supprimons la plupart des éléments et plaçons un maillage simple de trois.js devant la caméra qui joue notre alimentation de caméra.
En examinant nos déclarations variables, la plupart des variables ici seront familières à ceux qui ont traversé la démo précédente. Les variables pour préparer notre scène trois.js, notre appareil photo, notre rendu, l'élément pour notre sortie de toile, notre conteneur pour placer cet élément et une variable pour stocker notre effet stéréoscopique sont les mêmes.
<span>var scene, </span> camera<span>, </span> renderer<span>, </span> element<span>, </span> container<span>, </span> effect<span>,</span>
Nos trois nouvelles variables liées à notre flux de caméras sont la vidéo, la toile et le contexte.
video<span>, </span> canvas<span>, </span> context<span>,</span>
Nous avons quelques autres variables sous celles qui se rapportent à notre fonctionnalité de filtre.
themes <span>= ['blackandwhite', 'sepia', 'arcade', 'inverse'], </span> currentTheme <span>= 0, </span> lookingAtGround <span>= false;</span>
Nous commençons par notre fonction init () configurant notre scène, notre appareil photo et ainsi de suite comme avant:
<span>init(); </span> <span>function init() { </span> scene <span>= new THREE<span>.Scene</span>(); </span> camera <span>= new THREE<span>.PerspectiveCamera</span>(90, window.innerWidth / window.innerHeight, 0.001, 700); </span> camera<span>.position.set(0, 15, 0); </span> scene<span>.add(camera); </span> renderer <span>= new THREE<span>.WebGLRenderer</span>(); </span> element <span>= renderer.domElement; </span> container <span>= document.getElementById('webglviewer'); </span> container<span>.appendChild(element); </span> effect <span>= new THREE<span>.StereoEffect</span>(renderer); </span> element<span>.addEventListener('click', fullscreen, false);</span>
Nous n'avons pas de fonctionnalité de mouvement de la caméra via l'événement de l'orientation device cette fois-ci. Comparé à une expérience VR, nous n'aurons pas besoin de modifier la position réelle de la caméra dans cette scène trois.js. Nous gardons la scène au même endroit - le flux de la caméra est ce qui se déplacera lorsque l'utilisateur regarde autour de lui.
Un auditeur que nous avons gardé de l'exemple précédent est un auditeur d'événements pour aller en plein écran si nous appuyons sur la scène. Cela supprime la barre d'adresse Chrome de notre point de vue.
Il y a une nouvelle utilisation pour le device OoritationEvent dans cette démo. Nous le définissons pour surveiller les modifications de l'orientation de notre appareil et l'utilisons comme déclencheur pour changer notre filtre. Nous n'avons pas vraiment de contrôles physiques pour déclencher des événements, nous contrôlons donc les choses en ce qui concerne l'utilisateur. En particulier, nous modifions le filtre à chaque fois que l'utilisateur regarde le sol.
<span>var scene, </span> camera<span>, </span> renderer<span>, </span> element<span>, </span> container<span>, </span> effect<span>,</span>
Dans ce code, nous surveillons si l'EVT.Gamma se situe entre -1 et 1. Si c'est le cas, ils regardent le sol. C'est un endroit assez précis sur le sol, si vous le trouvez trop petit et difficile à déclencher, vous pouvez augmenter la plage entre -1,5 et 1,5… etc.
Lorsqu'ils regardent dans cette gamme et que lorsque la recherche de terrain est fausse, nous exécutons notre code de commutateur de thème. Cela ajuste CurrentTheme au prochain numéro d'index de notre tableau de thèmes. Nous avons défini la lookatground sur true et le avons réglé après 4 secondes. Cela garantit que nous ne changeons le filtre qu'une fois toutes les quatre secondes au maximum.
Afin de filtrer le monde qui nous entoure, nous avons besoin d'accéder à l'appareil photo à l'origine de «l'environnement» sur notre smartphone. Nous commençons par créer un élément
video<span>, </span> canvas<span>, </span> context<span>,</span>
Notre prochaine étape consiste à tirer notre flux de caméras en utilisant ces options. Pour cela, nous utilisons l'API MediaStream. Il s'agit d'un ensemble d'API JavaScript qui nous permet de tirer des données à partir de flux audio et vidéo locaux - parfait pour obtenir un flux de caméras de notre téléphone. En particulier, nous utiliserons la fonction GetUserMedia. L'API MediaStream est toujours dans le projet de l'éditeur de W3C »et est implémenté légèrement le navigateur au navigateur. Cette démo est principalement axée sur Google Chrome pour mobile, mais pour une future compatibilité, nous obtenons celui qui fonctionne avec le navigateur actuel de notre utilisateur et le affecte à Navigator.getUserMedia:
themes <span>= ['blackandwhite', 'sepia', 'arcade', 'inverse'], </span> currentTheme <span>= 0, </span> lookingAtGround <span>= false;</span>
Ensuite, tant que notre navigateur comprend MediaStreamtrack de l'API MediaStream et a trouvé avec succès une fonction GetUserMedia compatible dans notre navigateur, nous commencerons notre recherche des données de la caméra.
<span>init(); </span> <span>function init() { </span> scene <span>= new THREE<span>.Scene</span>(); </span> camera <span>= new THREE<span>.PerspectiveCamera</span>(90, window.innerWidth / window.innerHeight, 0.001, 700); </span> camera<span>.position.set(0, 15, 0); </span> scene<span>.add(camera); </span> renderer <span>= new THREE<span>.WebGLRenderer</span>(); </span> element <span>= renderer.domElement; </span> container <span>= document.getElementById('webglviewer'); </span> container<span>.appendChild(element); </span> effect <span>= new THREE<span>.StereoEffect</span>(renderer); </span> element<span>.addEventListener('click', fullscreen, false);</span>
Dans l'API MediaStream, nous avons une fonction dans MediaStreamTrack.getsources () qui récupère toutes les sources audio et vidéo disponibles pour le navigateur à partir de son appareil. Il peut récupérer les données de microphone de chaque microphone connecté à votre appareil, ainsi que les données vidéo de chaque appareil photo.
Les valeurs renvoyées de cette fonction nous sont disponibles dans un tableau appelé Sources. Nous parcourons chaque source et recherchons ceux dont le type est égal à "vidéo". Chaque source aura soit une sorte de "Audio" ou "vidéo". Nous voyons alors si la vidéo trouvée a une propriété orientée égale à "l'environnement", dans l'affirmative, c'est la caméra que nous préférerions utiliser. Nous récupérons son ID dans l'API, puis mettons à jour notre objet d'options plus tôt pour inclure également cet ID source comme notre flux vidéo préféré à utiliser.
<span>var scene, </span> camera<span>, </span> renderer<span>, </span> element<span>, </span> container<span>, </span> effect<span>,</span>
L'objet Options ressemblerait maintenant à des coulisses:
video<span>, </span> canvas<span>, </span> context<span>,</span>
Enfin, nous transmettons ces options à notre fonction Navigator.getUserMedia ainsi qu'un succès et un rappel d'erreur. Cela fera la récupération de nos données vidéo.
themes <span>= ['blackandwhite', 'sepia', 'arcade', 'inverse'], </span> currentTheme <span>= 0, </span> lookingAtGround <span>= false;</span>
Une fois que nous avons notre flux vidéo, nous l'avons mis dans notre scène dans notre rappel de succès, StreamFound (). Nous commençons par ajouter notre élément vidéo au DOM, définissant son contenu à notre flux vidéo retourné et en faisant la pleine largeur et la hauteur de la fenêtre (car nous voulons une résolution élevée pour lire notre toile).
<span>init(); </span> <span>function init() { </span> scene <span>= new THREE<span>.Scene</span>(); </span> camera <span>= new THREE<span>.PerspectiveCamera</span>(90, window.innerWidth / window.innerHeight, 0.001, 700); </span> camera<span>.position.set(0, 15, 0); </span> scene<span>.add(camera); </span> renderer <span>= new THREE<span>.WebGLRenderer</span>(); </span> element <span>= renderer.domElement; </span> container <span>= document.getElementById('webglviewer'); </span> container<span>.appendChild(element); </span> effect <span>= new THREE<span>.StereoEffect</span>(renderer); </span> element<span>.addEventListener('click', fullscreen, false);</span>
Après que nous ayons joué notre flux de caméras dans la page, nous créons un élément de toile en JavaScript que nous utilisons pour faire la manipulation de nos données vidéo. L'élément de toile lui-même n'est jamais ajouté dans la page elle-même, elle reste juste dans notre javascript.
Nous définissons notre toile sur la même largeur et la même hauteur que la vidéo, arrondi jusqu'à la puissance la plus proche de deux. La raison en est que les textures de trois.js fonctionnent mieux comme des pouvoirs de 2. Si vous passez dans d'autres largeurs et hauteurs qui ne sont pas conformes à cela, c'est tout à fait bien, mais vous devez utiliser des options spécifiques de minfilter et de Magfilter. J'ai préféré l'ajuster à la puissance de deux pour garder les choses simples ici.
<span>if (window.<span>DeviceOrientationEvent</span>) { </span> <span>window.addEventListener('deviceorientation', function(evt) { </span> <span>if (evt.gamma > -1 && evt.gamma < 1 && !lookingAtGround) { </span> lookingAtGround <span>= true; </span> currentTheme <span>= (themes.length > currentTheme+1) ? currentTheme+1 : 0; </span> <span>setTimeout(function() { </span> lookingAtGround <span>= false; </span> <span>}, 4000); </span> <span>} </span> <span>}.bind(this)); </span> <span>}</span>
Ensuite, nous créons notre texture trois.js qui contiendra nos séquences vidéo de streaming, passant notre élément de toile. Nous définissons notre variable de contexte dans le contexte de notre élément Canvas créé et attribuons le contexte de notre texture au contexte de notre caneva. Garder le tout en synchronisation
video <span>= document.createElement('video'); </span> video<span>.setAttribute('autoplay', true); </span> <span>var options = { </span> <span>video: { </span> <span>optional: [{facingMode: "environment"}] </span> <span>} </span> <span>};</span>
Nous créons ensuite le plan Three.js que nous allons mettre notre flux sur en utilisant trois.planegeométrie. Je l'ai réglé sur 1920 × 1280 comme taille de base pour notre vidéo.
<span>navigator.getUserMedia = navigator.getUserMedia || </span> <span>navigator.webkitGetUserMedia || navigator.mozGetUserMedia;</span>
Ensuite, nous créons un objet Three.Mesh en utilisant notre plan et notre texture avec notre flux vidéo. Nous le positionnons -600 sur l'axe Z, l'éloignons de notre champ de vision et l'ajoutant dans notre scène trois.js. Si vous avez un flux vidéo de taille différent, vous devrez peut-être ajuster la position Z pour vous assurer que la forme remplit la fenêtre.
<span>if (typeof MediaStreamTrack === 'undefined' && navigator.getUserMedia) { </span> <span>alert('This browser doesn\'t support this demo :('); </span> <span>} else { </span> <span>// Get our camera data!</span>
Après cela, nous avons notre fonction de rappel d'erreur qui exécutera une console.log si quelque chose ne va pas avec notre récupération de flux vidéo.
<span>MediaStreamTrack.getSources(function(sources) { </span> <span>for (var i = 0; i !== sources.length; ++i) { </span> <span>var source = sources[i]; </span> <span>if (source.kind === 'video') { </span> <span>if (source.facing && source.facing == "environment") { </span> options<span>.video.optional.push({'sourceId': source.id}); </span> <span>} </span> <span>} </span> <span>}</span>
À la fin de notre fonction init (), vous verrez notre fonction animate (). C'est là que nous ferons notre traitement de l'image vidéo:
<span>var scene, </span> camera<span>, </span> renderer<span>, </span> element<span>, </span> container<span>, </span> effect<span>,</span>
Notre fonction animate () commence par dessiner le dernier cadre de notre appareil photo sur notre toile en utilisant context.DrawImage ():
video<span>, </span> canvas<span>, </span> context<span>,</span>
À partir de là, nous pouvons lire notre canevas en utilisant context.getimagedata () et appliquer des filtres aux données qu'il contient en fonction du thème sur lequel nous sommes définis. Le code ci-dessous commence par les paramètres de notre filtre noir et blanc qui se lit dans nos données, obtient la luminance générale de chaque pixel dans l'image, puis filtre chaque pixel pour être noir, gris ou blanc en fonction de l'échelle de la luminance qu'il contient . Cela donne une sensation de journal de dessin animé / à l'ancienne à l'image.
themes <span>= ['blackandwhite', 'sepia', 'arcade', 'inverse'], </span> currentTheme <span>= 0, </span> lookingAtGround <span>= false;</span>
qui ressemble à ainsi:
Le thème suivant inverse nos pixels, donc le blanc est noir et ainsi de suite. Il donne un style de rayons X à l'image:
<span>init(); </span> <span>function init() { </span> scene <span>= new THREE<span>.Scene</span>(); </span> camera <span>= new THREE<span>.PerspectiveCamera</span>(90, window.innerWidth / window.innerHeight, 0.001, 700); </span> camera<span>.position.set(0, 15, 0); </span> scene<span>.add(camera); </span> renderer <span>= new THREE<span>.WebGLRenderer</span>(); </span> element <span>= renderer.domElement; </span> container <span>= document.getElementById('webglviewer'); </span> container<span>.appendChild(element); </span> effect <span>= new THREE<span>.StereoEffect</span>(renderer); </span> element<span>.addEventListener('click', fullscreen, false);</span>
qui ressemble à ainsi:
Notre thème sépia utilise une formule que j'ai vue sur divers endroits sur le Web pour donner à l'image une sensation sépia et colorée de la vieille école. J'ajoute également du bruit à l'image en ajoutant un niveau aléatoire de rouge, de vert et de bleu à chaque pixel. Si les pixels via le sépia vont être de plus grands niveaux de couleur que 255, je le coiffe à 255.
<span>if (window.<span>DeviceOrientationEvent</span>) { </span> <span>window.addEventListener('deviceorientation', function(evt) { </span> <span>if (evt.gamma > -1 && evt.gamma < 1 && !lookingAtGround) { </span> lookingAtGround <span>= true; </span> currentTheme <span>= (themes.length > currentTheme+1) ? currentTheme+1 : 0; </span> <span>setTimeout(function() { </span> lookingAtGround <span>= false; </span> <span>}, 4000); </span> <span>} </span> <span>}.bind(this)); </span> <span>}</span>
qui ressemble à ainsi:
Enfin, mon préféré de tous les effets! Le style «arcade» qui pixéle l'image pour le faire ressembler à un monde rétro. Pour réaliser cet effet, j'ai ajusté le plugin Pixelate Close Pixelate par David Desandro et John Schulz. La version originale du plugin convertit une image en ligne et la remplace par une version en toile pixélienne. Ma version prend plutôt des données sur toile et la place dans la même toile et le même contexte, afin que nous puissions l'utiliser pour la vidéo en direct. Ma version ajustée accepte toujours tous les mêmes paramètres que celui de leur page de plugin. Il est un peu plus lent que les autres filtres ci-dessus et pourrait potentiellement être optimisé si j'ai le temps de l'examiner. Pour l'instant, je suis d'accord avec un peu de décalage, ce qui le fait se sentir plus rétro! Une note pour tous ceux qui cherchent à appliquer de nouvelles options dans ce filtre (par exemple, transformer le monde en diamants à la place) - cela peut le faire entendre encore plus!
video <span>= document.createElement('video'); </span> video<span>.setAttribute('autoplay', true); </span> <span>var options = { </span> <span>video: { </span> <span>optional: [{facingMode: "environment"}] </span> <span>} </span> <span>};</span>
qui ressemble à ainsi:
Enfin, nous définissons la texture pour mettre à jour le prochain trame pour trois.js (car nous l'avons définitivement modifié d'une manière ou d'une autre) et exécutez Animate () sur le prochain demandeanimationframe (). Nous exécutons également du code pour mettre à jour et refaire notre scène trois.js.
<span>var scene, </span> camera<span>, </span> renderer<span>, </span> element<span>, </span> container<span>, </span> effect<span>,</span>
Mise à jour fin 2015 - Je reviens dans cet article pour ajouter un nouveau peu d'informations assez importantes - Chrome nécessite désormais que les pages Web utilisant l'appareil photo soient servies sur HTTPS. Donc, avant d'essayer d'exécuter cela, vous devrez trouver un moyen d'exécuter votre service via HTTPS. Une méthode que j'ai utilisée jusqu'à présent pour les tests est Ngrok, qui peut fournir un tunnel HTTPS à votre Host local. Nous avons un guide pour accéder à LocalHost de n'importe où ici à SitePoint, ce qui peut vous aider à démarrer.
Afin de pouvoir accéder à la webcam et tout, il semble que vous deviez l'héberger sur un serveur plutôt que de l'exécuter localement. À des fins de test, j'ai utilisé Ngrok pour tester à partir de mon Mac sur mon téléphone. Sinon, ftp vos affaires sur un serveur Web quelque part et testez!
Exécutez-le dans votre google en carton ou un autre casque VR et vous devriez voir l'environnement autour de vous avec notre filtre noir et blanc pour commencer. Si vous regardez le sol, il doit changer de filtres. C'est très amusant! Voici un petit GIF animé pour le montrer en action (en dehors du casque afin que vous puissiez voir ce qu'il affiche):
combinant la puissance de Google Cardboard, HTML5, JavaScript et Three.js apporte des possibilités vraiment soignées qui ne sont pas uniquement limitées à la réalité virtuelle. En utilisant l'entrée de la caméra, vous pouvez également amener le monde autour de vous dans la scène! Il existe de nombreux autres domaines dans lesquels cette idée initiale peut être développée. Il est également possible de filtrer l'image via trois.js en utilisant les shaders et possible d'ajouter des objets de réalité augmentée sur votre scène - deux idées que je couvrirai dans les futurs articles.
Si vous faites des expériences AR vraiment soignées en fonction de cette démo, laissez une note dans les commentaires ou contactez-moi sur Twitter (@thatpatrickguy), je suis toujours très désireux de jeter un coup d'œil!
L'intégration de HTML5 à la réalité augmentée (AR) peut être réalisée en utilisant des bibliothèques telles que Ar.Js. Cette bibliothèque vous permet de créer des expériences AR qui sont accessibles directement à partir d'un navigateur Web, sans avoir besoin d'une application spécifique. Vous pouvez créer des modèles 3D à l'aide d'un cadre A ou d'autres logiciels de modélisation 3D, puis utiliser AR.JS pour superposer ces modèles sur le monde réel lorsqu'il est vu via la caméra d'un appareil. Cela peut être fait avec seulement quelques lignes de code, ce qui le rend accessible même pour les débutants.
JavaScript joue un rôle crucial dans la création d'expériences AR. Il est utilisé pour contrôler le comportement des éléments AR, tels que la façon dont ils se déplacent, réagissent à l'entrée de l'utilisateur ou changent avec le temps. JavaScript peut également être utilisé pour gérer des tâches plus complexes, telles que le suivi de la position et de l'orientation de l'utilisateur, ou de la gestion de l'interaction entre plusieurs objets AR.
Google Cardboard est une plate-forme de réalité virtuelle (VR) qui utilise une visionneuse en carton dépliante et un smartphone. Vous pouvez utiliser JavaScript avec l'API WebVR pour créer des expériences VR immersives pour Google Cardboard. L'API WebVR fournit les outils nécessaires pour rendre les scènes 3D dans le casque, gérer la saisie de l'utilisateur et gérer l'affichage VR.
Bien que HTML soit crucial pour structurer le contenu d'une page Web, il ne peut pas créer une application AR. Vous devrez utiliser JavaScript et potentiellement d'autres bibliothèques pour gérer la fonctionnalité AR. Cependant, des bibliothèques comme AR.js peuvent rendre ce processus beaucoup plus simple, vous permettant de créer des expériences AR avec seulement quelques lignes de code.
Il existe de nombreux cas d'utilisation potentiels pour intégrer HTML5 à AR. Par exemple, vous pouvez créer une application de magasinage AR qui permet aux utilisateurs de voir à quoi ressemblerait les meubles dans leur maison avant d'acheter. Ou, vous pouvez créer une application éducative qui superpose des informations sur des objets du monde réel, aidant les élèves à apprendre de manière plus interactive.
Bien que HTML soit crucial pour structurer le contenu d'une page Web, il ne peut pas créer une application AR. Vous devrez utiliser JavaScript et potentiellement d'autres bibliothèques pour gérer la fonctionnalité AR. Cependant, des bibliothèques comme AR.JS peuvent rendre ce processus beaucoup plus simple, vous permettant de créer des expériences AR avec seulement quelques lignes de code.
La propriété «filtre» dans JavaScript est utilisée pour définir ou renvoyer les filtres appliqués à un élément. Cela peut inclure des choses comme le flou, la luminosité, le contraste, la niveale des gris, la teinte rotate, l'inverse, l'opacité, la sature, le sépia, etc. Il peut être utilisé pour créer divers effets visuels sur votre page Web.
JavaScript peut être utilisée pour créer des expériences AR en contrôlant le comportement du comportement du Les éléments AR, tels que la façon dont ils se déplacent, réagissent à la saisie des utilisateurs ou changent avec le temps. Des bibliothèques comme AR.JS peuvent simplifier ce processus, vous permettant de créer des expériences AR avec seulement quelques lignes de code.
Le carton Google est principalement conçu pour les expériences VR, mais il peut également être utilisé pour la RA avec le bon logiciel. Vous pouvez utiliser JavaScript avec l'API WebVR pour créer des expériences AR pour Google Cardboard.
Il existe de nombreux exemples d'expériences AR créées avec JavaScript. . Par exemple, vous pouvez créer une application de magasinage AR qui permet aux utilisateurs de voir à quoi ressemblerait les meubles dans leur maison avant d'acheter. Ou, vous pouvez créer une application éducative qui superpose des informations sur des objets du monde réel, aidant les élèves à apprendre de manière plus interactive.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!