I can't seem to get my video playing. At first, it was just a black plane but I managed to get it to the point where I can see the first frame of the video but it doesn't play.I am using MindAR too.
The video is a 4 seconds long 608 x 1408 h.264 MPEG video. I've tried another 1080 x 1920 video but that one just displays a black plane.
Currently only testing on my Macbook Pro 14 Inch, but will eventually be for android and iOS as I'm making a AR publication.
https://glitch.com/edit/#!/unreal-realities-test
https://unreal-realities-test.glitch.me
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js#1.1.4/dist/mindar-image.prod.js"></script>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras#v6.1.1/dist/aframe-extras.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js#1.1.4/dist/mindar-image-aframe.prod.js"></script>
<script>AFRAME.registerComponent("play-on-click", {
init: function () {
this.onClick = this.onClick.bind(this);
},
play: function () {
window.addEventListener("click", this.onClick);
},
pause: function () {
window.removeEventListener("click", this.onClick);
},
onClick: function (evt) {
var videoEl = this.el.getAttribute("material").src;
if (!videoEl) {
return;
}
this.el.object3D.visible = true;
videoEl.play();
},
});
</script>
<script>
AFRAME.registerComponent('hide-on-play', {
schema: {type: 'selector'},
init: function () {
this.onPlaying = this.onPlaying.bind(this);
this.onPause = this.onPause.bind(this);
this.el.object3D.visible = !this.data.playing;
},
play: function () {
if (this.data) {
this.data.addEventListener('playing', this.onPlaying);
this.data.addEventListener('pause', this.onPause);
}
},
pause: function () {
if (this.data) {
this.data.removeEventListener('playing', this.onPlaying);
this.data.removeEventListener('pause', this.onPause);
}
},
onPlaying: function (evt) {
this.el.object3D.visible = false;
},
onPause: function (evt) {
this.el.object3D.visible = true;
}
});</script>
</head>
<body>
<a-scene
mindar-image="imageTargetSrc: https://cdn.glitch.global/644ffc8d-f16a-4136-9daf-b2a8d5be4cd1/ASCIItargets.mind?v=1646650005503; maxTrack: 2"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false"
>
<a-assets>
<img
id="card0"
src="https://cdn.glitch.global/644ffc8d-f16a-4136-9daf-b2a8d5be4cd1/Jesper1_2.jpg?v=1645538130237"
/>
<a-asset-item
id="card1"
src="https://cdn.glitch.global/644ffc8d-f16a-4136-9daf-b2a8d5be4cd1/3D%20Scan%20Test.gltf?v=1645538142025"
></a-asset-item>
<video
id="video"
preload="auto"
src="https://cdn.glitch.global/644ffc8d-f16a-4136-9daf-b2a8d5be4cd1/NFTDemo.mp4?v=1646662685556"
autoplay
loop="true"
crossorigin="anonymous"
width="1"
height="0.552"
webkit-playsinline
></video>
</a-assets>
<a-entity mindar-image-target="targetIndex: 2">
<a-image
src="#card0"
alpha-test="0.5"
position="0 0 0"
height="0.552"
width="1"
material=""
geometry=""
>
</a-image>
</a-entity>
<a-entity mindar-image-target="targetIndex: 1">
<a-gltf-model
rotation="0 -270 0"
position="0 0 0"
scale="1 1 1"
src="#card1"
animation="property: position; to: 0 0.2 0.2; dur: 1000; easing: easeInOutQuad; loop: true; dir: alternate"
></a-gltf-model>
</a-entity>
<a-entity
mindar-image-target="targetIndex: 0"
material="shader: flat; src: #video"
geometry="primitive: plane; width: 2.25; height: 5.25"
position="0 0 0"
rotation="0 0 0"
play-on-click
visible="false"
>
</a-entity>
<a-camera position="0 0 0" look-controls="enabled: false">
<a-entity
position="0 0 -1.5"
text="align: center;
width: 4;
wrapCount: 100;
color: black;
value: Tap to allow videos to play"
hide-on-play="#video">
</a-entity>
</a-camera>
</a-scene>
</body>
</html>
As per browser policies most browsers today don't allow video autoplay without user consent. You need to capture a click or tap and trigger video playback by calling the play() method on the video element. The click event cannot be synthesized: A-Frame entities won't work, you need a 2D DOM element that the user clicks (the window element will work letting the user click anywhere on the screen but can also have some button somewhere that the user needs to tap).
See A-Frame example displaying a modal UI (made with A-Frame) to request the user to start video playback (a component listens for click / taps on the window element): https://aframe.io/aframe/examples/test/video/
The corresponding component logic can be found at: https://github.com/aframevr/aframe/blob/master/examples/js/play-on-click.js#L16
You need something like the code below:
window.addEventListener('click', function () {
document.querySelector('#video').play();
});
I modified your example to illustrate how to play the video on user click. I omitted the mind-ar parts. The video feed covers the UI and I think it's not relevant to the issue: video playback must be triggered by user action.
https://glitch.com/edit/#!/roomy-hyper-bear
Notice play-on-click and hide-on-play are not built-in A-Frame components and you have to import them in your page (see index.html in example above).
I am using 8th wall web to detect image target and place model when the target is found. However when the image target is not in view of the camera, the model disappears. I want the model to stay even if the image target is not in view. Such like extended tracking provided in this example: https://www.youtube.com/watch?v=WjwyBLBhfXU
head.html
<!-- Use "8thwall:" meta tags to hook into 8th Wall's build process and developer tools. -->
<meta name="8thwall:renderer" content="aframe:1.2.0">
<meta name="8thwall:package" content="#8thwall.xrextras">
<!-- Other external scripts and meta tags can also be added. -->
<meta name="apple-mobile-web-app-capable" content="yes">
body.html
<!-- Copyright (c) 2021 8th Wall, Inc. -->
<!-- body.html is optional; elements will be added to your html body after app.js is loaded. -->
<a-scene
xrextras-gesture-detector
xrextras-almost-there
xrextras-loading
xrextras-runtime-error
renderer="colorManagement:true"
xrweb="disableWorldTracking: false">
<a-assets>
<a-asset-item id="jelly-glb" src="assets/jellyfish-model.glb"></a-asset-item>
<img id="jelly-thumb" src="assets/video-thumbnail.jpg">
<video
id="jelly-video"
autoplay
muted
crossorigin="anonymous"
loop="true"
src="assets/jellyfish-video.mp4">
</video>
</a-assets>
<a-camera
position="0 4 10"
raycaster="objects: .cantap"
cursor="fuse: false; rayOrigin: mouse;">
</a-camera>
<a-light type="directional" intensity="0.5" position="1 1 1"></a-light>
<a-light type="ambient" intensity="0.7"></a-light>
<!-- Note: "name:" must be set to the name of the image target uploaded to the 8th Wall Console -->
<xrextras-named-image-target name="video-target">
<a-entity
xrextras-play-video="video: #jelly-video; thumb: #jelly-thumb; canstop: true"
geometry="primitive: plane; height: 1; width: 0.79;"
></a-entity>
</xrextras-named-image-target>
<!-- Note: "name:" must be set to the name of the image target uploaded to the 8th Wall Console -->
<xrextras-named-image-target name="model-target">
<!-- Add a child entity that can be rotated independently of the image target. -->
<a-entity xrextras-one-finger-rotate gltf-model="#jelly-glb"></a-entity>
</xrextras-named-image-target>
</a-scene>
1/ Add in the app.js the following component :
AFRAME.registerComponent('keepvisibleonlost', {
init() {
let el = this.el
el.sceneEl.addEventListener('xrimagelost', function(){
el.object3D.visible = true
})
},
})
2/ Add this new component to your image target in the html :
<xrextras-named-image-target name="video-target" keepvisibleonlost>
I'm trying to load a gltf model to an a-frame , but it isn't loading. Here's the code:
<html>
<head>
<title>Tree model</title>
<script src="https://aframe.io/releases/0.7.1/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-assets id="#tree" src="tree-assets/tree01.gltf">
</a-assets>
<a-entity gltf-model="#tree"></a-entity>
</a-scene>
</body>
</html>
When you give an item an id you don't need to give it a hash tag. Also, try giving the model a position, they default to position 0 0 0, which sometimes you're unable to see as its inside of the camera. Also try using the latest version of A-frame
Try this:
<html>
<head>
<title>Tree model</title>
<script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-assets id="tree" src="tree-assets/tree01.gltf"></a-assets>
<a-entity gltf-model="#tree" position="0 2 -2"></a-entity>
</a-scene>
</body>
</html>
Hope this helped :)
I'm trying to load a single .JSON model exporter from Blender to A-frame
I already try using this loader
https://github.com/donmccurdy/aframe-extras/tree/master/src/loaders
but the model don't show up.
Here's what I'm trying:
<!DOCTYPE>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/styles.css">
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
<script src="components/json-model.js"></script>
</head>
<body>
<a-scene>
<a-assets>
<a-asset-item id="model" src="models/stockcar.json"></a-asset-item>
</a-assets>
<a-entity json-model="src:#model" scale="0.5 0.5 0.5"></a-entity>
<a-camera position="0 0 20"></a-camera>
<a-light type="point" color="#3d8be6" position="-10 0 0" look-at="#car" intensity="5"></a-light>
<a-light type="hemisphere" color="#33b522" position="-10 0 0" intensity="1"></a-light>
</a-scene>
</body>
</html>
and this is what the console is showing
A-Frame Version: 0.5.0 (Date 10-02-2017, Commit #110055d)
index.js:74three Version: ^0.83.0
index.js:75WebVR Polyfill Version: dmarcos/webvr-polyfill#a02a8089b
json-model.js:7 Uncaught SyntaxError: Unexpected token <
three.js:19590THREE.WebGLRenderer 83
http://127.0.0.1:57153/favicon.ico Failed to load resource: the server responded with a status of 404 (Not Found)
Any help would be greatly appreciated
Firstly, you have an extra "/" at the end of your asset-item opening tag :
<a-asset-item id="model" src="models/stockcar.json"/></a-asset-item>
Secondly, to use the asset you have to state the asset's id in the json-model "src" attribute:
<a-entity json-model="src:#model" scale="0.5 0.5 0.5"></a-entity>
I have an issue using polymer (1.3.1) to define a custom element which is a svg button for a Portal webapp.
Here the code of my custom element :
<link rel="import" href="../../lib/polymer/1.3.1/polymer.html">
<dom-module id="portal-button">
<link rel="import" type="css" href="portal-button.css">
<template>
<svg id="hexagon-button" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="187">
<a xlink:href="#dummy" xlink:href$="{{url}}">
<defs>
<pattern id="dashed-line" height="9" width="9" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="9" height="9" fill="rgb(245,245,245)" />
<line x1="1" y1="9" x2="9" y2="1" stroke="rgb(187,187,187)" stroke-dasharray="2" />
</pattern>
<pattern id="logo" width="100%" height="100%" viewBox="0 0 135 133">
<image id="buttonlogo" width="135" height="133" xlink:href="#dummy" xlink:href$="{{src}}" />
</pattern>
<pattern id="text" width="100%" height="100%" viewBox="0 0 590 76">
<image id="buttontext" width="590" height="76" xlink:href="#dummy" xlink:href$="{{text}}" />
</pattern>
</defs>
<g class="button">
<g class="back">
<path d="M 150,13 L 50,13 0,100 50,187 150,187 200,100 z M 140,31 L 60,31 20,100 60,169 140,169 180,100 z" fill-rule="evenodd" fill="url(#dashed-line)" />
<polygon points="140,31 60,31 20,100 60,169 140,169 180,100" fill="rgb(88,151,162)" />
<polygon points="140,31 60,31 20,100 60,169 140,169 180,100" fill="url(#logo)" />
</g>
<g class="front">
<polygon points="19,100 25,90 175,90 181,100 175,110 25,110" fill="url(#dashed-line)" />
<polygon points="19,100 25,90 175,90 181,100 175,110 25,110" fill="url(#text)" />
</g>
</g>
</a>
</svg>
</template>
</dom-module>
<script>
Polymer({
is: 'portal-button',
properties: {
text: String,
url: String,
src: String
}
});
</script>
A little bit of css to display/hide the front svg element
.back {
fill-opacity: 0.5;
}
.front {
fill-opacity: 0.1;
}
.button:hover > * {
fill-opacity: 1;
}
The index.html with declaration of two instances of my custom element
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Izakiel's Lair</title>
<link rel="icon" href="chaos_symbol.png">
<!-- include polymer html5 polyfill library -->
<script src="lib/webcomponentsjs/0.7.21/webcomponents-lite.js"></script>
<link rel="import" href="components/portal-button/portal-button.html">
</head>
<body>
<portal-button id="virtualmin" url="http://localhost:8080/portal" src="img/virtualmin-logo.svg" text="img/virtualmin-titles.svg"></portal-button>
<portal-button id="jenkins" url="http://localhost:8080/portal" src="img/jenkins-logo.svg" text="img/jenkins-titles.svg"></portal-button>
</body>
</html>
When the page is loaded the rendering is perfectly ok.
When i hover with cursor on a button, the opacity is set to 1 by css, forcing the browser to redraw the button.
When the button is re-rendered, all the information for svg image are rendered with the latest declared element (i.e the jenkins button data in this example) but ll the datas in the DOM are perfectly goods that is weird in my opinion.
Does someone know why the browser set all custom elements rendering with latest element rendering or is it a bug ?
My previous test was done with Chrome, when i try with Firefox it's even worst, all the elements have the rendering of the first element, but datas in the DOM are good. Did i miss something ?
I think your issue is that the patterns are global, not scoped to the shadow root. I tried this with both shady DOM and native shadow root, with the same results.
Here's a partial workaround that fixes the immediate issue on both Chrome and Firefox: create a unique ID for each pattern:
<pattern id="logo-{{id}}" width="100%" height="100%" viewBox="0 0 135 133">
<image id="buttonlogo" width="135" height="133" xlink:href="#dummy" xlink:href$="{{src}}" />
</pattern>
Apply the pattern like this:
<polygon points="140,31 60,31 20,100 60,169 140,169 180,100" fill$="[[_computeFill('#logo', id)]]" />
I found I needed a computed binding here--I think the parens in the url( arg mixed up the binding system, but perhaps I just got something wrong. YMMV. Anyway, the computing function could look like this:
_computeFill: function(name, id) {
return 'url('+ name + '-' + id + ')';
}
You could make this a little more elegant, but this should get you working.
This is a partial workaround because if you re-use an ID, you'll be back to the initial problem of swapping images.
If you wanted to avoid that, you could define a separate library of patterns, identified by ID (like the iron-iconset-svg does for icons). Or as a simpler solution, you could compute a unique ID from the SVG file name.
Hope this helps.