Информация об устройстве: Android 9; HUAIWEI COL-AL10; Chrome 80.0.3987.99
Я работаю над применением A-Frame к моему HMD на основе мобильного телефона с моей индивидуальной ориентацией камеры и искажением.
Однако после того, как я изменил искажающее устройство карты (CardboardDistorter. prototype.computeMeshVertices_ в строке 63069 в рамке. js) и запустите сэмплы, искажение все еще использует искажение картбад. В то время как я изменил тот же самый искажатель в webvr-polyfill js, новое искажение работает для меня. И когда я использую другие телефоны для тестирования своей демонстрации в режиме «a-frame», новое искажение также работает ...... Похоже, что «a-frame» рассматривает мой телефон как собственное VR-устройство, поэтому оно запускает службу Google VR в бэкэнде ... .
Как включить новое искажение, которое я изменил в CardboardDistorter? Мне нужно запустить WebVR-polyfill ПРЯМО на моем телефоне. Недавно я создал несколько игр VR для единства, основанных на Google VR. Может быть, они сделали мой телефон «родным устройством Google VR»?
картонное искажение: картонное искажение
мой тестовое искажение (при использовании полифилла оно должно отображаться так): новое искажение
Вот мое новое искажение для теста:
CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {
var vertices = new Float32Array(2 * width * height * 5);
var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();
var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();
var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);
var vidx = 0;
for (var e = 0; e < 2; e++) {
for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++, vidx++) {
var u = i / (width - 1);
var v = j / (height - 1);
var s = u;
var t = v;
var x = lerp(lensFrustum[0], lensFrustum[2], u);
var y = lerp(lensFrustum[3], lensFrustum[1], v);
var d = Math.sqrt(x * x + y * y);
var r = deviceInfo.distortion.distortInverse(d);
var p = x * r / d;
var q = y * r / d;
// test distortion
u = u - 0.5;
v = v - 0.5;
u = u * (v + 0.7);
v = v * 0.7;
u = u + 0.5;
v = v + 0.5;
//u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);
//v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);
u = (viewport.x + u * viewport.width - 0.5) * 2.0;
v = (viewport.y + v * viewport.height - 0.5) * 2.0;
vertices[vidx * 5 + 0] = u;
vertices[vidx * 5 + 1] = v;
vertices[vidx * 5 + 2] = s;
vertices[vidx * 5 + 3] = t;
vertices[vidx * 5 + 4] = e;
}
}
var w = lensFrustum[2] - lensFrustum[0];
lensFrustum[0] = -(w + lensFrustum[0]);
lensFrustum[2] = w - lensFrustum[2];
w = noLensFrustum[2] - noLensFrustum[0];
noLensFrustum[0] = -(w + noLensFrustum[0]);
noLensFrustum[2] = w - noLensFrustum[2];
viewport.x = 1 - (viewport.x + viewport.width);
}
return vertices;
};
Вот что я пробовал : Строка 3511
function shouldUseNative() {
return false;
}
Строка 80341
window.hasNativeWebVRImplementation = false;
window.hasNativeWebXRImplementation = false;
[ОБНОВЛЕНИЕ] Я считаю, что A-Frame 0.9.2 напрямую использует polyfill, а с 1.0.0 он использует собственный сервис Google VR для display.
enterVR: {
value: function (useAR) {
var self = this;
var vrDisplay;
var vrManager = self.renderer.xr;
// Don't enter VR if already in VR.
if (this.is('vr-mode')) { return Promise.resolve('Already in VR.'); }
// Has VR.
if (this.checkHeadsetConnected() || this.isMobile) {
vrDisplay = utils.device.getVRDisplay();
vrManager.enabled = true;
vrManager.setDevice(vrDisplay);
if (this.hasWebXR) {
// XR API.
if (this.xrSession) {
this.xrSession.removeEventListener('end', this.exitVRBound);
}
navigator.xr.requestSession(useAR ? 'immersive-ar' : 'immersive-vr', {
requiredFeatures: ['local-floor'],
optionalFeatures: ['bounded-floor']
}).then(function requestSuccess (xrSession) {
self.xrSession = xrSession;
vrManager.setSession(xrSession);
xrSession.addEventListener('end', self.exitVRBound);
if (useAR) {
self.addState('ar-mode');
}
enterVRSuccess();
});
} else {
vrDisplay = utils.device.getVRDisplay();
vrManager.setDevice(vrDisplay);
if (vrDisplay.isPresenting &&
!window.hasNativeWebVRImplementation) {
enterVRSuccess();
return Promise.resolve();
}
var rendererSystem = this.getAttribute('renderer');
var presentationAttributes = {
highRefreshRate: rendererSystem.highRefreshRate,
foveationLevel: rendererSystem.foveationLevel
};
return vrDisplay.requestPresent([{
source: this.canvas,
attributes: presentationAttributes
}]).then(enterVRSuccess, enterVRFailure);
}
return Promise.resolve();
}
// No VR.
enterVRSuccess();
return Promise.resolve();
// Callback that happens on enter VR success or enter fullscreen (any API).
function enterVRSuccess () {
// vrdisplaypresentchange fires only once when the first requestPresent is completed;
// the first requestPresent could be called from ondisplayactivate and there is no way
// to setup everything from there. Thus, we need to emulate another vrdisplaypresentchange
// for the actual requestPresent. Need to make sure there are no issues with firing the
// vrdisplaypresentchange multiple times.
var event;
if (window.hasNativeWebVRImplementation && !window.hasNativeWebXRImplementation) {
event = new CustomEvent('vrdisplaypresentchange', {detail: {display: utils.device.getVRDisplay()}});
window.dispatchEvent(event);
}
self.addState('vr-mode');
self.emit('enter-vr', {target: self});
// Lock to landscape orientation on mobile.
if (!isWebXRAvailable && self.isMobile && screen.orientation && screen.orientation.lock) {
screen.orientation.lock('landscape');
}
self.addFullScreenStyles();
// On mobile, the polyfill handles fullscreen.
// TODO: 07/16 Chromium builds break when `requestFullscreen`ing on a canvas
// that we are also `requestPresent`ing. Until then, don't fullscreen if headset
// connected.
if (!self.isMobile && !self.checkHeadsetConnected()) {
requestFullscreen(self.canvas);
}
self.renderer.setAnimationLoop(self.render);
self.resize();
}
function enterVRFailure (err) {
if (err && err.message) {
throw new Error('Failed to enter VR mode (`requestPresent`): ' + err.message);
} else {
throw new Error('Failed to enter VR mode (`requestPresent`).');
}
}
},
writable: true
},
Я обнаружил, что в 0.9.2 this.hasXR = false и в 1.0.0 this.hasXR = true. Поэтому в 1.0.0 я устанавливаю это значение в false, а затем в else {} говорится, что vrDisplay.isPresenting не определен. Похоже, что vrDisplay = utils.device.getVRDisplay (); не может получить правильное значение, как в 0.9.2. Затем я нахожу этот код:
function getVRDisplay () { return vrDisplay; }
Для правильного возврата vrDisplay я попытался изменить приведенные выше коды:
if (false) {
var updateEnterInterfaces = function () {
var sceneEl = document.querySelector('a-scene');
if (sceneEl.hasLoaded) {
sceneEl.components['vr-mode-ui'].updateEnterInterfaces();
} else {
sceneEl.addEventListener('loaded', updateEnterInterfaces);
}
};
var errorHandler = function (err) {
error('WebXR session support error: ' + err.message);
};
if (navigator.xr.isSessionSupported) {
// Current WebXR spec uses a boolean-returning isSessionSupported promise
navigator.xr.isSessionSupported('immersive-vr').then(function (supported) {
supportsVRSession = supported;
updateEnterInterfaces();
}).catch(errorHandler);
navigator.xr.isSessionSupported('immersive-ar').then(function (supported) {
supportsARSession = supported;
updateEnterInterfaces();
}).catch(function () {});
} else if (navigator.xr.supportsSession) {
// Fallback for implementations that haven't updated to the new spec yet,
// the old version used supportsSession which is rejected for missing
// support.
navigator.xr.supportsSession('immersive-vr').then(function () {
supportsVRSession = true;
updateEnterInterfaces();
}).catch(errorHandler);
navigator.xr.supportsSession('immersive-ar').then(function () {
supportsARSession = true;
updateEnterInterfaces();
}).catch(function () {});
} else {
error('WebXR has neither isSessionSupported or supportsSession?!');
}
} else {
console.log('navigator.getVRDisplays',!!navigator.getVRDisplays);
if (navigator.getVRDisplays) {
navigator.getVRDisplays().then(function (displays) {
console.log('displays[0]',displays[0]);
var sceneEl = document.querySelector('a-scene');
vrDisplay = displays.length && displays[0];
console.log(vrDisplay);
if (sceneEl) { sceneEl.emit('displayconnected', {vrDisplay: vrDisplay}); }
});
}
}
Тогда vrDisplay имеет правильное значение (CardboardVRDisplay). Однако, таким образом, когда я вхожу в режим VR, экран становится черным. После сравнения vrDisplay между 0.9.2 и 1.0.0 я обнаружил, что искажение vrDisplay равно нулю в 1.0.0.
Я думаю, что ключевой момент - vrDisplay = utils.device.getVRDisplay () в Введите VR , но я не знаю, как решить эту проблему, надеюсь, кто-нибудь сможет увидеть этот вопрос и помочь этому бедному новичку ie ..