|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<title>A-Frame 3D Editor with Animated Rotation</title> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script> |
|
<style> |
|
.ui-panel { |
|
position: fixed; |
|
top: 20px; |
|
left: 20px; |
|
z-index: 9999; |
|
background: rgba(0,0,0,0.7); |
|
padding: 10px; |
|
border-radius: 5px; |
|
color: white; |
|
font-family: Arial, sans-serif; |
|
} |
|
.ui-panel button { |
|
display: block; |
|
margin: 5px 0; |
|
padding: 5px 10px; |
|
} |
|
.control-panel { |
|
position: fixed; |
|
top: 20px; |
|
right: 20px; |
|
z-index: 9999; |
|
background: rgba(0,0,0,0.7); |
|
padding: 10px; |
|
border-radius: 5px; |
|
color: white; |
|
font-family: Arial, sans-serif; |
|
} |
|
.control-panel input { |
|
width: 50px; |
|
margin-right: 5px; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="ui-panel"> |
|
<button onclick="addPrimitive('box')">Add Box</button> |
|
<button onclick="addPrimitive('sphere')">Add Sphere</button> |
|
<button onclick="addPrimitive('cylinder')">Add Cylinder</button> |
|
<button onclick="addPrimitive('cone')">Add Cone</button> |
|
<button onclick="addPrimitive('torus')">Add Torus</button> |
|
</div> |
|
|
|
<div class="control-panel"> |
|
<h3>Object Controls</h3> |
|
<p>Position:</p> |
|
<input id="px" type="number" step="0.1" placeholder="X"> |
|
<input id="py" type="number" step="0.1" placeholder="Y"> |
|
<input id="pz" type="number" step="0.1" placeholder="Z"> |
|
<p>Rotation (degrees):</p> |
|
<input id="rx" type="number" step="1" placeholder="X"> |
|
<input id="ry" type="number" step="1" placeholder="Y"> |
|
<input id="rz" type="number" step="1" placeholder="Z"> |
|
<p>Rotation Velocity (degrees/second):</p> |
|
<input id="rvx" type="number" step="1" placeholder="X"> |
|
<input id="rvy" type="number" step="1" placeholder="Y"> |
|
<input id="rvz" type="number" step="1" placeholder="Z"> |
|
<button onclick="applyTransform()">Apply Transform</button> |
|
<button onclick="placeInFrontOfCamera()">Place in Front of Camera</button> |
|
</div> |
|
|
|
<a-scene> |
|
<a-sky color="#ECECEC"></a-sky> |
|
<a-entity id="rig" position="0 1.6 0"> |
|
<a-camera look-controls wasd-controls> |
|
<a-cursor></a-cursor> |
|
</a-camera> |
|
</a-entity> |
|
</a-scene> |
|
|
|
<script> |
|
let selectedObject = null; |
|
let objects = []; |
|
|
|
function addPrimitive(type) { |
|
const scene = document.querySelector('a-scene'); |
|
const newEntity = document.createElement('a-entity'); |
|
newEntity.setAttribute('geometry', `primitive: ${type}`); |
|
newEntity.setAttribute('material', 'color: #4CC3D9'); |
|
newEntity.setAttribute('class', 'editable'); |
|
newEntity.addEventListener('click', function() { selectObject(this); }); |
|
newEntity.rotationVelocity = { x: 0, y: 30, z: 0 }; |
|
scene.appendChild(newEntity); |
|
objects.push(newEntity); |
|
placeInFrontOfCamera(newEntity); |
|
} |
|
|
|
function selectObject(obj) { |
|
if (selectedObject) { |
|
selectedObject.setAttribute('material', 'color', '#4CC3D9'); |
|
} |
|
selectedObject = obj; |
|
selectedObject.setAttribute('material', 'color', '#FF0000'); |
|
updateTransformInputs(selectedObject); |
|
} |
|
|
|
function updateTransformInputs(obj) { |
|
const position = obj.getAttribute('position'); |
|
document.getElementById('px').value = position.x.toFixed(2); |
|
document.getElementById('py').value = position.y.toFixed(2); |
|
document.getElementById('pz').value = position.z.toFixed(2); |
|
|
|
const rotation = obj.getAttribute('rotation'); |
|
document.getElementById('rx').value = rotation.x.toFixed(2); |
|
document.getElementById('ry').value = rotation.y.toFixed(2); |
|
document.getElementById('rz').value = rotation.z.toFixed(2); |
|
|
|
document.getElementById('rvx').value = obj.rotationVelocity.x; |
|
document.getElementById('rvy').value = obj.rotationVelocity.y; |
|
document.getElementById('rvz').value = obj.rotationVelocity.z; |
|
} |
|
|
|
function applyTransform() { |
|
if (!selectedObject) { |
|
alert('Please select an object first'); |
|
return; |
|
} |
|
|
|
const px = parseFloat(document.getElementById('px').value) || 0; |
|
const py = parseFloat(document.getElementById('py').value) || 0; |
|
const pz = parseFloat(document.getElementById('pz').value) || 0; |
|
const rx = parseFloat(document.getElementById('rx').value) || 0; |
|
const ry = parseFloat(document.getElementById('ry').value) || 0; |
|
const rz = parseFloat(document.getElementById('rz').value) || 0; |
|
const rvx = parseFloat(document.getElementById('rvx').value) || 0; |
|
const rvy = parseFloat(document.getElementById('rvy').value) || 0; |
|
const rvz = parseFloat(document.getElementById('rvz').value) || 0; |
|
|
|
selectedObject.setAttribute('position', `${px} ${py} ${pz}`); |
|
selectedObject.setAttribute('rotation', `${rx} ${ry} ${rz}`); |
|
selectedObject.rotationVelocity = { x: rvx, y: rvy, z: rvz }; |
|
} |
|
|
|
function placeInFrontOfCamera(obj = null) { |
|
const targetObject = obj || selectedObject; |
|
if (!targetObject) { |
|
alert('Please select an object first'); |
|
return; |
|
} |
|
|
|
const camera = document.querySelector('[camera]'); |
|
const cameraPosition = camera.object3D.position; |
|
const cameraRotation = camera.object3D.rotation; |
|
|
|
|
|
const direction = new THREE.Vector3(0, 0, -1); |
|
direction.applyQuaternion(camera.object3D.quaternion); |
|
|
|
|
|
const distance = 3; |
|
|
|
|
|
const newPosition = new THREE.Vector3( |
|
cameraPosition.x + direction.x * distance, |
|
cameraPosition.y + direction.y * distance, |
|
cameraPosition.z + direction.z * distance |
|
); |
|
|
|
targetObject.setAttribute('position', newPosition); |
|
|
|
|
|
if (targetObject === selectedObject) { |
|
updateTransformInputs(targetObject); |
|
} |
|
} |
|
|
|
function animateObjects() { |
|
objects.forEach(obj => { |
|
const currentRotation = obj.getAttribute('rotation'); |
|
const newRotation = { |
|
x: (currentRotation.x + obj.rotationVelocity.x * 0.016) % 360, |
|
y: (currentRotation.y + obj.rotationVelocity.y * 0.016) % 360, |
|
z: (currentRotation.z + obj.rotationVelocity.z * 0.016) % 360 |
|
}; |
|
obj.setAttribute('rotation', newRotation); |
|
}); |
|
requestAnimationFrame(animateObjects); |
|
} |
|
|
|
|
|
document.querySelector('a-scene').addEventListener('click', (event) => { |
|
if (event.detail.intersectedEl && event.detail.intersectedEl.classList.contains('editable')) { |
|
selectObject(event.detail.intersectedEl); |
|
} |
|
}); |
|
|
|
|
|
animateObjects(); |
|
</script> |
|
</body> |
|
</html> |