junkerstock
 vrb-test71


<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<title>Babylon.js - Interactive Cylinders Scene</title>
<script src="https://preview.babylonjs.com/babylon.js"></script>
<style>
html, body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
}
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>


<script>
window.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('renderCanvas');
const engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });

const createScene = async function() {
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3.FromHexString("#ECECEC");

// --- カメラ設定 ---
const pcCamera = new BABYLON.UniversalCamera("pcCamera", new BABYLON.Vector3(0, 1.6, 5), scene);
pcCamera.setTarget(BABYLON.Vector3.Zero());
pcCamera.attachControl(canvas, true);
pcCamera.speed = 0.15;
pcCamera.keysUp = [87, 38];
pcCamera.keysDown = [83, 40];
pcCamera.keysLeft = [65, 37];
pcCamera.keysRight = [68, 39];
pcCamera.angularSensibility = 2000;

// --- 光源 ---
const ambientLight = new BABYLON.HemisphericLight("ambientLight", new BABYLON.Vector3(0, 1, 0), scene);
ambientLight.intensity = 0.8;
const directionalLight = new BABYLON.DirectionalLight("dirLight", new BABYLON.Vector3(-1, 1.5, 1), scene);
directionalLight.intensity = 0.8;

// --- 情報パネル ---
const panelWidth = 2.5;
const panelHeight = 1.2;
const infoPanel = BABYLON.MeshBuilder.CreatePlane("infoPanel", { width: panelWidth, height: panelHeight }, scene);
infoPanel.material = new BABYLON.StandardMaterial("panelMat", scene);
infoPanel.material.backFaceCulling = false;
infoPanel.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL;
infoPanel.isVisible = false;

const textureResolution = 512;
const panelTexture = new BABYLON.DynamicTexture(
"panelTexture",
{ width: textureResolution, height: Math.round(textureResolution * (panelHeight / panelWidth)) },
scene,
true
);
infoPanel.material.diffuseTexture = panelTexture;
infoPanel.material.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);

function updatePanelText(text) {
const ctx = panelTexture.getContext();
const size = panelTexture.getSize();
const fontSize = 28;
const font = `bold ${fontSize}px sans-serif`;
const lines = text.split('\n');
ctx.fillStyle = "#333333";
ctx.fillRect(0, 0, size.width, size.height);
ctx.font = font;
ctx.fillStyle = "white";
lines.forEach((line, index) => {
const y = 50 + index * (fontSize + 15);
ctx.fillText(line, 25, y);
});
panelTexture.update();
}

// --- シリンダー生成 ---
const numCylinders = 30;
const spread = 20;
for (let i = 0; i < numCylinders; i++) {
const radius = Math.random() * 0.4 + 0.2;
const height = Math.random() * 1.5 + 0.5;

const cylinder = BABYLON.MeshBuilder.CreateCylinder(`cylinder${i}`, {
diameter: radius * 2,
height: height,
tessellation: 24
}, scene);

const x = (Math.random() - 0.5) * spread;
const y = Math.random() * (spread / 2) + height / 2;
const z = (Math.random() - 0.5) * spread;
cylinder.position = new BABYLON.Vector3(x, y, z);

cylinder.material = new BABYLON.StandardMaterial(`mat${i}`, scene);
const hue = Math.random() * 360;
const saturation = 0.7;
const value = 0.95;
cylinder.material.diffuseColor = BABYLON.Color3.FromHSV(hue, saturation, value);

cylinder.metadata = {
info: `シリンダー ${i + 1}\n色: HSV(${Math.round(hue)}, ${Math.round(saturation * 100)}%, ${Math.round(value * 100)}%)\n半径: ${radius.toFixed(2)}\n高さ: ${height.toFixed(2)}`
};
}

// --- クリックでパネル表示 ---
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit && pickResult.pickedMesh && pickResult.pickedMesh.metadata) {
const clickedMesh = pickResult.pickedMesh;
const targetWorldPosition = clickedMesh.getWorldMatrix().getTranslation();
const cameraWorldPosition = scene.activeCamera.globalPosition;
const meshRadius = clickedMesh.getBoundingInfo().boundingSphere.radius;
const offsetDistance = meshRadius + 0.8;
const direction = cameraWorldPosition.subtract(targetWorldPosition).normalize();
const panelPosition = targetWorldPosition.add(direction.scale(offsetDistance));
infoPanel.position.copyFrom(panelPosition);
updatePanelText(clickedMesh.metadata.info);
infoPanel.isVisible = true;
} else {
infoPanel.isVisible = false;
}
};

// --- WebXR対応(元のまま) ---
const xr = await scene.createDefaultXRExperienceAsync({});
xr.baseExperience.onStateChangedObservable.add((state) => {
if (state === BABYLON.WebXRState.IN_XR) {
pcCamera.detachControl();
} else if (state === BABYLON.WebXRState.NOT_IN_XR) {
pcCamera.attachControl(canvas, true);
}
});

scene.onBeforeRenderObservable.add(() => {
if (xr.baseExperience.state !== BABYLON.WebXRState.IN_XR) return;
const deltaMillis = engine.getDeltaTime();
const xrCamera = xr.baseExperience.camera;

const leftController = xr.input.controllers.find(c => c.inputSource.handedness === 'left');
if (leftController?.motionController) {
const thumbstick = leftController.motionController.getComponent("xr-standard-thumbstick");
if (thumbstick?.axes) {
const moveSpeed = 1.2 * deltaMillis / 1000;
const forward = xrCamera.getDirection(BABYLON.Vector3.Forward());
forward.y = 0;
xrCamera.position.addInPlace(forward.normalize().scale(-thumbstick.axes.y * moveSpeed));
const right = xrCamera.getDirection(BABYLON.Vector3.Right());
xrCamera.position.addInPlace(right.scale(thumbstick.axes.x * moveSpeed));
}
}

const rightController = xr.input.controllers.find(c => c.inputSource.handedness === 'right');
if (rightController?.motionController) {
const thumbstick = rightController.motionController.getComponent("xr-standard-thumbstick");
if (thumbstick?.axes) {
const rotationThreshold = 0.2;
if (Math.abs(thumbstick.axes.x) > rotationThreshold) {
const rotSpeed = 0.4 * deltaMillis / 1000;
if (xrCamera.parent) {
xrCamera.parent.rotate(BABYLON.Vector3.Up(), thumbstick.axes.x * rotSpeed, BABYLON.Space.WORLD);
}
}
if (Math.abs(thumbstick.axes.y) > rotationThreshold) {
const verticalSpeed = 2.0 * deltaMillis / 1000;
xrCamera.position.y += -thumbstick.axes.y * verticalSpeed;
}
}
}
});

return scene;
};

createScene().then(scene => {
engine.runRenderLoop(() => scene.render());
window.addEventListener('resize', () => engine.resize());
});
});
</script>


</body>
</html>

</body>
</html>