From 09f1e9a1cb3f9a93d61f1510f80c46264c84209c Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Tue, 6 Oct 2026 16:43:03 +0200 Subject: [PATCH] Perspective view with horizon --- assets/index.html | 108 ++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/assets/index.html b/assets/index.html index b5ee323..6bd7f4c 100644 --- a/assets/index.html +++ b/assets/index.html @@ -24,25 +24,24 @@ window.addEventListener('resize', resize); resize(); - var offX = 0, offY = 0; + var offX = 0, offZ = 0; 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; + var fov = 800; + var scale = fov / (fov + z); + var isoX = (x - y) * 0.5; + var isoY = ((x + y) * 0.5) - z; + var sx = isoX * scale + W / 2; + var sy = isoY * scale + H / 2; return [sx, sy]; } - function generateTriangle(p1, p2, p3, water) { - return { p1: p1, p2: p2, p3: p3, water: water, depth: (p1[2] + p2[2] + p3[2]) / 3 }; - } - - function getHeight(x, y) { + function getHeight(x, z) { var h = 0; - h += Math.sin(x / 300) * 50; - h += Math.cos(y / 300) * 50; - h += Math.sin(x / 150 + y / 300) * 25; - h += Math.cos(y / 150 - x / 300) * 20; + h += Math.sin(x / 200) * 60; + h += Math.cos(z / 200) * 60; + h += Math.sin(x / 100 + z / 200) * 30; + h += Math.cos(z / 100 - x / 200) * 25; return h; } @@ -53,20 +52,20 @@ var range = 25; var size = 100; for (var x = -range; x <= range; x++) { - for (var y = -range; y <= range; y++) { + for (var z = -range; z <= range; z++) { 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 wz = z * size + offZ; + var h1 = getHeight(wx, wz); + var h2 = getHeight(wx + size, wz); + var h3 = getHeight(wx + size, wz + size); + var h4 = getHeight(wx, wz + 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)); + var p1 = [wx, h1, wz]; + var p2 = [wx + size, h2, wz]; + var p3 = [wx + size, h3, wz + size]; + var p4 = [wx, h4, wz + size]; + triangles.push({ p1: p1, p2: p2, p3: p3, water: water, depth: (p1[2] + p2[2] + p3[2]) / 3 }); + triangles.push({ p1: p1, p2: p3, p3: p4, water: water, depth: (p1[2] + p3[2] + p4[2]) / 3 }); } } } @@ -75,9 +74,11 @@ 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]); + var p1 = project(t.p1[0], t.p1[1], t.p1[2]); + var p2 = project(t.p2[0], t.p2[1], t.p2[2]); + var p3 = project(t.p3[0], t.p3[1], t.p3[2]); + + if (p1[1] < -200 || p1[1] > H + 200) continue; ctx.fillStyle = t.water ? 'rgba(0, 80, 200, 0.85)' : 'rgba(0, 160, 0, 0.85)'; ctx.beginPath(); @@ -93,6 +94,16 @@ } } + function drawHorizon() { + var hY = H / 2 - 50; + ctx.strokeStyle = 'rgba(255, 200, 100, 0.3)'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(0, hY); + ctx.lineTo(W, hY); + ctx.stroke(); + } + var planeVertices = []; function initPlane() { planeVertices = []; @@ -111,12 +122,10 @@ planeVertices.push([40, 30, 0]); } - var yawT = 0, rollT = 0, pitchT = 0; - function drawPlane() { var yaw = -0.4; var roll = 0; - var pitch = 0.2; + var pitch = 0.15; var transformed = planeVertices.map(function(v) { var x = v[0], y = v[1], z = v[2]; @@ -138,27 +147,42 @@ ctx.shadowColor = '#ff0000'; for (var i = 0; i < transformed.length; i++) { - var p = project(transformed[i][0], transformed[i][2], transformed[i][1]); + var p = project(transformed[i][0], transformed[i][1], transformed[i][2]); ctx.fillStyle = '#ff0000'; ctx.beginPath(); 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]); + for (var i = 0; i < 7; i++) { + var p1 = project(transformed[i][0], transformed[i][1], transformed[i][2]); + var p2 = project(transformed[i + 1][0], transformed[i + 1][1], transformed[i + 1][2]); + ctx.beginPath(); + ctx.moveTo(p1[0], p1[1]); + ctx.lineTo(p2[0], p2[1]); + ctx.stroke(); + } + ctx.beginPath(); + var pFirst = project(transformed[0][0], transformed[0][1], transformed[0][2]); + var pLast = project(transformed[7][0], transformed[7][1], transformed[7][2]); + ctx.moveTo(pFirst[0], pFirst[1]); + ctx.lineTo(pLast[0], pLast[1]); + ctx.stroke(); + + for (var i = 8; i <= 11; i++) { + var j = (i + 1 > 11) ? 8 : i + 1; + var p1 = project(transformed[i][0], transformed[i][1], transformed[i][2]); + var p2 = project(transformed[j][0], transformed[j][1], transformed[j][2]); 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]); + for (var i = 12; i <= 15; i++) { + var j = (i + 1 > 15) ? 12 : i + 1; + var p1 = project(transformed[i][0], transformed[i][1], transformed[i][2]); + var p2 = project(transformed[j][0], transformed[j][1], transformed[j][2]); ctx.beginPath(); ctx.moveTo(p1[0], p1[1]); ctx.lineTo(p2[0], p2[1]); @@ -175,10 +199,10 @@ ctx.fillRect(0, 0, W, H); offX -= 1.5; - offY -= 0.7; + offZ -= 0.7; generateLandscape(); drawLandscape(); - + drawHorizon(); drawPlane(); requestAnimationFrame(frame);