aframe-environment-component
Version:
Infinite environments for your A-Frame VR scene in just one file.
364 lines (333 loc) • 8.07 kB
HTML
<html lang="en">
<head>
<title>LatheGeometry Editor for ThreeJS</title>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
<style>
body {
font: 11px verdana, sans-serif;
line-height: 1.1rem;
}
a {
color: black;
text-decoration: none;
border-bottom: 1px solid black;
}
a:hover {
color: #888;
border-bottom: 1px solid #888;
}
p {
margin: 0;
}
h1 {
margin: 0;
margin-bottom: 1rem;
font-weight: normal;
}
b {
font-weight: normal;
background: #e0e0e0;
padding: 0 2px;
border-radius: 3px;
}
canvas {
width: 500px;
height: 500px;
background: #555;
cursor: default;
}
#c {
grid-column: 2;
-moz-user-select : none;
-khtml-user-select : none;
-webkit-user-select : none;
-o-user-select : none;
user-select : none;
}
#o {
grid-column: 3;
}
footer {
text-align: right;
}
.info {
grid-column-start: 2;
grid-column-end: 4;
}
#log {
grid-column-start: 2;
grid-column-end: 4;
font-family: monospace;
padding: 4px;
}
#all {
margin-top: 30px;
display: grid;
grid-template-columns: auto 500px 500px auto;
grid-template-rows: auto 500px auto ;
grid-column-gap: 30px;
grid-row-gap: 30px;
}
</style>
</head>
<body>
<div id="all">
<div class="info">
<h1>Lathe editor for three.js</h1>
<p>
Place points on left canvas with <b>Left Click</b><br>
Finish contour with <b>Double Click</b>, <b>ENTER</b> or <b>ESC</b><br>
Delete / Add points by hovering on them and pressing <b>DEL</b> / <b>INS</b><br>
Clear canvas with <b>c</b> key
</p>
</div>
<canvas id="c"></canvas>
<canvas id="o"></canvas>
<div id="log"></div>
<footer class="info">
<a href="http://github.com/feiss">GitHub</a>
</footer>
</div>
<script>
var editor = document.getElementById('c')
var three = document.getElementById('o')
editor.width = 500;
editor.height = 500;
var points = []; // list of control points
var m = {x: 0, y: 0}; // mouse position
var drawing = false;
var editing = false;
var hovering = false;
var finished = false;
var F = Math.floor;
var c = editor.getContext('2d');
var W = editor.width;
var H = editor.height;
var W2 = F(W / 2);
var H2 = F(H / 2);
editor.addEventListener('dblclick', dblclick);
editor.addEventListener('mousedown', mousedown);
editor.addEventListener('mouseup', mouseup);
editor.addEventListener('mousemove', mousemove);
window.addEventListener('keydown', keydown);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 40, 1, 0.1, 1000 );
camera.position.z = 25;
camera.position.y = -5;
camera.lookAt(new THREE.Vector3(0, -5, 0));
var renderer = new THREE.WebGLRenderer({canvas: three, antialias: true});
renderer.setSize(W, H);
var light = new THREE.PointLight(0xffffff, 1);
light.position.set(10, 0, 30);
scene.add(light);
var obj = null;
var material = new THREE.MeshPhongMaterial({color: 0xcccccc, side: THREE.DoubleSide});
function renderThree() {
if (obj) {
obj.rotation.y += 0.02;
obj.rotation.x = -Math.PI + Math.sin(performance.now()/1000) * 0.5;
}
requestAnimationFrame( renderThree );
renderer.render(scene, camera);
}
renderThree();
paint();
function dblclick(evt) {
if (finished) return;
// remove last
points.splice(points.length - 1, 1);
drawing = false;
m = null;
finished = true;
}
function mousedown(evt) {
if (hovering === false && !finished) {
m = {x: Math.max(W2 + 0.1, evt.offsetX), y: evt.offsetY};
points.push(m)
drawing = true;
updateObj();
}
else {
editing = hovering;
}
paint();
}
function mouseup(evt) {
if (editing !== false) {
updateObj();
editor.style.cursor = 'default';
}
editing = false;
paint();
}
function mousemove(evt) {
if (drawing || editing !== false) {
m = {x: Math.max(W2 + 0.1, evt.offsetX), y: evt.offsetY};
if (editing !== false) {
points[editing].x = m.x;
points[editing].y = m.y;
}
}
else {
hovering = getControlPoint(evt.offsetX, evt.offsetY);
editor.style.cursor = hovering !== false? 'pointer': 'default';
}
paint();
}
function keydown(evt) {
if (evt.shiftKey || evt.metaKey || evt.ctrlKey || evt.altKey) return;
if (evt.keyCode == 27 || evt.keyCode == 13) { // escape or enter
if (!finished) {
finished = true;
drawing = false;
m = null;
paint();
}
}
else if (evt.keyCode == 67) { // c
finished = false;
drawing = false;
editing = false;
m = null;
points = [];
paint();
updateObj();
}
else if (evt.keyCode == 45) { // insert
var idx = 0;
if (hovering !== false) {
idx = hovering;
}
if (idx == points.length - 1) idx = Math.max(0, points.length - 2);
var p = {
x: (points[idx].x + points[idx + 1].x) / 2,
y: (points[idx].y + points[idx + 1].y) / 2
};
points.splice(idx + 1, 0, p);
paint();
updateObj();
}
else if (evt.keyCode == 46) { // delete
if (hovering !== false) {
points.splice(hovering, 1);
updateObj();
paint();
}
}
}
function getControlPoint(x, y) {
for (var i = 0; i < points.length; i++) {
var dx = points[i].x - x;
var dy = points[i].y - y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 20) {
return i;
}
}
return false;
}
function paint() {
drawBG();
drawPoints();
}
function drawPoints() {
if (points.length == 0) return;
// lines
c.strokeStyle = '#f7f';
c.lineWidth = 2;
c.beginPath();
c.moveTo(points[0].x, points[0].y)
for (var i = 1; i < points.length; i++) {
c.lineTo(points[i].x, points[i].y);
}
c.stroke();
// mirror
c.strokeStyle = '#666';
c.lineWidth = 1;
c.beginPath();
c.moveTo(W - points[0].x , points[0].y)
for (var i = 1; i < points.length; i++) {
c.lineTo(W - points[i].x, points[i].y);
}
c.stroke();
// to current mouse point
if (m && drawing) {
c.strokeStyle = '#bbb';
c.beginPath();
c.moveTo(points[points.length - 1].x, points[ points.length - 1].y)
c.lineTo(m.x, m.y);
c.stroke();
}
// points
c.lineWidth = 2;
c.strokeStyle = '#f3a';
for (var i = 0; i < points.length; i++) {
c.beginPath();
c.arc(points[i].x, points[i].y, hovering === i ? 8 : 2, 0, 2 * Math.PI, false);
c.stroke();
}
}
function drawBG() {
// background
c.fillStyle = '#ddd';
c.fillRect(0, 0, W, H);
// secondary axis
c.lineWidth = 1;
c.strokeStyle = '#ccc';
c.beginPath();
for (var i = 0; i < 10; i++) {
c.moveTo(0, F(W / 10 * i)) ;
c.lineTo(W, F(W / 10 * i));
c.moveTo(F(H / 10 * i), 0);
c.lineTo(F(H / 10 * i), H);
}
c.stroke();
// primary axis
c.setLineDash([]);
c.strokeStyle = '#888';
c.beginPath();
c.moveTo(W2, 0);
c.lineTo(W2, H);
c.moveTo(0, H2);
c.lineTo(W, H2);
c.stroke();
}
function getThreeCoords() {
var coords = [];
for (var i = 0; i < points.length; i ++ ) {
coords.push(new THREE.Vector2(
points[i].x / W - 0.5,
points[i].y / H
));
}
return coords;
}
function updateObj() {
var verts = getThreeCoords();
if (obj) {
scene.remove(obj);
}
var geo = new THREE.LatheGeometry(verts);
obj = new THREE.Mesh(geo, material);
obj.scale.set(10,10,10);
scene.add(obj);
// dump ThreeJS code to <div>
var log = document.getElementById('log');
var list = [];
var dec3 = (v) => Math.floor(v * 1000) / 1000; // trim number to 3 decimals
for (var i = 0; i < verts.length; i++) {
list.push(dec3(verts[i].x), dec3(verts[i].y));
}
html = 'var plist = [' + list.join(', ') + '];<br>';
html += 'var points = [];<br>';
html += 'for (var i = 0; i < plist.length; i += 2) {<br>';
html += ' points.push(new THREE.Vector2(plist[i], plist[i + 1]);<br>';
html += '}<br>';
html += 'var geometry = new THREE.LatheGeometry(points);<br>var material = new THREE.MeshPhongMaterial();<br>var lathe = new THREE.Mesh(geometry, material);<br>scene.add(lathe);';
log.innerHTML = html;
}
</script>
</body>
</html>