193 lines
5.2 KiB
Text
193 lines
5.2 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# perspective projection\n",
|
|
"\n",
|
|
"```\n",
|
|
"x' = x / z\n",
|
|
"y' = y / z\n",
|
|
"```\n",
|
|
"\n",
|
|
"divide by distance. that's it."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# a cube: 8 vertices, 12 edges\n",
|
|
"\n",
|
|
"vertices = [\n",
|
|
" (-1, -1, -1),\n",
|
|
" ( 1, -1, -1),\n",
|
|
" ( 1, 1, -1),\n",
|
|
" (-1, 1, -1),\n",
|
|
" (-1, -1, 1),\n",
|
|
" ( 1, -1, 1),\n",
|
|
" ( 1, 1, 1),\n",
|
|
" (-1, 1, 1),\n",
|
|
"]\n",
|
|
"\n",
|
|
"edges = [\n",
|
|
" (0, 1), (1, 2), (2, 3), (3, 0), # front\n",
|
|
" (4, 5), (5, 6), (6, 7), (7, 4), # back\n",
|
|
" (0, 4), (1, 5), (2, 6), (3, 7), # connecting\n",
|
|
"]\n",
|
|
"\n",
|
|
"print(f\"{len(vertices)} vertices, {len(edges)} edges\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# the formula\n",
|
|
"\n",
|
|
"def project(x, y, z):\n",
|
|
" return (x / z, y / z)\n",
|
|
"\n",
|
|
"# example: a point at (2, 1, 4)\n",
|
|
"x, y, z = 2, 1, 4\n",
|
|
"x_proj, y_proj = project(x, y, z)\n",
|
|
"\n",
|
|
"print(f\"3d point: ({x}, {y}, {z})\")\n",
|
|
"print(f\"2d projection: ({x_proj}, {y_proj})\")\n",
|
|
"print(f\"\\nfarther away = smaller on screen\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# static cube\n",
|
|
"\n",
|
|
"from IPython.display import HTML\n",
|
|
"\n",
|
|
"HTML(\"\"\"\n",
|
|
"<canvas id=\"static\" width=\"300\" height=\"300\" style=\"background:#111\"></canvas>\n",
|
|
"<script>\n",
|
|
"(function() {\n",
|
|
" const canvas = document.getElementById('static');\n",
|
|
" const ctx = canvas.getContext('2d');\n",
|
|
" const w = canvas.width, h = canvas.height;\n",
|
|
" \n",
|
|
" const vertices = [\n",
|
|
" [-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1],\n",
|
|
" [-1,-1, 1], [1,-1, 1], [1,1, 1], [-1,1, 1]\n",
|
|
" ];\n",
|
|
" const edges = [\n",
|
|
" [0,1],[1,2],[2,3],[3,0],\n",
|
|
" [4,5],[5,6],[6,7],[7,4],\n",
|
|
" [0,4],[1,5],[2,6],[3,7]\n",
|
|
" ];\n",
|
|
" \n",
|
|
" function project(x, y, z) {\n",
|
|
" z += 4; // push back so z > 0\n",
|
|
" return [x/z * 100 + w/2, y/z * 100 + h/2];\n",
|
|
" }\n",
|
|
" \n",
|
|
" ctx.strokeStyle = '#0f0';\n",
|
|
" ctx.lineWidth = 2;\n",
|
|
" \n",
|
|
" for (const [i, j] of edges) {\n",
|
|
" const [x1, y1] = project(...vertices[i]);\n",
|
|
" const [x2, y2] = project(...vertices[j]);\n",
|
|
" ctx.beginPath();\n",
|
|
" ctx.moveTo(x1, y1);\n",
|
|
" ctx.lineTo(x2, y2);\n",
|
|
" ctx.stroke();\n",
|
|
" }\n",
|
|
"})();\n",
|
|
"</script>\n",
|
|
"\"\"\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# spinning cube\n",
|
|
"\n",
|
|
"from IPython.display import HTML\n",
|
|
"\n",
|
|
"HTML(\"\"\"\n",
|
|
"<canvas id=\"spin\" width=\"300\" height=\"300\" style=\"background:#111\"></canvas>\n",
|
|
"<script>\n",
|
|
"(function() {\n",
|
|
" const canvas = document.getElementById('spin');\n",
|
|
" const ctx = canvas.getContext('2d');\n",
|
|
" const w = canvas.width, h = canvas.height;\n",
|
|
" \n",
|
|
" const vertices = [\n",
|
|
" [-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1],\n",
|
|
" [-1,-1, 1], [1,-1, 1], [1,1, 1], [-1,1, 1]\n",
|
|
" ];\n",
|
|
" const edges = [\n",
|
|
" [0,1],[1,2],[2,3],[3,0],\n",
|
|
" [4,5],[5,6],[6,7],[7,4],\n",
|
|
" [0,4],[1,5],[2,6],[3,7]\n",
|
|
" ];\n",
|
|
" \n",
|
|
" function rotateY(x, y, z, a) {\n",
|
|
" const c = Math.cos(a), s = Math.sin(a);\n",
|
|
" return [x*c - z*s, y, x*s + z*c];\n",
|
|
" }\n",
|
|
" \n",
|
|
" function project(x, y, z) {\n",
|
|
" z += 4;\n",
|
|
" return [x/z * 100 + w/2, y/z * 100 + h/2];\n",
|
|
" }\n",
|
|
" \n",
|
|
" let angle = 0;\n",
|
|
" function draw() {\n",
|
|
" ctx.fillStyle = '#111';\n",
|
|
" ctx.fillRect(0, 0, w, h);\n",
|
|
" ctx.strokeStyle = '#0f0';\n",
|
|
" ctx.lineWidth = 2;\n",
|
|
" \n",
|
|
" for (const [i, j] of edges) {\n",
|
|
" const a = rotateY(...vertices[i], angle);\n",
|
|
" const b = rotateY(...vertices[j], angle);\n",
|
|
" const [x1, y1] = project(...a);\n",
|
|
" const [x2, y2] = project(...b);\n",
|
|
" ctx.beginPath();\n",
|
|
" ctx.moveTo(x1, y1);\n",
|
|
" ctx.lineTo(x2, y2);\n",
|
|
" ctx.stroke();\n",
|
|
" }\n",
|
|
" \n",
|
|
" angle += 0.02;\n",
|
|
" requestAnimationFrame(draw);\n",
|
|
" }\n",
|
|
" draw();\n",
|
|
"})();\n",
|
|
"</script>\n",
|
|
"\"\"\")"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"version": "3.11.0"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|