Complete rewrite - simpler working version
This commit is contained in:
1 parent
e19f5e57ec
commit
7ce1789c73
1 file changed
+130
-180
+130
-180
@@ -5,236 +5,186 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Wireframe Flight Background</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { overflow: hidden; background: #000; }
|
||||
canvas { display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="bgCanvas"></canvas>
|
||||
<canvas id="c"></canvas>
|
||||
<script>
|
||||
const canvas = document.getElementById('bgCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
let width, height;
|
||||
var c = document.getElementById('c');
|
||||
var ctx = c.getContext('2d');
|
||||
var W = 0, H = 0;
|
||||
|
||||
function resize() {
|
||||
width = canvas.width = window.innerWidth;
|
||||
height = canvas.height = window.innerHeight;
|
||||
W = c.width = window.innerWidth;
|
||||
H = c.height = window.innerHeight;
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resize);
|
||||
resize();
|
||||
|
||||
const camera = { fov: 600 };
|
||||
var offX = 0, offY = 0;
|
||||
|
||||
function rotateY(p, angle) {
|
||||
const cos = Math.cos(angle);
|
||||
const sin = Math.sin(angle);
|
||||
return { x: p.x * cos - p.z * sin, y: p.y, z: p.x * sin + p.z * cos };
|
||||
function project(x, y, z) {
|
||||
var scale = 600 / (600 + z);
|
||||
var sx = (x - y) * scale + W / 2;
|
||||
var sy = ((x + y) * 0.5 - z) * scale + H / 2;
|
||||
return [sx, sy];
|
||||
}
|
||||
|
||||
class Point3D {
|
||||
constructor(x, y, z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
function generateTriangle(p1, p2, p3, water) {
|
||||
return { p1: p1, p2: p2, p3: p3, water: water, depth: (p1[2] + p2[2] + p3[2]) / 3 };
|
||||
}
|
||||
|
||||
project() {
|
||||
const scale = camera.fov / (camera.fov + this.z);
|
||||
const xIso = this.x - this.z;
|
||||
const yIso = (this.x + this.z) * 0.5 - this.y;
|
||||
const x2d = xIso * scale + width / 2;
|
||||
const y2d = yIso * scale + height / 2;
|
||||
return { x: x2d, y: y2d };
|
||||
}
|
||||
function getHeight(x, y) {
|
||||
var h = 0;
|
||||
h += Math.sin(x / 200) * 80;
|
||||
h += Math.cos(y / 200) * 80;
|
||||
h += Math.sin(x / 100 + y / 200) * 40;
|
||||
h += Math.cos(y / 100 - x / 200) * 30;
|
||||
return h;
|
||||
}
|
||||
|
||||
class Landscape {
|
||||
constructor() {
|
||||
this.gridSize = 120;
|
||||
this.gridRange = 25;
|
||||
this.offsetX = 0;
|
||||
this.offsetZ = 0;
|
||||
this.triangles = [];
|
||||
this.waterLevel = 20;
|
||||
this.generateTriangles();
|
||||
}
|
||||
var triangles = [];
|
||||
|
||||
generateHeight(x, z) {
|
||||
const nx = x / 300;
|
||||
const nz = z / 300;
|
||||
let y = 0;
|
||||
y += Math.sin(nx * 0.7) * 60;
|
||||
y += Math.cos(nz * 0.7) * 60;
|
||||
y += Math.sin(nx * 1.5 + nz * 0.3) * 30;
|
||||
y += Math.cos(nz * 1.5 - nx * 0.4) * 25;
|
||||
return y;
|
||||
}
|
||||
|
||||
isWater(y) {
|
||||
return y < this.waterLevel;
|
||||
}
|
||||
|
||||
update() {
|
||||
this.offsetX -= 1.5;
|
||||
this.offsetZ -= 0.7;
|
||||
this.generateTriangles();
|
||||
}
|
||||
|
||||
getPoint(x, z) {
|
||||
const worldX = x * this.gridSize + this.offsetX;
|
||||
const worldZ = z * this.gridSize + this.offsetZ;
|
||||
const y = this.generateHeight(worldX, worldZ);
|
||||
return new Point3D(worldX, y, worldZ);
|
||||
}
|
||||
|
||||
generateTriangles() {
|
||||
this.triangles = [];
|
||||
for (let x = -this.gridRange; x <= this.gridRange; x++) {
|
||||
for (let z = -this.gridRange; z <= this.gridRange; z++) {
|
||||
const p1 = this.getPoint(x, z);
|
||||
const p2 = this.getPoint(x + 1, z);
|
||||
const p3 = this.getPoint(x + 1, z + 1);
|
||||
const p4 = this.getPoint(x, z + 1);
|
||||
|
||||
const w = this.isWater(p1.y) || this.isWater(p2.y) || this.isWater(p3.y) || this.isWater(p4.y);
|
||||
|
||||
this.triangles.push({ p1, p2, p3, isWater: w, depth: (p1.z + p2.z + p3.z) / 3 });
|
||||
this.triangles.push({ p1, p3, p4, isWater: w, depth: (p1.z + p3.z + p4.z) / 3 });
|
||||
function generateLandscape() {
|
||||
triangles = [];
|
||||
var range = 25;
|
||||
var size = 100;
|
||||
for (var x = -range; x <= range; x++) {
|
||||
for (var y = -range; y <= range; y++) {
|
||||
var wx = x * size + offX;
|
||||
var wy = y * size + offY;
|
||||
var h1 = getHeight(wx, wy);
|
||||
var h2 = getHeight(wx + size, wy);
|
||||
var h3 = getHeight(wx + size, wy + size);
|
||||
var h4 = getHeight(wx, wy + size);
|
||||
var water = (h1 < 30 || h2 < 30 || h3 < 30 || h4 < 30);
|
||||
var p1 = [wx, h1, wy];
|
||||
var p2 = [wx + size, h2, wy];
|
||||
var p3 = [wx + size, h3, wy + size];
|
||||
var p4 = [wx, h4, wy + size];
|
||||
triangles.push(generateTriangle(p1, p2, p3, water));
|
||||
triangles.push(generateTriangle(p1, p3, p4, water));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.triangles.sort((a, b) => b.depth - a.depth);
|
||||
this.triangles.forEach(tri => {
|
||||
const proj1 = tri.p1.project();
|
||||
const proj2 = tri.p2.project();
|
||||
const proj3 = tri.p3.project();
|
||||
function drawLandscape() {
|
||||
triangles.sort(function(a, b) { return b.depth - a.depth; });
|
||||
for (var i = 0; i < triangles.length; i++) {
|
||||
var t = triangles[i];
|
||||
var p1 = project(t.p1[0], t.p1[2], t.p1[1]);
|
||||
var p2 = project(t.p2[0], t.p2[2], t.p2[1]);
|
||||
var p3 = project(t.p3[0], t.p3[2], t.p3[1]);
|
||||
|
||||
ctx.fillStyle = tri.isWater ? 'rgba(0, 100, 200, 0.9)' : 'rgba(0, 180, 0, 0.9)';
|
||||
ctx.fillStyle = t.water ? 'rgba(0, 80, 200, 0.85)' : 'rgba(0, 160, 0, 0.85)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(proj1.x, proj1.y);
|
||||
ctx.lineTo(proj2.x, proj2.y);
|
||||
ctx.lineTo(proj3.x, proj3.y);
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.lineTo(p3[0], p3[1]);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
ctx.strokeStyle = tri.isWater ? '#00ccff' : '#00ff66';
|
||||
ctx.strokeStyle = t.water ? '#00ccff' : '#00ff66';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
var planeVertices = [];
|
||||
function initPlane() {
|
||||
planeVertices = [];
|
||||
var segs = 8, len = 60, rad = 6;
|
||||
for (var i = 0; i < segs; i++) {
|
||||
var a = (i / segs) * Math.PI * 2;
|
||||
planeVertices.push([Math.cos(a) * rad, 0, Math.sin(a) * rad]);
|
||||
}
|
||||
for (var i = 0; i < segs; i++) {
|
||||
var a = (i / segs) * Math.PI * 2;
|
||||
planeVertices.push([Math.cos(a) * rad, len, Math.sin(a) * rad]);
|
||||
}
|
||||
planeVertices.push([-40, 30, 0]);
|
||||
planeVertices.push([-40, 50, 0]);
|
||||
planeVertices.push([40, 50, 0]);
|
||||
planeVertices.push([40, 30, 0]);
|
||||
}
|
||||
|
||||
var yawT = 0, rollT = 0, pitchT = 0;
|
||||
|
||||
function drawPlane() {
|
||||
var yaw = Math.sin(Date.now() / 1500) * 0.3;
|
||||
var roll = Math.sin(Date.now() / 800) * 0.3;
|
||||
var pitch = Math.cos(Date.now() / 1000) * 0.2;
|
||||
|
||||
var transformed = planeVertices.map(function(v) {
|
||||
var x = v[0], y = v[1], z = v[2];
|
||||
var cy = Math.cos(yaw), sy = Math.sin(yaw);
|
||||
var x1 = x * cy - z * sy;
|
||||
var z1 = x * sy + z * cy;
|
||||
var cr = Math.cos(roll), sr = Math.sin(roll);
|
||||
var x2 = x1 * cr - y * sr;
|
||||
var y1 = x1 * sr + y * cr;
|
||||
var cp = Math.cos(pitch), sp = Math.sin(pitch);
|
||||
var y2 = y1 * cp - z1 * sp;
|
||||
var z2 = y1 * sp + z1 * cp;
|
||||
return [x2, y2 + 120, z2 + 100];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class Airplane {
|
||||
constructor() {
|
||||
this.vertices = [];
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const segments = 8;
|
||||
const fuselageLength = 80;
|
||||
const fuselageRadius = 8;
|
||||
|
||||
for (let i = 0; i < segments; i++) {
|
||||
const angle = (i / segments) * Math.PI * 2;
|
||||
this.vertices.push(new Point3D(
|
||||
Math.cos(angle) * fuselageRadius,
|
||||
Math.sin(angle) * fuselageRadius,
|
||||
0
|
||||
));
|
||||
}
|
||||
|
||||
for (let i = 0; i < segments; i++) {
|
||||
const angle = (i / segments) * Math.PI * 2;
|
||||
this.vertices.push(new Point3D(
|
||||
Math.cos(angle) * fuselageRadius,
|
||||
Math.sin(angle) * fuselageRadius,
|
||||
fuselageLength
|
||||
));
|
||||
}
|
||||
|
||||
const wingSpan = 100;
|
||||
const wingY = -2;
|
||||
this.vertices.push(new Point3D(-wingSpan / 2, wingY, 10));
|
||||
this.vertices.push(new Point3D(-wingSpan / 2 + 5, wingY, 35));
|
||||
this.vertices.push(new Point3D(wingSpan / 2 - 5, wingY, 35));
|
||||
this.vertices.push(new Point3D(wingSpan / 2, wingY, 10));
|
||||
}
|
||||
|
||||
update() {
|
||||
this.yaw = Math.sin(Date.now() / 1000) * 0.15;
|
||||
this.roll = Math.sin(Date.now() / 600) * 0.2;
|
||||
this.pitch = Math.cos(Date.now() / 800) * 0.15;
|
||||
}
|
||||
|
||||
render() {
|
||||
ctx.strokeStyle = '#ff0000';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.shadowBlur = 15;
|
||||
ctx.shadowBlur = 12;
|
||||
ctx.shadowColor = '#ff0000';
|
||||
|
||||
this.vertices.forEach(v => {
|
||||
const proj = v.project();
|
||||
if (!proj) return;
|
||||
ctx.beginPath();
|
||||
ctx.arc(proj.x, proj.y, 4, 0, Math.PI * 2);
|
||||
for (var i = 0; i < transformed.length; i++) {
|
||||
var p = project(transformed[i][0], transformed[i][2], transformed[i][1]);
|
||||
ctx.fillStyle = '#ff0000';
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
for (let i = 0; i < this.vertices.length - 1; i++) {
|
||||
const v1 = this.vertices[i];
|
||||
const v2 = this.vertices[i + 1];
|
||||
if (!v1 || !v2) continue;
|
||||
const p1 = v1.project();
|
||||
const p2 = v2.project();
|
||||
if (!p1 || !p2) continue;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(p1.x, p1.y);
|
||||
ctx.lineTo(p2.x, p2.y);
|
||||
ctx.arc(p[0], p[1], 3, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
for (var i = 0; i < transformed.length - 1; i++) {
|
||||
if (i >= 7 && i <= 10) continue;
|
||||
var p1 = project(transformed[i][0], transformed[i][2], transformed[i][1]);
|
||||
var p2 = project(transformed[i + 1][0], transformed[i + 1][2], transformed[i + 1][1]);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
for (var i = 7; i <= 10; i++) {
|
||||
var j = (i + 1 > 10) ? 7 : i + 1;
|
||||
var p1 = project(transformed[i][0], transformed[i][2], transformed[i][1]);
|
||||
var p2 = project(transformed[j][0], transformed[j][2], transformed[j][1]);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.shadowBlur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const landscape = new Landscape();
|
||||
const airplane = new Airplane();
|
||||
initPlane();
|
||||
|
||||
function animate() {
|
||||
function frame() {
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
|
||||
landscape.update();
|
||||
landscape.draw();
|
||||
offX -= 1.5;
|
||||
offY -= 0.7;
|
||||
generateLandscape();
|
||||
drawLandscape();
|
||||
|
||||
airplane.update();
|
||||
airplane.render();
|
||||
drawPlane();
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
animate();
|
||||
frame();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user