Poisson-disk sampling, new org-roam content
This commit is contained in:
parent
c5096cf3f9
commit
c2309066e3
2
.dir-locals.el
Normal file
2
.dir-locals.el
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
((nil . ((org-roam-directory . "/home/joe/Development/gaming-pads/content")
|
||||||
|
(org-roam-db-location . "/home/joe/Development/gaming-pads/org-roam.db"))))
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/org-roam.db
|
12
content/20240813113042-gaming_pads.org
Normal file
12
content/20240813113042-gaming_pads.org
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 6793b3f2-32d1-46dc-b104-e2d446c9a66e
|
||||||
|
:END:
|
||||||
|
#+title: Gaming Pads
|
||||||
|
|
||||||
|
It's how the acronym GAIMENPAAADS sounds, but that's a crappy acronym. Here is
|
||||||
|
a hierarchical overview of the topics
|
||||||
|
|
||||||
|
* [[id:f2b91852-e931-4026-a9a4-cc4188eecbb0][Math for Game Programmers]]
|
||||||
|
* [[id:bdba2433-f92c-48cc-a401-a9d8f777df8f][Graphics]]
|
||||||
|
* [[id:f548e57e-3d8e-4fe4-a5eb-5ebd338b1825][Artificial Intelligence]]
|
||||||
|
|
@ -1,24 +1,26 @@
|
|||||||
#+TEST: [[file:SpatialPartitioning.org][Spacial Partitioning]]
|
:PROPERTIES:
|
||||||
|
:ID: 4f3f07d3-a05e-40ad-94f9-cb35dad69ef1
|
||||||
|
:END:
|
||||||
|
#+title: Quadtree
|
||||||
|
|
||||||
* Quadtree
|
|
||||||
Recursively subdivide an AABB into 4 regions, hence Quad. They are usually
|
Recursively subdivide an AABB into 4 regions, hence Quad. They are usually
|
||||||
denoted as North West, North East, South West, and South East (NW, NE, SW, SE).
|
denoted as North West, North East, South West, and South East (NW, NE, SW, SE).
|
||||||
Several things can be created with this;
|
Several things can be created with this;
|
||||||
** Linked Implementation :datastructure:
|
* Linked Implementation :datastructure:
|
||||||
** Array Implementation :datastructure:
|
* Array Implementation :datastructure:
|
||||||
** Insertion :algorithm:
|
* Insertion :algorithm:
|
||||||
** Query :algorithm:
|
* Query :algorithm:
|
||||||
** Find Nearest Neighbor :algorithm:
|
* Find Nearest Neighbor :algorithm:
|
||||||
** Morton codes
|
* Morton codes
|
||||||
This is a technique that allows us to convert coordinates into an array index,
|
This is a technique that allows us to convert coordinates into an array index,
|
||||||
allowing us to pack them contiguously in memory
|
allowing us to pack them contiguously in memory
|
||||||
http://johnsietsma.com/2019/12/05/morton-order-introduction/
|
http://johnsietsma.com/2019/12/05/morton-order-introduction/
|
||||||
** Resources
|
* Resources
|
||||||
[[http://ericandrewlewis.github.io/how-a-quadtree-works/][Visualize a Quadtree]]
|
[[http://ericandrewlewis.github.io/how-a-quadtree-works/][Visualize a Quadtree]]
|
||||||
[[http://donar.umiacs.umd.edu/quadtree/][Academic Interactive Demo]]
|
[[http://donar.umiacs.umd.edu/quadtree/][Academic Interactive Demo]]
|
||||||
[[https://codepen.io/_bm/pen/ExPBMrW][Codepen (Js example)]]
|
[[https://codepen.io/_bm/pen/ExPBMrW][Codepen (Js example)]]
|
||||||
[[https://gist.github.com/patricksurry/6478178][D3.js Example]]
|
[[https://gist.github.com/patricksurry/6478178][D3.js Example]]
|
||||||
** Notes
|
* Notes
|
||||||
#+begin_src js
|
#+begin_src js
|
||||||
// exclude node if point is farther away than best distance in either axis
|
// exclude node if point is farther away than best distance in either axis
|
||||||
if (x < x1 - best.d || x > x2 + best.d || y < y1 - best.d || y > y2 + best.d) {
|
if (x < x1 - best.d || x > x2 + best.d || y < y1 - best.d || y > y2 + best.d) {
|
6
content/20240813113150-math_for_game_programmers.org
Normal file
6
content/20240813113150-math_for_game_programmers.org
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: f2b91852-e931-4026-a9a4-cc4188eecbb0
|
||||||
|
:END:
|
||||||
|
#+title: Math for Game Programmers
|
||||||
|
|
||||||
|
* [[id:42583e83-bc7d-4428-8228-c1c04f91806f][Geometry]]
|
7
content/20240813113239-geometry.org
Normal file
7
content/20240813113239-geometry.org
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 42583e83-bc7d-4428-8228-c1c04f91806f
|
||||||
|
:END:
|
||||||
|
#+title: Geometry
|
||||||
|
|
||||||
|
* [[id:62ab48ad-9a26-4fb7-a41b-dd341165cdec][Spatial Partitioning]]
|
||||||
|
* [[id:729ccfcc-8015-4438-b0c6-3097f311e505][Triangulation]]
|
8
content/20240813113258-spatial_partitioning.org
Normal file
8
content/20240813113258-spatial_partitioning.org
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 62ab48ad-9a26-4fb7-a41b-dd341165cdec
|
||||||
|
:END:
|
||||||
|
#+title: Spatial Partitioning
|
||||||
|
|
||||||
|
* [[id:4f3f07d3-a05e-40ad-94f9-cb35dad69ef1][Quadtree]]
|
||||||
|
* [[id:9d793370-5e77-4ae6-bf7a-6f3e6377a79c][KD-Tree]]
|
||||||
|
* [[id:137d9b32-c670-4b30-89ff-4b2da47006db][Poisson-disk sampling]]
|
10
content/20240813113355-kd_tree.org
Normal file
10
content/20240813113355-kd_tree.org
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 9d793370-5e77-4ae6-bf7a-6f3e6377a79c
|
||||||
|
:END:
|
||||||
|
#+title: KD-Tree
|
||||||
|
|
||||||
|
Info about a KD-Tree
|
||||||
|
* Linked Implementation :datastructure:
|
||||||
|
* Array Implementation :datastructure:
|
||||||
|
* Insertion :algorithm:
|
||||||
|
* Find Nearest Neighbor :algorithm:
|
@ -1,12 +1,14 @@
|
|||||||
#+TEST: [[file:Geometry][Geometry]]
|
:PROPERTIES:
|
||||||
|
:ID: 729ccfcc-8015-4438-b0c6-3097f311e505
|
||||||
|
:END:
|
||||||
|
#+title: Triangulation
|
||||||
|
|
||||||
* Triangulation
|
|
||||||
Generate triangles from points
|
Generate triangles from points
|
||||||
** Convex Hull Jarvis March (Gift wrapping) :algorithm:
|
* Convex Hull Jarvis March (Gift wrapping) :algorithm:
|
||||||
[[file:~/Development/gaming-pads/convexhull-jarvismarch.py][Python Code]]
|
[[file:~/Development/gaming-pads/convexhull-jarvismarch.py][Python Code]]
|
||||||
** Resources
|
* Resources
|
||||||
https://www.youtube.com/watch?v=Vu84lmMzP2o
|
https://www.youtube.com/watch?v=Vu84lmMzP2o
|
||||||
https://www.habrador.com/tutorials/math/8-convex-hull/
|
https://www.habrador.com/tutorials/math/8-convex-hull/
|
||||||
https://www.youtube.com/watch?v=B2AJoQSZf4M
|
https://www.youtube.com/watch?v=B2AJoQSZf4M
|
||||||
https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
|
https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
|
||||||
** Notes
|
* Notes
|
9
content/20240813113634-procedural_generation.org
Normal file
9
content/20240813113634-procedural_generation.org
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 98eb9900-fead-478c-8db4-29310ced82fb
|
||||||
|
:END:
|
||||||
|
#+title: Procedural Generation
|
||||||
|
|
||||||
|
These are used to divide a space in either a 2D or 3D world into smaller spaces
|
||||||
|
that can make operations like searching and filtering more efficient.
|
||||||
|
|
||||||
|
* [[id:137d9b32-c670-4b30-89ff-4b2da47006db][Poisson-disk sampling]]
|
5
content/20240813113652-poisson_disk_sampling.org
Normal file
5
content/20240813113652-poisson_disk_sampling.org
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: 137d9b32-c670-4b30-89ff-4b2da47006db
|
||||||
|
:END:
|
||||||
|
#+title: Poisson-disk sampling
|
||||||
|
|
7
content/20240813114155-graphics.org
Normal file
7
content/20240813114155-graphics.org
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: bdba2433-f92c-48cc-a401-a9d8f777df8f
|
||||||
|
:END:
|
||||||
|
#+title: Graphics
|
||||||
|
|
||||||
|
* [[id:98eb9900-fead-478c-8db4-29310ced82fb][Procedural Generation]]
|
||||||
|
* [[id:729ccfcc-8015-4438-b0c6-3097f311e505][Triangulation]]
|
6
content/20240813114306-artificial_intelligence.org
Normal file
6
content/20240813114306-artificial_intelligence.org
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
:PROPERTIES:
|
||||||
|
:ID: f548e57e-3d8e-4fe4-a5eb-5ebd338b1825
|
||||||
|
:END:
|
||||||
|
#+title: Artificial Intelligence
|
||||||
|
|
||||||
|
* [[id:98eb9900-fead-478c-8db4-29310ced82fb][Procedural Generation]]
|
@ -1,19 +0,0 @@
|
|||||||
* Gaming Pads
|
|
||||||
It's how the acronym GAIMENPAAADS sounds, but that's a crappy acronym. Here is
|
|
||||||
a hierarchical overview of the topics
|
|
||||||
** Math
|
|
||||||
*** Trigonometry
|
|
||||||
*** Data Structures
|
|
||||||
*** Algorithms
|
|
||||||
*** Linear Algebra
|
|
||||||
*** Geometry
|
|
||||||
**** Bezier Curves
|
|
||||||
**** Triangulation
|
|
||||||
**** Spatial Partitioning
|
|
||||||
#+transclude: [[file:Quadtree.org]] :level 5 :exclude-elements "keyword"
|
|
||||||
#+transclude: [[file:KD-Tree.org]] :level 5 :exclude-elements "keyword"
|
|
||||||
** Engineering
|
|
||||||
*** Machine Architecture
|
|
||||||
*** Networking
|
|
||||||
*** Compilers
|
|
||||||
*** Operating Systems
|
|
@ -1,6 +0,0 @@
|
|||||||
#+TODO: ⬜ 🟩️ | ✅
|
|
||||||
|
|
||||||
* Geometry
|
|
||||||
** [[file:SpatialPartitioning.org][Spatial Partitioning]]
|
|
||||||
** [[file:Triangulation.org][Triangulation]]
|
|
||||||
** Bezier Curves
|
|
@ -1,8 +0,0 @@
|
|||||||
#+NAVIGATION_UP: [[file:SpatialPartitioning.org][Spacial Partitioning]]
|
|
||||||
|
|
||||||
* KD-Tree
|
|
||||||
Info about a KD-Tree
|
|
||||||
** Linked Implementation :datastructure:
|
|
||||||
** Array Implementation :datastructure:
|
|
||||||
** Insertion :algorithm:
|
|
||||||
** Find Nearest Neighbor :algorithm:
|
|
@ -1 +0,0 @@
|
|||||||
* Math
|
|
@ -1,9 +0,0 @@
|
|||||||
# -*- mode: Org; eval: (org-transclusion-mode 0) -*- #
|
|
||||||
#+NAVIGATION-UP: [[file:Geometry.org][Geometry]]
|
|
||||||
|
|
||||||
* Spatial Partitioning
|
|
||||||
These are used to divide a space in either a 2D or 3D world into smaller spaces
|
|
||||||
that can make operations like searching and filtering more efficient.
|
|
||||||
|
|
||||||
#+transclude: [[file:Quadtree.org]] :level 2
|
|
||||||
#+transclude: [[file:KD-Tree.org]] :level 2
|
|
151
poisson-disk-sampling.py
Normal file
151
poisson-disk-sampling.py
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import pyray as RL
|
||||||
|
from pyray import (Rectangle as Rect, Vector2 as Vec2, Vector3 as Vec3, Camera3D, BoundingBox, Color)
|
||||||
|
import math
|
||||||
|
import pdb
|
||||||
|
import random
|
||||||
|
from typing import Optional, Tuple, List
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
def dump(struct):
|
||||||
|
s = f"{RL.ffi.typeof(struct)}: (".replace('<ctype ', '').replace('>', '')
|
||||||
|
for field in dir(struct):
|
||||||
|
data = struct.__getattribute__(field)
|
||||||
|
if str(data).startswith("<cdata"):
|
||||||
|
data = dump(data)
|
||||||
|
s += f"{field}:{data} "
|
||||||
|
s += ")"
|
||||||
|
return s
|
||||||
|
|
||||||
|
screen_width = 1024
|
||||||
|
screen_height = 512
|
||||||
|
r = 10
|
||||||
|
k = 30
|
||||||
|
cell_size = r / math.sqrt(2)
|
||||||
|
cols = int(screen_width // cell_size)
|
||||||
|
rows = int(screen_height // cell_size)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class World:
|
||||||
|
grid: List[Vec2]
|
||||||
|
points: List[Vec2]
|
||||||
|
active: List[Vec2]
|
||||||
|
pidx = 0
|
||||||
|
start = False
|
||||||
|
point_count = 0
|
||||||
|
frame_count: int = 0
|
||||||
|
debug_draw: bool = False
|
||||||
|
|
||||||
|
def init() -> World:
|
||||||
|
grid = [None] * rows * cols
|
||||||
|
points = [Vec2(screen_width // 2, screen_height // 2)]
|
||||||
|
# points = []
|
||||||
|
active = points.copy()
|
||||||
|
for p in points:
|
||||||
|
idx = int(p.y // cell_size * cols + p.x // cell_size)
|
||||||
|
grid[idx] = p
|
||||||
|
return World(grid, points, active)
|
||||||
|
|
||||||
|
def player_input(w: World):
|
||||||
|
if RL.is_mouse_button_pressed(0):
|
||||||
|
p = RL.get_mouse_position()
|
||||||
|
w.points.append(p)
|
||||||
|
idx = int(p.y // cell_size * cols + p.x // cell_size)
|
||||||
|
if idx < len(w.grid):
|
||||||
|
w.grid[idx] = 1
|
||||||
|
if RL.is_key_pressed(RL.KEY_SPACE):
|
||||||
|
w.debug_draw = not w.debug_draw
|
||||||
|
if RL.is_key_pressed(RL.KEY_ENTER):
|
||||||
|
w.start = True
|
||||||
|
|
||||||
|
def update(w: World):
|
||||||
|
# if w.frame_count % 1 != 0:
|
||||||
|
# return
|
||||||
|
if not w.start or not w.points or not w.active:
|
||||||
|
return
|
||||||
|
for _ in range(25):
|
||||||
|
if not w.active:
|
||||||
|
break
|
||||||
|
point = w.active[-1]
|
||||||
|
w.pidx = (w.pidx + 1) % len(w.points)
|
||||||
|
found = False
|
||||||
|
for i in range(k):
|
||||||
|
r_angle = random.random() * math.pi * 2
|
||||||
|
r_dist = random.uniform(r, 2 * r)
|
||||||
|
new_point = Vec2(point.x + math.cos(r_angle) * r_dist, point.y + math.sin(r_angle) * r_dist)
|
||||||
|
new_point_idx = int(new_point.y // cell_size * cols + new_point.x // cell_size)
|
||||||
|
if (new_point_idx >= len(w.grid) or w.grid[new_point_idx] is not None
|
||||||
|
or new_point.x < 0 or new_point.x > cell_size * cols
|
||||||
|
or new_point.y < 0 or new_point.y > cell_size * rows):
|
||||||
|
continue
|
||||||
|
new_point_row = new_point_idx // cols
|
||||||
|
new_point_col = new_point_idx % cols
|
||||||
|
collides = False
|
||||||
|
for i in range(-2, 3):
|
||||||
|
for j in range(-2, 3):
|
||||||
|
if collides:
|
||||||
|
break
|
||||||
|
row = new_point_row + i
|
||||||
|
col = new_point_col + j
|
||||||
|
if row < 0 or row >= rows or col < 0 or col >= cols:
|
||||||
|
continue
|
||||||
|
idx = row * cols + col
|
||||||
|
if w.grid[idx] is not None:
|
||||||
|
# Check distance
|
||||||
|
dist_sqr = RL.vector_2distance_sqr(w.grid[idx], new_point)
|
||||||
|
if dist_sqr < r * r:
|
||||||
|
collides = True
|
||||||
|
|
||||||
|
if collides:
|
||||||
|
continue
|
||||||
|
w.grid[new_point_idx] = new_point
|
||||||
|
w.points.append(new_point)
|
||||||
|
w.point_count += 1
|
||||||
|
w.active.append(new_point)
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
w.active.pop()
|
||||||
|
|
||||||
|
|
||||||
|
def draw_2d(w: World):
|
||||||
|
# for p in w.points:
|
||||||
|
# prx = p.x // cell_size * cell_size
|
||||||
|
# pry = p.y // cell_size * cell_size
|
||||||
|
# rect = Rect(prx, pry, cell_size, cell_size)
|
||||||
|
# RL.draw_rectangle_rec(rect, Color(230, 230, 230, 255))
|
||||||
|
if w.debug_draw:
|
||||||
|
for i,c in enumerate(w.grid):
|
||||||
|
if c != -1:
|
||||||
|
cell_x = (i % cols) * cell_size
|
||||||
|
cell_y = (i // cols) * cell_size
|
||||||
|
rect = Rect(cell_x, cell_y, cell_size, cell_size)
|
||||||
|
RL.draw_rectangle_rec(rect, Color(230, 230, 230, 255))
|
||||||
|
|
||||||
|
for i in range(int((screen_width // cell_size) + 1) - 1):
|
||||||
|
for j in range(int((screen_height // cell_size) + 1) - 1):
|
||||||
|
rect = Rect(cell_size * i, cell_size * j, cell_size, cell_size)
|
||||||
|
RL.draw_rectangle_lines_ex(rect, 2, RL.GREEN)
|
||||||
|
for i,p in enumerate(w.points):
|
||||||
|
red = min(200, i % 255)
|
||||||
|
green = min(200, i * 2 % 255)
|
||||||
|
blue = min(200, i * 3 % 255)
|
||||||
|
RL.draw_circle_v(p, 2, Color(red, green, blue, 255))
|
||||||
|
|
||||||
|
|
||||||
|
RL.init_window(screen_width, screen_height, "Poisson-disk Sampling");
|
||||||
|
RL.set_target_fps(60)
|
||||||
|
|
||||||
|
w = init()
|
||||||
|
while not RL.window_should_close():
|
||||||
|
player_input(w)
|
||||||
|
update(w)
|
||||||
|
|
||||||
|
# Drawing
|
||||||
|
RL.begin_drawing()
|
||||||
|
RL.clear_background(RL.WHITE)
|
||||||
|
|
||||||
|
draw_2d(w)
|
||||||
|
|
||||||
|
RL.end_drawing()
|
||||||
|
w.frame_count += 1
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user