expansion: 25 modular editor props (52 total) + pool tile / grate textures
John's editor taxonomy: kink/A-frame/donkey/down/square rails, pole jam, hubba, low/table boxes, inclined manny, pyramid, euro gap, vert quarter, wallride wall, volcano, roller, jersey barrier, parking block, hydrant, pool coping, chain fence, floodlight, bleachers, drain grate. propkit: alpha + emissive materials; lathe winding fixed (was inside-out). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
153e26c329
commit
0c551843a7
24
README.md
24
README.md
@ -1,7 +1,7 @@
|
||||
# park_kit — GODVERSE park object library
|
||||
|
||||
Reusable, textured, license-clean park objects for **bookquoy** and **skatemakerpro**
|
||||
(and whatever comes next). 27 props, 18 photoreal surfaces, all original: geometry
|
||||
(and whatever comes next). 52 props, 20 photoreal surfaces, all original: geometry
|
||||
authored parametrically in `tools/prop_author.py`, textures generated on the
|
||||
MODELBEAST farm (flux_local, local GPU, no cloud spend).
|
||||
|
||||
@ -28,14 +28,20 @@ matches across every prop.
|
||||
|
||||
## Catalog
|
||||
|
||||
- **obstacles (14):** qp_24, qp_18, bank_12, kicker, funbox_ply, spine_ply,
|
||||
manual_pad, ledge_concrete, grindbox_ply, rail_flat_3m, rail_flat_6m,
|
||||
rail_kink, rail_rainbow, pipe_full (graffiti-bombed concrete full pipe)
|
||||
- **furniture (7):** bench_park, bench_concrete, picnic_table, bin_council,
|
||||
bollard_steel, railing_ped_2m, planter_box (with gum sapling)
|
||||
- **vegetation (2):** tree_fig (Moreton Bay, buttress roots), tree_gum (eucalypt)
|
||||
- **dressing (4):** kerb_3m (slappy central), wall_graffiti (wallride bait),
|
||||
shade_sail, mound_dirt
|
||||
- **transition:** qp_24, qp_18, qp_vert (8ft), wallride_qp (to-vertical, concrete),
|
||||
spine_ply, bank_12, kicker, launch_high, euro_gap, pyramid, funbox_ply,
|
||||
volcano, roller, pipe_full (graffiti-bombed concrete full pipe), mound_dirt
|
||||
- **rails:** rail_flat_3m, rail_flat_6m, square_flatbar, rail_down, rail_kink,
|
||||
rail_kink2 (double), rail_aframe, rail_donkey (kinks up), rail_rainbow,
|
||||
pole_jam (35°)
|
||||
- **ledges/boxes:** ledge_concrete, grindbox_ply, box_low (10in),
|
||||
box_table (24in), manual_pad, manny_incline, hubba_down (flat-to-down)
|
||||
- **street furniture:** bench_park, bench_concrete, picnic_table, bin_council,
|
||||
bollard_steel, railing_ped_2m, planter_box, jersey_barrier, parking_block,
|
||||
hydrant, pool_edge (bullnose coping + tile band), bleachers_3
|
||||
- **vegetation:** tree_fig (Moreton Bay, buttress roots), tree_gum (eucalypt)
|
||||
- **infrastructure/dressing:** kerb_3m (slappy central), wall_graffiti
|
||||
(wallride bait), shade_sail, fence_chain_3m, floodlight, drain_grate
|
||||
|
||||
## View it
|
||||
|
||||
|
||||
956
manifest.json
956
manifest.json
@ -909,6 +909,962 @@
|
||||
"h": 0.55,
|
||||
"s": 1.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "qp_vert",
|
||||
"src": "props/qp_vert.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "vert quarter 8ft",
|
||||
"size": [
|
||||
3.6,
|
||||
2.45,
|
||||
3.283
|
||||
],
|
||||
"tris": 124,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.8,
|
||||
-2.6832815729997477
|
||||
],
|
||||
"b": [
|
||||
1.8,
|
||||
-2.6832815729997477
|
||||
],
|
||||
"ya": 2.42,
|
||||
"yb": 2.42,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "quarter",
|
||||
"len": 3.6,
|
||||
"r0": 2.7,
|
||||
"r1": 2.7,
|
||||
"h": 2.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "wallride_qp",
|
||||
"src": "props/wallride_qp.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "wallride wall \u2014 transition to vertical",
|
||||
"size": [
|
||||
3.0,
|
||||
1.5,
|
||||
1.62
|
||||
],
|
||||
"tris": 72,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.5,
|
||||
-1.5
|
||||
],
|
||||
"b": [
|
||||
1.5,
|
||||
-1.5
|
||||
],
|
||||
"ya": 1.5,
|
||||
"yb": 1.5,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "quarter",
|
||||
"len": 3.0,
|
||||
"r0": 1.5,
|
||||
"r1": 1.5,
|
||||
"h": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "launch_high",
|
||||
"src": "props/launch_high.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "high launch ramp",
|
||||
"size": [
|
||||
1.5,
|
||||
0.9,
|
||||
1.64
|
||||
],
|
||||
"tris": 56,
|
||||
"element": {
|
||||
"kind": "bank",
|
||||
"len": 1.5,
|
||||
"h": 0.9,
|
||||
"run": 1.6
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "square_flatbar",
|
||||
"src": "props/square_flatbar.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "square-section flatbar",
|
||||
"size": [
|
||||
2.4,
|
||||
0.4,
|
||||
0.12
|
||||
],
|
||||
"tris": 60,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.2,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.2,
|
||||
0
|
||||
],
|
||||
"ya": 0.4,
|
||||
"yb": 0.4,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "pole_jam",
|
||||
"src": "props/pole_jam.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "bent pole jammed out of the concrete, 35 deg",
|
||||
"size": [
|
||||
1.661,
|
||||
1.003,
|
||||
0.5
|
||||
],
|
||||
"tris": 52,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.392558475291286,
|
||||
0
|
||||
],
|
||||
"ya": 0.05,
|
||||
"yb": 0.9750799417967783,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rail_down",
|
||||
"src": "props/rail_down.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "straight down rail",
|
||||
"size": [
|
||||
3.008,
|
||||
0.8,
|
||||
0.12
|
||||
],
|
||||
"tris": 128,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.5,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.5,
|
||||
0
|
||||
],
|
||||
"ya": 0.78,
|
||||
"yb": 0.18,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rail_kink2",
|
||||
"src": "props/rail_kink2.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "double-kink down rail",
|
||||
"size": [
|
||||
4.404,
|
||||
0.7,
|
||||
0.12
|
||||
],
|
||||
"tris": 276,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-2.2,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
-1.0,
|
||||
0
|
||||
],
|
||||
"ya": 0.68,
|
||||
"yb": 0.68,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-1.0,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
0.1,
|
||||
0
|
||||
],
|
||||
"ya": 0.68,
|
||||
"yb": 0.36,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.1,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
0.9,
|
||||
0
|
||||
],
|
||||
"ya": 0.36,
|
||||
"yb": 0.36,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.9,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
2.2,
|
||||
0
|
||||
],
|
||||
"ya": 0.36,
|
||||
"yb": 0.08,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rail_aframe",
|
||||
"src": "props/rail_aframe.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "A-frame rail",
|
||||
"size": [
|
||||
3.613,
|
||||
0.74,
|
||||
0.12
|
||||
],
|
||||
"tris": 192,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.8,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"ya": 0.12,
|
||||
"yb": 0.72,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.8,
|
||||
0
|
||||
],
|
||||
"ya": 0.72,
|
||||
"yb": 0.12,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rail_donkey",
|
||||
"src": "props/rail_donkey.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "donkey-kick rail \u2014 kinks up at the end",
|
||||
"size": [
|
||||
3.108,
|
||||
0.818,
|
||||
0.12
|
||||
],
|
||||
"tris": 192,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.6,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
0.6,
|
||||
0
|
||||
],
|
||||
"ya": 0.42,
|
||||
"yb": 0.42,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.6,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.5,
|
||||
0
|
||||
],
|
||||
"ya": 0.42,
|
||||
"yb": 0.8,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "box_low",
|
||||
"src": "props/box_low.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "low grind box 10in",
|
||||
"size": [
|
||||
1.8,
|
||||
0.25,
|
||||
0.558
|
||||
],
|
||||
"tris": 60,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-0.9,
|
||||
0.25
|
||||
],
|
||||
"b": [
|
||||
0.9,
|
||||
0.25
|
||||
],
|
||||
"ya": 0.25,
|
||||
"yb": 0.25,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-0.9,
|
||||
-0.25
|
||||
],
|
||||
"b": [
|
||||
0.9,
|
||||
-0.25
|
||||
],
|
||||
"ya": 0.25,
|
||||
"yb": 0.25,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "ledge",
|
||||
"hw": 0.9,
|
||||
"hd": 0.25,
|
||||
"h": 0.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "box_table",
|
||||
"src": "props/box_table.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "high table box 24in",
|
||||
"size": [
|
||||
2.4,
|
||||
0.62,
|
||||
0.758
|
||||
],
|
||||
"tris": 60,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.2,
|
||||
0.35
|
||||
],
|
||||
"b": [
|
||||
1.2,
|
||||
0.35
|
||||
],
|
||||
"ya": 0.62,
|
||||
"yb": 0.62,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-1.2,
|
||||
-0.35
|
||||
],
|
||||
"b": [
|
||||
1.2,
|
||||
-0.35
|
||||
],
|
||||
"ya": 0.62,
|
||||
"yb": 0.62,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "ledge",
|
||||
"hw": 1.2,
|
||||
"hd": 0.35,
|
||||
"h": 0.62
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hubba_down",
|
||||
"src": "props/hubba_down.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "flat-to-down hubba ledge",
|
||||
"size": [
|
||||
2.6,
|
||||
0.66,
|
||||
0.42
|
||||
],
|
||||
"tris": 14,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.3,
|
||||
-0.21
|
||||
],
|
||||
"b": [
|
||||
-0.5,
|
||||
-0.21
|
||||
],
|
||||
"ya": 0.66,
|
||||
"yb": 0.66,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-0.5,
|
||||
-0.21
|
||||
],
|
||||
"b": [
|
||||
1.3,
|
||||
-0.21
|
||||
],
|
||||
"ya": 0.66,
|
||||
"yb": 0.12,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-1.3,
|
||||
0.21
|
||||
],
|
||||
"b": [
|
||||
-0.5,
|
||||
0.21
|
||||
],
|
||||
"ya": 0.66,
|
||||
"yb": 0.66,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-0.5,
|
||||
0.21
|
||||
],
|
||||
"b": [
|
||||
1.3,
|
||||
0.21
|
||||
],
|
||||
"ya": 0.66,
|
||||
"yb": 0.12,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "box",
|
||||
"hw": 1.3,
|
||||
"hd": 0.21,
|
||||
"h": 0.66
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "manny_incline",
|
||||
"src": "props/manny_incline.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "inclined manual pad",
|
||||
"size": [
|
||||
2.0,
|
||||
0.4,
|
||||
1.603
|
||||
],
|
||||
"tris": 12,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.0,
|
||||
-0.8
|
||||
],
|
||||
"b": [
|
||||
1.0,
|
||||
-0.8
|
||||
],
|
||||
"ya": 0.18,
|
||||
"yb": 0.4,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-1.0,
|
||||
0.8
|
||||
],
|
||||
"b": [
|
||||
1.0,
|
||||
0.8
|
||||
],
|
||||
"ya": 0.18,
|
||||
"yb": 0.4,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "box",
|
||||
"hw": 1.0,
|
||||
"hd": 0.8,
|
||||
"h": 0.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "pyramid",
|
||||
"src": "props/pyramid.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "four-sided pyramid, flat top, steel edges",
|
||||
"size": [
|
||||
4.8,
|
||||
0.8,
|
||||
4.8
|
||||
],
|
||||
"tris": 116,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-0.8,
|
||||
0.8
|
||||
],
|
||||
"b": [
|
||||
0.8,
|
||||
0.8
|
||||
],
|
||||
"ya": 0.8,
|
||||
"yb": 0.8,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.8,
|
||||
0.8
|
||||
],
|
||||
"b": [
|
||||
0.8,
|
||||
-0.8
|
||||
],
|
||||
"ya": 0.8,
|
||||
"yb": 0.8,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.8000000000000002,
|
||||
-0.7999999999999999
|
||||
],
|
||||
"b": [
|
||||
-0.7999999999999999,
|
||||
-0.8000000000000002
|
||||
],
|
||||
"ya": 0.8,
|
||||
"yb": 0.8,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-0.7999999999999999,
|
||||
-0.8000000000000002
|
||||
],
|
||||
"b": [
|
||||
-0.8000000000000002,
|
||||
0.7999999999999999
|
||||
],
|
||||
"ya": 0.8,
|
||||
"yb": 0.8,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "funbox",
|
||||
"hw": 2.4,
|
||||
"hd": 2.4,
|
||||
"h": 0.8,
|
||||
"skirt": 1.5999999999999999
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "euro_gap",
|
||||
"src": "props/euro_gap.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "euro gap: bank up, sheer drop off the deck",
|
||||
"size": [
|
||||
2.4,
|
||||
0.75,
|
||||
2.529
|
||||
],
|
||||
"tris": 54,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.2,
|
||||
-0.5
|
||||
],
|
||||
"b": [
|
||||
1.2,
|
||||
-0.5
|
||||
],
|
||||
"ya": 0.75,
|
||||
"yb": 0.75,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "bank",
|
||||
"len": 2.4,
|
||||
"h": 0.75,
|
||||
"run": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "volcano",
|
||||
"src": "props/volcano.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "concrete volcano cone, grindable rim",
|
||||
"size": [
|
||||
4.4,
|
||||
1.1,
|
||||
4.4
|
||||
],
|
||||
"tris": 180,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-0.36,
|
||||
-0.36
|
||||
],
|
||||
"b": [
|
||||
0.36,
|
||||
-0.36
|
||||
],
|
||||
"ya": 1.1,
|
||||
"yb": 1.1,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.36,
|
||||
-0.36
|
||||
],
|
||||
"b": [
|
||||
0.36,
|
||||
0.36
|
||||
],
|
||||
"ya": 1.1,
|
||||
"yb": 1.1,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
0.36,
|
||||
0.36
|
||||
],
|
||||
"b": [
|
||||
-0.36,
|
||||
0.36
|
||||
],
|
||||
"ya": 1.1,
|
||||
"yb": 1.1,
|
||||
"kind": "rail"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-0.36,
|
||||
0.36
|
||||
],
|
||||
"b": [
|
||||
-0.36,
|
||||
-0.36
|
||||
],
|
||||
"ya": 1.1,
|
||||
"yb": 1.1,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"element": {
|
||||
"kind": "mogul",
|
||||
"h": 1.1,
|
||||
"s": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "roller",
|
||||
"src": "props/roller.glb",
|
||||
"category": "obstacle",
|
||||
"desc": "concrete speed roller / pump bump",
|
||||
"size": [
|
||||
2.4,
|
||||
0.32,
|
||||
2.2
|
||||
],
|
||||
"tris": 42,
|
||||
"element": {
|
||||
"kind": "mogul",
|
||||
"h": 0.32,
|
||||
"s": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "jersey_barrier",
|
||||
"src": "props/jersey_barrier.glb",
|
||||
"category": "furniture",
|
||||
"desc": "concrete K-rail jersey barrier",
|
||||
"size": [
|
||||
2.0,
|
||||
0.81,
|
||||
0.6
|
||||
],
|
||||
"tris": 26,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.0,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.0,
|
||||
0
|
||||
],
|
||||
"ya": 0.81,
|
||||
"yb": 0.81,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "box",
|
||||
"hw": 1.0,
|
||||
"hd": 0.3,
|
||||
"h": 0.81
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "parking_block",
|
||||
"src": "props/parking_block.glb",
|
||||
"category": "furniture",
|
||||
"desc": "concrete parking block \u2014 slappy bait",
|
||||
"size": [
|
||||
1.7,
|
||||
0.15,
|
||||
0.16
|
||||
],
|
||||
"tris": 12,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-0.85,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
0.85,
|
||||
0
|
||||
],
|
||||
"ya": 0.15,
|
||||
"yb": 0.15,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hydrant",
|
||||
"src": "props/hydrant.glb",
|
||||
"category": "furniture",
|
||||
"desc": "fire hydrant \u2014 bonk it",
|
||||
"size": [
|
||||
0.32,
|
||||
0.8,
|
||||
0.32
|
||||
],
|
||||
"tris": 208,
|
||||
"collider": {
|
||||
"type": "cylinder",
|
||||
"r": 0.2,
|
||||
"h": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "pool_edge",
|
||||
"src": "props/pool_edge.glb",
|
||||
"category": "furniture",
|
||||
"desc": "pool coping + tile band, 2m section",
|
||||
"size": [
|
||||
2.0,
|
||||
0.182,
|
||||
0.565
|
||||
],
|
||||
"tris": 54,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.0,
|
||||
0.01
|
||||
],
|
||||
"b": [
|
||||
1.0,
|
||||
0.01
|
||||
],
|
||||
"ya": 0.185,
|
||||
"yb": 0.185,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fence_chain_3m",
|
||||
"src": "props/fence_chain_3m.glb",
|
||||
"category": "dressing",
|
||||
"desc": "chain-link fence section",
|
||||
"size": [
|
||||
3.048,
|
||||
1.821,
|
||||
0.048
|
||||
],
|
||||
"tris": 98,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.5,
|
||||
0
|
||||
],
|
||||
"b": [
|
||||
1.5,
|
||||
0
|
||||
],
|
||||
"ya": 1.8,
|
||||
"yb": 1.8,
|
||||
"kind": "rail"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "box",
|
||||
"hw": 1.5,
|
||||
"hd": 0.03,
|
||||
"h": 1.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "floodlight",
|
||||
"src": "props/floodlight.glb",
|
||||
"category": "dressing",
|
||||
"desc": "park floodlight pole",
|
||||
"size": [
|
||||
1.2,
|
||||
6.23,
|
||||
0.236
|
||||
],
|
||||
"tris": 86,
|
||||
"collider": {
|
||||
"type": "cylinder",
|
||||
"r": 0.12,
|
||||
"h": 6.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bleachers_3",
|
||||
"src": "props/bleachers_3.glb",
|
||||
"category": "furniture",
|
||||
"desc": "three-row spectator bleachers",
|
||||
"size": [
|
||||
3.0,
|
||||
0.92,
|
||||
1.5
|
||||
],
|
||||
"tris": 78,
|
||||
"grinds": [
|
||||
{
|
||||
"a": [
|
||||
-1.5,
|
||||
-0.225
|
||||
],
|
||||
"b": [
|
||||
1.5,
|
||||
-0.225
|
||||
],
|
||||
"ya": 0.32,
|
||||
"yb": 0.32,
|
||||
"kind": "ledge"
|
||||
},
|
||||
{
|
||||
"a": [
|
||||
-1.5,
|
||||
0.775
|
||||
],
|
||||
"b": [
|
||||
1.5,
|
||||
0.775
|
||||
],
|
||||
"ya": 0.92,
|
||||
"yb": 0.92,
|
||||
"kind": "ledge"
|
||||
}
|
||||
],
|
||||
"collider": {
|
||||
"type": "box",
|
||||
"hw": 1.5,
|
||||
"hd": 0.75,
|
||||
"h": 0.92
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "drain_grate",
|
||||
"src": "props/drain_grate.glb",
|
||||
"category": "dressing",
|
||||
"desc": "flush drainage grate",
|
||||
"size": [
|
||||
1.06,
|
||||
0.022,
|
||||
0.76
|
||||
],
|
||||
"tris": 24,
|
||||
"collider": {
|
||||
"type": "none"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
BIN
props/bleachers_3.glb
Normal file
BIN
props/bleachers_3.glb
Normal file
Binary file not shown.
Binary file not shown.
BIN
props/box_low.glb
Normal file
BIN
props/box_low.glb
Normal file
Binary file not shown.
BIN
props/box_table.glb
Normal file
BIN
props/box_table.glb
Normal file
Binary file not shown.
BIN
props/drain_grate.glb
Normal file
BIN
props/drain_grate.glb
Normal file
Binary file not shown.
BIN
props/euro_gap.glb
Normal file
BIN
props/euro_gap.glb
Normal file
Binary file not shown.
BIN
props/fence_chain_3m.glb
Normal file
BIN
props/fence_chain_3m.glb
Normal file
Binary file not shown.
BIN
props/floodlight.glb
Normal file
BIN
props/floodlight.glb
Normal file
Binary file not shown.
BIN
props/hubba_down.glb
Normal file
BIN
props/hubba_down.glb
Normal file
Binary file not shown.
BIN
props/hydrant.glb
Normal file
BIN
props/hydrant.glb
Normal file
Binary file not shown.
BIN
props/jersey_barrier.glb
Normal file
BIN
props/jersey_barrier.glb
Normal file
Binary file not shown.
BIN
props/launch_high.glb
Normal file
BIN
props/launch_high.glb
Normal file
Binary file not shown.
BIN
props/manny_incline.glb
Normal file
BIN
props/manny_incline.glb
Normal file
Binary file not shown.
BIN
props/parking_block.glb
Normal file
BIN
props/parking_block.glb
Normal file
Binary file not shown.
Binary file not shown.
BIN
props/pole_jam.glb
Normal file
BIN
props/pole_jam.glb
Normal file
Binary file not shown.
BIN
props/pool_edge.glb
Normal file
BIN
props/pool_edge.glb
Normal file
Binary file not shown.
BIN
props/pyramid.glb
Normal file
BIN
props/pyramid.glb
Normal file
Binary file not shown.
BIN
props/qp_vert.glb
Normal file
BIN
props/qp_vert.glb
Normal file
Binary file not shown.
BIN
props/rail_aframe.glb
Normal file
BIN
props/rail_aframe.glb
Normal file
Binary file not shown.
BIN
props/rail_donkey.glb
Normal file
BIN
props/rail_donkey.glb
Normal file
Binary file not shown.
BIN
props/rail_down.glb
Normal file
BIN
props/rail_down.glb
Normal file
Binary file not shown.
BIN
props/rail_kink2.glb
Normal file
BIN
props/rail_kink2.glb
Normal file
Binary file not shown.
BIN
props/roller.glb
Normal file
BIN
props/roller.glb
Normal file
Binary file not shown.
BIN
props/square_flatbar.glb
Normal file
BIN
props/square_flatbar.glb
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
props/volcano.glb
Normal file
BIN
props/volcano.glb
Normal file
Binary file not shown.
BIN
props/wallride_qp.glb
Normal file
BIN
props/wallride_qp.glb
Normal file
Binary file not shown.
BIN
textures/steel_grate.jpg
Normal file
BIN
textures/steel_grate.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 231 KiB |
BIN
textures/tiles_pool.jpg
Normal file
BIN
textures/tiles_pool.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
Binary file not shown.
@ -38,6 +38,8 @@ TEXTURES = {
|
||||
'brick_qld': 'reddish brown queensland house bricks with pale mortar joints, running bond',
|
||||
'graffiti_a': 'colorful graffiti burner piece with bold wildstyle letters on a concrete skatepark wall, aerosol art, blues oranges purples',
|
||||
'graffiti_b': 'concrete wall covered in layered spray paint tags and simple throw-up graffiti letters, black silver white paint',
|
||||
'tiles_pool': 'vintage swimming pool tile band, small square ceramic tiles, white with pale smalt-blue accent rows, aged grout lines',
|
||||
'steel_grate': 'steel drainage grate with parallel slot openings, dark weathered galvanized metal',
|
||||
'sky_day': 'clear bright queensland blue sky with a few small white cumulus clouds, wide even gradient',
|
||||
}
|
||||
|
||||
|
||||
@ -86,7 +86,8 @@ def arc_pts(r, th0, th1, n):
|
||||
for t in [th0 + (th1 - th0) * i / n for i in range(n + 1)]]
|
||||
|
||||
# =================================================================== ramps
|
||||
def quarter(pid, w, h, r, desc):
|
||||
def quarter(pid, w, h, r, desc, coping=True, deck=True, mat=None):
|
||||
mat = mat or PLY
|
||||
th = math.acos(1 - h / r)
|
||||
depth = r * math.sin(th)
|
||||
n = 14
|
||||
@ -95,21 +96,26 @@ def quarter(pid, w, h, r, desc):
|
||||
p = Prop(pid, 'obstacle', desc)
|
||||
# riding surface (two columns across width)
|
||||
rows = [[(-w / 2, y, z), (w / 2, y, z)] for y, z in ys_zs]
|
||||
p.add(PLY, sheet(rows))
|
||||
p.add(mat, sheet(rows))
|
||||
# deck platform + coping
|
||||
deck_d = 0.6
|
||||
p.add(PLY, box(0, h - 0.04, -depth - deck_d / 2, w, 0.08, deck_d))
|
||||
p.add(STEEL, tube([(-w / 2, h + 0.02, -depth), (w / 2, h + 0.02, -depth)],
|
||||
0.032, seg=10))
|
||||
deck_d = 0.6 if deck else 0.12
|
||||
if deck:
|
||||
p.add(mat, box(0, h - 0.04, -depth - deck_d / 2, w, 0.08, deck_d))
|
||||
if coping:
|
||||
p.add(STEEL, tube([(-w / 2, h + 0.02, -depth), (w / 2, h + 0.02, -depth)],
|
||||
0.032, seg=10))
|
||||
# side plates: arc boundary + deck + back-down (fan from back-bottom corner)
|
||||
prof = [( -depth - deck_d, 0)] + [(z, y) for y, z in ys_zs] + \
|
||||
[(-depth, h), (-depth - deck_d, h)]
|
||||
for sx in (-w / 2, w / 2):
|
||||
pts = [(sx, y, z) for z, y in prof]
|
||||
p.add(PLY, fan(pts, lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
p.add(mat, fan(pts, lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
# back wall
|
||||
p.add(GALV, box(0, h / 2, -depth - deck_d + 0.02, w, h, 0.04))
|
||||
p.grind(-w / 2, -depth, w / 2, -depth, h + 0.02, h + 0.02, 'rail')
|
||||
if coping:
|
||||
p.grind(-w / 2, -depth, w / 2, -depth, h + 0.02, h + 0.02, 'rail')
|
||||
else:
|
||||
p.grind(-w / 2, -depth, w / 2, -depth, h, h, 'ledge')
|
||||
p.element = {'kind': 'quarter', 'len': w, 'r0': r, 'r1': r, 'h': h}
|
||||
return p
|
||||
|
||||
@ -127,9 +133,10 @@ def bank(pid, w, h, run, desc):
|
||||
p.element = {'kind': 'bank', 'len': w, 'h': h, 'run': run}
|
||||
return p
|
||||
|
||||
def kicker():
|
||||
p = Prop('kicker', 'obstacle', 'curved plywood launch kicker')
|
||||
w, h, run, n = 1.2, 0.45, 1.0, 8
|
||||
def kicker(pid='kicker', w=1.2, h=0.45, run=1.0,
|
||||
desc='curved plywood launch kicker'):
|
||||
p = Prop(pid, 'obstacle', desc)
|
||||
n = 8
|
||||
rows = []
|
||||
for i in range(n + 1):
|
||||
t = i / n
|
||||
@ -484,6 +491,273 @@ def mound_dirt():
|
||||
p.element = {'kind': 'mogul', 'h': H, 's': 1.4}
|
||||
return p
|
||||
|
||||
# ====================================================== expansion: modular set
|
||||
# John's editor taxonomy (2026-08-03): kink variants, pole jams, hubbas, boxes,
|
||||
# pyramid, euro gap, vert wall, volcano, street props, park infrastructure.
|
||||
|
||||
def rail_from(pid, pts_xy, feet_x, desc, r=0.021, kind='rail'):
|
||||
"""Polyline rail in the xz=0 plane. pts_xy: (x, y) knots -> one grind
|
||||
segment per span; feet dropped at feet_x (height lerped from the line)."""
|
||||
p = Prop(pid, 'obstacle', desc)
|
||||
p.add(STEEL, tube([(x, y, 0) for x, y in pts_xy], r, seg=10))
|
||||
def y_at(x):
|
||||
for (x0, y0), (x1, y1) in zip(pts_xy, pts_xy[1:]):
|
||||
if x0 - 1e-6 <= x <= x1 + 1e-6:
|
||||
return y0 + (y1 - y0) * (x - x0) / (x1 - x0)
|
||||
return pts_xy[-1][1]
|
||||
for fx in feet_x:
|
||||
p.add(GALV, tube([(fx, 0, 0), (fx, y_at(fx) - r, 0)], 0.018, seg=8))
|
||||
p.add(GALV, box(fx, 0.006, 0, 0.16, 0.012, 0.12))
|
||||
for (x0, y0), (x1, y1) in zip(pts_xy, pts_xy[1:]):
|
||||
p.grind(x0, 0, x1, 0, y0, y1, kind)
|
||||
p.collider = {'type': 'none'}
|
||||
return p
|
||||
|
||||
def square_flatbar():
|
||||
p = Prop('square_flatbar', 'obstacle', 'square-section flatbar')
|
||||
L, h = 2.4, 0.4
|
||||
p.add(STEEL, box(0, h - 0.03, 0, L, 0.06, 0.06))
|
||||
for fx in (-L / 2 + 0.2, L / 2 - 0.2):
|
||||
p.add(GALV, box(fx, (h - 0.06) / 2, 0, 0.05, h - 0.06, 0.05))
|
||||
p.add(GALV, box(fx, 0.006, 0, 0.16, 0.012, 0.12))
|
||||
p.grind(-L / 2, 0, L / 2, 0, h, h, 'rail')
|
||||
p.collider = {'type': 'none'}
|
||||
return p
|
||||
|
||||
def pole_jam():
|
||||
p = Prop('pole_jam', 'obstacle', 'bent pole jammed out of the concrete, 35 deg')
|
||||
L, ang = 1.7, math.radians(35)
|
||||
tip = (L * math.cos(ang), L * math.sin(ang))
|
||||
p.add(STEEL, tube([(-0.05, 0.0, 0), (tip[0], tip[1], 0)], 0.035, seg=10))
|
||||
p.add(CONC_R, box(0, 0.04, 0, 0.5, 0.08, 0.5)) # broken footing stub
|
||||
p.grind(0, 0, tip[0], 0, 0.05, tip[1], 'rail')
|
||||
p.collider = {'type': 'none'}
|
||||
return p
|
||||
|
||||
def sloped_box(pid, L, w, y0, y1, desc, mat=None, cat='obstacle', graf=False):
|
||||
"""Box whose top slopes from y0 (at -x) to y1 (+x): hubbas, manny pads."""
|
||||
mat = mat or CONC
|
||||
p = Prop(pid, cat, desc)
|
||||
rows = [[(-L / 2, y0, -w / 2), (-L / 2, y0, w / 2)],
|
||||
[(L / 2, y1, -w / 2), (L / 2, y1, w / 2)]]
|
||||
p.add(mat, sheet(rows, flip=True))
|
||||
for sz in (-w / 2, w / 2): # side walls
|
||||
pts = [(-L / 2, 0, sz), (L / 2, 0, sz), (L / 2, y1, sz), (-L / 2, y0, sz)]
|
||||
f = fan(pts, lambda pp: (pp[0], pp[1]), out=(0, 0, sz))
|
||||
p.add(mat, f)
|
||||
for sx, yy in ((-L / 2, y0), (L / 2, y1)): # end caps
|
||||
p.add(mat, fan([(sx, 0, -w / 2), (sx, 0, w / 2), (sx, yy, w / 2), (sx, yy, -w / 2)],
|
||||
lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
if graf:
|
||||
p.add(GRAF_B, uv_fit(fan([(-L / 2, 0, w / 2 + 0.003), (L / 2, 0, w / 2 + 0.003),
|
||||
(L / 2, y1, w / 2 + 0.003), (-L / 2, y0, w / 2 + 0.003)],
|
||||
lambda pp: (pp[0], pp[1]), out=(0, 0, 1))))
|
||||
for sz in (-w / 2, w / 2):
|
||||
p.grind(-L / 2, sz, L / 2, sz, y0, y1, 'ledge')
|
||||
p.collider = {'type': 'box', 'hw': L / 2, 'hd': w / 2, 'h': max(y0, y1)}
|
||||
return p
|
||||
|
||||
def hubba_down():
|
||||
# flat 0.8m at stair-top height, then down the imaginary stairs
|
||||
p = Prop('hubba_down', 'obstacle', 'flat-to-down hubba ledge')
|
||||
w, hf, hl = 0.42, 0.66, 0.12
|
||||
Lf, Ld = 0.8, 1.8
|
||||
top = sheet([[(-(Lf + Ld) / 2, hf, -w / 2), (-(Lf + Ld) / 2, hf, w / 2)],
|
||||
[(-(Lf + Ld) / 2 + Lf, hf, -w / 2), (-(Lf + Ld) / 2 + Lf, hf, w / 2)],
|
||||
[((Lf + Ld) / 2, hl, -w / 2), ((Lf + Ld) / 2, hl, w / 2)]], flip=True)
|
||||
p.add(CONC, top)
|
||||
x0, xk, x1 = -(Lf + Ld) / 2, -(Lf + Ld) / 2 + Lf, (Lf + Ld) / 2
|
||||
for sz in (-w / 2, w / 2):
|
||||
pts = [(x0, 0, sz), (x1, 0, sz), (x1, hl, sz), (xk, hf, sz), (x0, hf, sz)]
|
||||
p.add(CONC, fan(pts, lambda pp: (pp[0], pp[1]), out=(0, 0, sz)))
|
||||
p.add(CONC, fan([(x0, 0, -w / 2), (x0, 0, w / 2), (x0, hf, w / 2), (x0, hf, -w / 2)],
|
||||
lambda pp: (pp[2], pp[1]), out=(-1, 0, 0)))
|
||||
p.add(CONC, fan([(x1, 0, -w / 2), (x1, 0, w / 2), (x1, hl, w / 2), (x1, hl, -w / 2)],
|
||||
lambda pp: (pp[2], pp[1]), out=(1, 0, 0)))
|
||||
for sz in (-w / 2, w / 2):
|
||||
p.grind(x0, sz, xk, sz, hf, hf, 'ledge')
|
||||
p.grind(xk, sz, x1, sz, hf, hl, 'ledge')
|
||||
p.collider = {'type': 'box', 'hw': (Lf + Ld) / 2, 'hd': w / 2, 'h': hf}
|
||||
return p
|
||||
|
||||
def grind_box(pid, L, w, h, desc, mat=None):
|
||||
mat = mat or PLY
|
||||
p = Prop(pid, 'obstacle', desc)
|
||||
p.add(mat, box(0, h / 2, 0, L, h, w))
|
||||
for sz in (1, -1):
|
||||
p.add(STEEL, angle_cap(-L / 2, L / 2, h, sz * w / 2))
|
||||
p.grind(-L / 2, sz * w / 2, L / 2, sz * w / 2, h, h, 'ledge')
|
||||
p.element = {'kind': 'ledge', 'hw': L / 2, 'hd': w / 2, 'h': h}
|
||||
return p
|
||||
|
||||
def pyramid():
|
||||
p = Prop('pyramid', 'obstacle', 'four-sided pyramid, flat top, steel edges')
|
||||
B, T, H = 4.8, 1.6, 0.8
|
||||
p.add(PLY, box(0, H - 0.02, 0, T, 0.04, T)) # flat top
|
||||
for i in range(4): # four banks
|
||||
a = math.pi / 2 * i
|
||||
pts = [(-B / 2, 0, B / 2), (B / 2, 0, B / 2), (T / 2, H, T / 2), (-T / 2, H, T / 2)]
|
||||
f = fan(pts, lambda pp: (pp[0], pp[2]))
|
||||
f = rotate_y(f, a)
|
||||
ndir = (math.sin(a), 0.3, math.cos(a))
|
||||
d = sum(nn[k] * ndir[k] for nn in f['N'] for k in range(3))
|
||||
if d < 0:
|
||||
f['I'] = [f['I'][j + o] for j in range(0, len(f['I']), 3) for o in (0, 2, 1)]
|
||||
f['N'] = [(-x, -y, -z) for x, y, z in f['N']]
|
||||
p.add(PLY, f)
|
||||
for i in range(4): # top edge caps + grinds
|
||||
a = math.pi / 2 * i
|
||||
cap = rotate_y(angle_cap(-T / 2, T / 2, H, T / 2), a)
|
||||
p.add(STEEL, cap)
|
||||
ca, sa = math.cos(a), math.sin(a)
|
||||
rot = lambda x, z: (x * ca + z * sa, -x * sa + z * ca)
|
||||
ax, az = rot(-T / 2, T / 2); bx, bz = rot(T / 2, T / 2)
|
||||
p.grind(ax, az, bx, bz, H, H, 'ledge')
|
||||
p.element = {'kind': 'funbox', 'hw': B / 2, 'hd': B / 2, 'h': H, 'skirt': (B - T) / 2}
|
||||
return p
|
||||
|
||||
def euro_gap():
|
||||
p = Prop('euro_gap', 'obstacle', 'euro gap: bank up, sheer drop off the deck')
|
||||
w, h, run, deck = 2.4, 0.75, 1.5, 1.0
|
||||
rows = [[(-w / 2, 0, run + deck / 2), (w / 2, 0, run + deck / 2)],
|
||||
[(-w / 2, h, deck / 2), (w / 2, h, deck / 2)]]
|
||||
p.add(PLY, sheet(rows)) # bank faces +z
|
||||
p.add(PLY, box(0, h - 0.02, 0, w, 0.04, deck)) # deck
|
||||
p.add(CONC_R, box(0, h / 2 - 0.02, -deck / 2 + 0.02, w, h - 0.04, 0.04)) # drop face
|
||||
for sx in (-w / 2, w / 2):
|
||||
p.add(GALV, fan([(sx, 0, -deck / 2), (sx, 0, run + deck / 2),
|
||||
(sx, h, deck / 2), (sx, h, -deck / 2)],
|
||||
lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
p.add(STEEL, angle_cap(-w / 2, w / 2, h, -deck / 2))
|
||||
p.grind(-w / 2, -deck / 2, w / 2, -deck / 2, h, h, 'ledge')
|
||||
p.element = {'kind': 'bank', 'len': w, 'h': h, 'run': run}
|
||||
return p
|
||||
|
||||
def volcano():
|
||||
p = Prop('volcano', 'obstacle', 'concrete volcano cone, grindable rim')
|
||||
prof = [(2.2, 0.0), (1.55, 0.28), (1.0, 0.62), (0.64, 0.95), (0.5, 1.1)]
|
||||
p.add(CONC, lathe(prof, seg=20, cap_top=True))
|
||||
r, y = 0.36, 1.1
|
||||
for (ax, az), (bx, bz) in [((-r, -r), (r, -r)), ((r, -r), (r, r)),
|
||||
((r, r), (-r, r)), ((-r, r), (-r, -r))]:
|
||||
p.grind(ax, az, bx, bz, y, y, 'rail')
|
||||
p.element = {'kind': 'mogul', 'h': 1.1, 's': 1.5}
|
||||
return p
|
||||
|
||||
def roller():
|
||||
p = Prop('roller', 'obstacle', 'concrete speed roller / pump bump')
|
||||
L, R, H, n = 2.4, 1.1, 0.32, 10
|
||||
rows = []
|
||||
for i in range(n + 1):
|
||||
z = -R + 2 * R * i / n
|
||||
y = H * math.exp(-3.0 * (z / R) ** 2)
|
||||
rows.append([(-L / 2, y, z), (L / 2, y, z)])
|
||||
p.add(CONC, sheet(rows, flip=True))
|
||||
for sx in (-L / 2, L / 2):
|
||||
pts = [(sx, 0, -R)] + [(sx, H * math.exp(-3.0 * ((-R + 2 * R * i / n) / R) ** 2),
|
||||
-R + 2 * R * i / n) for i in range(n + 1)] + [(sx, 0, R)]
|
||||
p.add(CONC, fan(pts, lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
p.element = {'kind': 'mogul', 'h': H, 's': 0.9}
|
||||
return p
|
||||
|
||||
# ------------------------------------------------------------- street props
|
||||
def jersey_barrier():
|
||||
p = Prop('jersey_barrier', 'furniture', 'concrete K-rail jersey barrier')
|
||||
L = 2.0
|
||||
prof = [(0.30, 0.0), (0.30, 0.06), (0.115, 0.55), (0.095, 0.81),
|
||||
(-0.095, 0.81), (-0.115, 0.55), (-0.30, 0.06), (-0.30, 0.0)]
|
||||
rows = [[(-L / 2, y, z), (L / 2, y, z)] for z, y in prof]
|
||||
p.add(CONC_R, sheet(rows, flip=True))
|
||||
for sx in (-L / 2, L / 2):
|
||||
p.add(CONC_R, fan([(sx, y, z) for z, y in prof],
|
||||
lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
p.grind(-L / 2, 0, L / 2, 0, 0.81, 0.81, 'ledge')
|
||||
p.collider = {'type': 'box', 'hw': L / 2, 'hd': 0.3, 'h': 0.81}
|
||||
return p
|
||||
|
||||
def parking_block():
|
||||
p = Prop('parking_block', 'furniture', 'concrete parking block — slappy bait')
|
||||
p.add(Mat('conc_yellow', tex='concrete_rough', uv=1.4, tint=(1.0, 0.85, 0.45, 1)),
|
||||
box(0, 0.075, 0, 1.7, 0.15, 0.16))
|
||||
p.grind(-0.85, 0, 0.85, 0, 0.15, 0.15, 'ledge')
|
||||
p.collider = {'type': 'none'}
|
||||
return p
|
||||
|
||||
def hydrant():
|
||||
p = Prop('hydrant', 'furniture', 'fire hydrant — bonk it')
|
||||
RED = Mat('hydrant_red', tint=(0.72, 0.14, 0.1, 1), rough=0.55, metal=0.2)
|
||||
p.add(RED, lathe([(0.14, 0.0), (0.11, 0.1), (0.11, 0.55), (0.13, 0.6),
|
||||
(0.1, 0.7), (0.04, 0.78), (0.0, 0.8)], seg=12))
|
||||
p.add(RED, tube([(0, 0.45, -0.16), (0, 0.45, 0.16)], 0.05, seg=8))
|
||||
p.add(RED, tube([(-0.16, 0.45, 0), (0.16, 0.45, 0)], 0.05, seg=8))
|
||||
p.collider = {'type': 'cylinder', 'r': 0.2, 'h': 0.8}
|
||||
return p
|
||||
|
||||
def pool_edge():
|
||||
p = Prop('pool_edge', 'furniture', 'pool coping + tile band, 2m section')
|
||||
L = 2.0
|
||||
p.add(CONC_R, box(0, 0.06, -0.25, L, 0.12, 0.5)) # deck slab
|
||||
p.add(Mat('bullnose', tex='concrete_smooth', uv=0.6, rough=0.7),
|
||||
tube([(-L / 2, 0.13, 0.01), (L / 2, 0.13, 0.01)], 0.055, seg=10))
|
||||
p.add(Mat('tiles', tex='tiles_pool', uv=0.62),
|
||||
fan([(-L / 2, -0.32, 0.05), (L / 2, -0.32, 0.05),
|
||||
(L / 2, 0.05, 0.05), (-L / 2, 0.05, 0.05)],
|
||||
lambda pp: (pp[0], pp[1]), out=(0, 0, 1)))
|
||||
p.grind(-L / 2, 0.01, L / 2, 0.01, 0.185, 0.185, 'rail')
|
||||
p.collider = {'type': 'none'}
|
||||
return p
|
||||
|
||||
# ----------------------------------------------------------- infrastructure
|
||||
def fence_chain():
|
||||
p = Prop('fence_chain_3m', 'dressing', 'chain-link fence section')
|
||||
L, H = 3.0, 1.8
|
||||
MESH = Mat('chain_mesh', tint=(0.62, 0.66, 0.68, 0.38), rough=0.6,
|
||||
metal=0.7, double=True)
|
||||
p.add(MESH, fan([(-L / 2, 0.05, 0), (L / 2, 0.05, 0),
|
||||
(L / 2, H - 0.05, 0), (-L / 2, H - 0.05, 0)],
|
||||
lambda pp: (pp[0], pp[1]), out=(0, 0, 1)))
|
||||
p.add(GALV, tube([(-L / 2, H, 0), (L / 2, H, 0)], 0.021, seg=8))
|
||||
for sx in (-L / 2, L / 2):
|
||||
p.add(GALV, tube([(sx, 0, 0), (sx, H - 0.02, 0)], 0.024, seg=8))
|
||||
p.grind(-L / 2, 0, L / 2, 0, H, H, 'rail')
|
||||
p.collider = {'type': 'box', 'hw': L / 2, 'hd': 0.03, 'h': H}
|
||||
return p
|
||||
|
||||
def floodlight():
|
||||
p = Prop('floodlight', 'dressing', 'park floodlight pole')
|
||||
H = 6.0
|
||||
p.add(GALV, lathe([(0.09, 0.0), (0.07, H * 0.6), (0.05, H)], seg=10))
|
||||
p.add(GALV, box(0, H + 0.05, 0, 1.2, 0.08, 0.1))
|
||||
LAMP = Mat('lamp', tint=(1, 1, 0.92, 1), rough=0.3, emissive=(0.9, 0.9, 0.75))
|
||||
for dx in (-0.45, 0.45):
|
||||
p.add(LAMP, box(dx, H + 0.14, 0.04, 0.3, 0.18, 0.22))
|
||||
p.collider = {'type': 'cylinder', 'r': 0.12, 'h': H}
|
||||
return p
|
||||
|
||||
def bleachers():
|
||||
p = Prop('bleachers_3', 'furniture', 'three-row spectator bleachers')
|
||||
L = 3.0
|
||||
for i in range(3):
|
||||
y, z = 0.32 + i * 0.3, i * 0.5
|
||||
p.add(SLATS, box(0, y - 0.025, z, L, 0.05, 0.45)) # seat plank
|
||||
p.add(GALV, box(0, y - 0.15, z + 0.18, L, 0.24, 0.04)) # riser
|
||||
for sx in (-L / 2 + 0.1, L / 2 - 0.1): # side frames
|
||||
p.add(GALV, fan([(sx, 0, -0.25), (sx, 0, 1.25), (sx, 0.92, 1.25), (sx, 0.92, 0.75),
|
||||
(sx, 0.32, -0.25)],
|
||||
lambda pp: (pp[2], pp[1]), out=(sx, 0, 0)))
|
||||
p.grind(-L / 2, -0.225, L / 2, -0.225, 0.32, 0.32, 'ledge') # bottom row edge
|
||||
p.grind(-L / 2, 0.775, L / 2, 0.775, 0.92, 0.92, 'ledge') # top row edge
|
||||
p.collider = {'type': 'box', 'hw': L / 2, 'hd': 0.75, 'h': 0.92}
|
||||
return p
|
||||
|
||||
def drain_grate():
|
||||
p = Prop('drain_grate', 'dressing', 'flush drainage grate')
|
||||
p.add(Mat('grate', tex='steel_grate', uv=0.9, rough=0.5, metal=0.6),
|
||||
box(0, 0.011, 0, 0.9, 0.022, 0.6))
|
||||
p.add(CONC, box(0, 0.008, 0, 1.06, 0.016, 0.76))
|
||||
p.collider = {'type': 'none'}
|
||||
return p
|
||||
|
||||
# ---------------------------------------------------------------- build all
|
||||
BUILDERS = [
|
||||
lambda: quarter('qp_24', 2.4, 1.2, 1.8, 'plywood quarter pipe 4ft, steel coping'),
|
||||
@ -496,6 +770,30 @@ BUILDERS = [
|
||||
bench_park, bench_concrete, picnic_table, bin_council, bollard_steel,
|
||||
railing_ped, planter_box, kerb_3m, wall_graffiti, shade_sail,
|
||||
tree_fig, tree_gum, mound_dirt,
|
||||
# ---- expansion: modular editor set
|
||||
lambda: quarter('qp_vert', 3.6, 2.4, 2.7, 'vert quarter 8ft'),
|
||||
lambda: quarter('wallride_qp', 3.0, 1.5, 1.5,
|
||||
'wallride wall — transition to vertical', coping=False,
|
||||
deck=False, mat=CONC),
|
||||
lambda: kicker('launch_high', w=1.5, h=0.9, run=1.6, desc='high launch ramp'),
|
||||
square_flatbar, pole_jam,
|
||||
lambda: rail_from('rail_down', [(-1.5, 0.78), (1.5, 0.18)],
|
||||
(-1.3, 1.3), 'straight down rail'),
|
||||
lambda: rail_from('rail_kink2', [(-2.2, 0.68), (-1.0, 0.68), (0.1, 0.36),
|
||||
(0.9, 0.36), (2.2, 0.08)],
|
||||
(-2.0, -0.4, 0.6, 2.0), 'double-kink down rail'),
|
||||
lambda: rail_from('rail_aframe', [(-1.8, 0.12), (0, 0.72), (1.8, 0.12)],
|
||||
(-1.6, 0, 1.6), 'A-frame rail'),
|
||||
lambda: rail_from('rail_donkey', [(-1.6, 0.42), (0.6, 0.42), (1.5, 0.8)],
|
||||
(-1.4, 0.4, 1.35), 'donkey-kick rail — kinks up at the end'),
|
||||
lambda: grind_box('box_low', 1.8, 0.5, 0.25, 'low grind box 10in'),
|
||||
lambda: grind_box('box_table', 2.4, 0.7, 0.62, 'high table box 24in'),
|
||||
hubba_down,
|
||||
lambda: sloped_box('manny_incline', 2.0, 1.6, 0.18, 0.4,
|
||||
'inclined manual pad', graf=True),
|
||||
pyramid, euro_gap, volcano, roller,
|
||||
jersey_barrier, parking_block, hydrant, pool_edge,
|
||||
fence_chain, floodlight, bleachers, drain_grate,
|
||||
]
|
||||
|
||||
def main():
|
||||
|
||||
@ -38,11 +38,13 @@ def write_glb(path, gjson, bin_):
|
||||
|
||||
# ---------------------------------------------------------------- materials
|
||||
class Mat:
|
||||
"""tex: basename in textures/ (no ext) or None for flat colour."""
|
||||
"""tex: basename in textures/ (no ext) or None for flat colour.
|
||||
tint alpha < 1 -> BLEND (chain-link mesh); emissive -> emissiveFactor."""
|
||||
def __init__(self, name, tex=None, tint=(1, 1, 1, 1), rough=0.9, metal=0.0,
|
||||
uv=1.0, double=False):
|
||||
uv=1.0, double=False, emissive=None):
|
||||
self.name, self.tex, self.tint = name, tex, tuple(tint)
|
||||
self.rough, self.metal, self.uv, self.double = rough, metal, uv, double
|
||||
self.emissive = emissive
|
||||
def key(self): return self.name
|
||||
|
||||
# ---------------------------------------------------------------- part math
|
||||
@ -149,7 +151,10 @@ def lathe(profile, seg=16, jitter=None, cap_top=True, cap_bot=False):
|
||||
rows.append(row)
|
||||
# weld the seam ring so jitter matches
|
||||
rows[-1] = rows[0]
|
||||
pt = sheet(rows, flip=True)
|
||||
# rows=angle, cols=profile: unflipped winding already faces OUTWARD
|
||||
# (profile-tangent x angle-tangent = radial). flip=True shipped every
|
||||
# lathe inside-out — invisible on cylinders, obvious on the volcano cone.
|
||||
pt = sheet(rows)
|
||||
# match tube(): u wraps the girth, v climbs the profile (bark ridges stay
|
||||
# vertical — the transposed mapping chevroned the fig trunk)
|
||||
pt["UV"] = [(v, u) for (u, v) in pt["UV"]]
|
||||
@ -283,6 +288,8 @@ class Prop:
|
||||
"metallicFactor": mat.metal,
|
||||
"roughnessFactor": mat.rough}}
|
||||
if mat.double: m["doubleSided"] = True
|
||||
if mat.tint[3] < 1.0: m["alphaMode"] = "BLEND"
|
||||
if mat.emissive: m["emissiveFactor"] = list(mat.emissive)
|
||||
if mat.tex:
|
||||
if mat.tex not in teximg:
|
||||
ext = None
|
||||
|
||||
Loading…
Reference in New Issue
Block a user