Обнаружение вертикальной поверхности в Webxr в Andriod WebarJavascript

Форум по Javascript
Ответить
Anonymous
 Обнаружение вертикальной поверхности в Webxr в Andriod Webar

Сообщение Anonymous »

У меня есть этот код webxr, он правильно обнаруживает пол (горизонтальная поверхность) (после того, как когда -нибудь взял), но его сбой, когда я перемещаю камеру к стене. Я использую Chrome на Andriod. Что я делаю не так? Есть ли способ обнаружить вертикальные поверхности. < /P>

webxr AR обнаружение поверхности

start ar

Пусть сцена, камера, рендеринг, xrsession, xrrefspace;
let HittestSource = null;
let retacle = null;
let glbmodel = null;
// Load GLB model
function loadModel() {
return new Promise((resolve, reject) => {
const loader = new THREE.GLTFLoader();
loader.load(
'ac.glb', // Replace with your GLB file path
(gltf) => {
glbModel = gltf.scene;
// Scale your model if needed
glbModel.scale.set(1, 1, 1);
resolve(glbModel);
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
(error) => {
console.error('Error loading model:', error);
reject(error);
}
);
});
}

async function initAR() {
if (!navigator.xr) {
alert("WebXR not supported on this device!");
return;
}

try {
// Load model before starting AR
await loadModel();

const session = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ["hit-test", "local-floor"],
optionalFeatures: ["dom-overlay"],
domOverlay: { root: document.body }
});

session.addEventListener("end", () => {
xrSession = null;
document.getElementById("startAR").style.display = "block";
});

session.addEventListener("select", placeObjectAtReticle);

xrSession = session;
document.getElementById("startAR").style.display = "none";
setupXRScene(session);
} catch (err) {
console.error("WebXR session failed:", err);
alert("Error starting AR: " + err.message);
}
}

function setupXRScene(session) {
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const gl = canvas.getContext("webgl", { xrCompatible: true });

renderer = new THREE.WebGLRenderer({
alpha: true,
canvas: canvas,
context: gl
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
renderer.xr.setSession(session);

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 100);

// Improved reticle
reticle = new THREE.Group();

const reticleRing = new THREE.Mesh(
new THREE.RingGeometry(0.15, 0.2, 32),
new THREE.MeshBasicMaterial({
color: 0x00ff00,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8,
depthTest: false
})
);

reticle.add(reticleRing);
reticle.visible = false;
scene.add(reticle);

// Multiple hit test sources
/*session.requestReferenceSpace("viewer").then((viewerRefSpace) => {
Promise.all([
session.requestHitTestSource({
space: viewerRefSpace,
offsetRay: new XRRay()
}),
session.requestHitTestSource({
space: viewerRefSpace,
offsetRay: new XRRay({
direction: { x: 0, y: -0.5, z: -1 }
})
}),
session.requestHitTestSource({
space: viewerRefSpace,
offsetRay: new XRRay({
direction: { x: 0, y: 0, z: -1 }
})
})
]).then(sources => {
hitTestSource = sources;
console.log("Hit test sources created successfully");
}).catch(err => {
console.error("Hit test source creation failed:", err);
});
});*/

////another method
session.requestReferenceSpace("viewer").then((viewerRefSpace) => {
Promise.all([
// Default downward hit test (for floors)
session.requestHitTestSource({
space: viewerRefSpace,
offsetRay: new XRRay({ origin: {x: 0, y: 0, z: 0}, direction: {x: 0, y: -0.5, z: -1} })
}),
// Forward ray for detecting walls
session.requestHitTestSource({
space: viewerRefSpace,
offsetRay: new XRRay({ origin: {x: 0, y: 1.5, z: 0}, direction: {x: 0, y: 0, z: -1} }) // Ray at eye level
})
]).then(sources => {
hitTestSource = sources;
console.log("Hit test sources created successfully");
}).catch(err => {
console.error("Hit test source creation failed:", err);
});
< /code>
}); < /p>
///////////

session.requestReferenceSpace("local").then((refSpace) => {
xrRefSpace = refSpace;
session.requestAnimationFrame(onXRFrame);
});
}

function onXRFrame(time, frame) {
frame.session.requestAnimationFrame(onXRFrame);

if (!frame || !xrRefSpace || !hitTestSource) return;

const pose = frame.getViewerPose(xrRefSpace);

if (pose) {
let hitPose = null;

// Check all hit test sources
for (let source of hitTestSource) {
const hitTestResults = frame.getHitTestResults(source);
if (hitTestResults.length > 0) {
hitPose = hitTestResults[0].getPose(xrRefSpace);
break;
}
}

if (hitPose) {
reticle.visible = true;

const matrix = new THREE.Matrix4();
matrix.fromArray(hitPose.transform.matrix);

const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();
matrix.decompose(position, quaternion, scale);

reticle.position.copy(position);
reticle.quaternion.copy(quaternion);

// Calculate surface orientation
const normal = new THREE.Vector3(0, 1, 0);
normal.applyQuaternion(quaternion);
const angleWithVertical = normal.angleTo(new THREE.Vector3(0, 1, 0)) * (180 / Math.PI);

// Update reticle color
const reticleMaterial = reticle.children[0].material;
if (angleWithVertical < 20) {
reticleMaterial.color.setHex(0x00ff00); // Green for horizontal
} else if (angleWithVertical > 70) {
reticleMaterial.color.setHex(0x0000ff); // Blue for vertical
} else {
reticleMaterial.color.setHex(0xffff00); // Yellow for angled
}
} else {
reticle.visible = false;
}
}

renderer.render(scene, camera);
}

function placeObjectAtReticle() {
if (!reticle.visible || !glbModel) return;

const modelClone = glbModel.clone();
modelClone.position.copy(reticle.position);
modelClone.quaternion.copy(reticle.quaternion);

scene.add(modelClone);
}

document.getElementById("startAR").addEventListener("click", initAR);



Подробнее здесь: https://stackoverflow.com/questions/794 ... riod-webar
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»