Render 3D play mode on macOS via Metal instead of SceneKit#19
Open
colemancda wants to merge 29 commits into
Open
Render 3D play mode on macOS via Metal instead of SceneKit#19colemancda wants to merge 29 commits into
colemancda wants to merge 29 commits into
Conversation
- Updated junkbot.ldr model with detailed comments and improved structure. - Introduced Package.resolved to manage dependencies with swift-lego-draw. - Modified Package.swift to include swift-lego-draw as a dependency. - Removed obsolete LDrawColorTable and LDrawLoader implementations. - Added LDrawSupport for parsing and resolving LDraw models using swift-lego-draw. - Enhanced LDrawModel to utilize new LDrawSupport for loading models. - Updated SceneBuilder to support oblique shear transformation for rendering. - Improved main.swift to handle new command-line options and integrate LDrawSupport.
Adds a custom Metal renderer (Metal3DManager and friends) that replaces SceneKit as the live 3D rendering path on macOS: procedural brick geometry, all 15 baked LDraw entity models including Junkbot's animated walk-cycle legs, and the level backdrop image, framed with the same oblique-shear + orthographic camera the SceneKit path used. tools/Junkbot3D gains a parallel bake step that flattens each entity's LDraw model into JSON vertex data (Metal3DExporter) alongside the existing .scn bake output. Scene3DManager and the rest of the SceneKit path stay in the tree, unused on macOS - iOS/tvOS still render 3D mode via SceneKit as before.
Replaces the shader's ad hoc key/fill light weights (no reference behind their values) with the exact ambient/directional light color and intensity from three-stuff/3d-main.js's setupScene: AmbientLight(0xdedede, 0.8) added flatly, DirectionalLight(0xffffff, 0.8) at (-1000, 3200, 1500) scaled by N.L - matching the same light SceneBuilder.swift already ported to SceneKit.
…3D path GameEngine.backgroundDecals/decals were internal, making them unreachable from JunkbotMobile entirely - neither the SceneKit nor Metal 3D renderer ever drew them, even though the 2D path always has. Makes both properties public (matching backdropSpriteID's existing precedent) and adds Metal3DManager.loadLevelDecals, which resolves each decal's sprite and draws it as an unsheared textured quad at RenderList.swift's exact per-layer offsets, layered between the backdrop and entities.
Mirrors the macOS Metal renderer's scope (procedural bricks, all 15 baked LDraw entity models incl. Junkbot's walk-cycle rig, backdrop image, level background decals) using raw Vulkan calls via a new CVulkan system-library target bridging the NDK's own headers - no Swift/Vulkan wrapper package exists anywhere. Reuses the portable Metal3DSpace/Palette/Matrix/Model/ BrickGeometry files unchanged across platforms via a small SIMDShim.swift (Apple's simd module - float4x4 and friends - doesn't exist on Linux/ Android). Shaders are GLSL compiled to SPIR-V offline via glslc and committed, following this repo's existing bake-and-commit pattern. Junkbot's chest emblem is now baked to a PNG offline too (CoreGraphics isn't available on Android), shared by both the Metal and Vulkan paths. Also fixes Settings.swift never being symlinked into the shared SDL3/SDL2/ Android source tree despite Screens.swift (which all three build) already referencing Settings.render3DEnabled - every non-Darwin port's build was broken by this before now.
The Nintendo DS port now draws bricks and entities as flat-colored 3D boxes on the hardware 3D layer (MODE_5_3D's BG0) instead of blitting 2D sprites into a bitmap background. The baked LDraw geometry the Metal/Vulkan ports use is far too large (~8-10MB vs a ~2.48MB ARM9 budget) and too dense (a single model can exceed the DS GPU's ~3-4k triangle/frame ceiling), so every brick/entity is a single procedural box (Geometry3D's unit cube, scaled and positioned per draw) sized to its sprite footprint. The 3D look comes from the same oblique-projection shear the web three.js reference (three-stuff/3d-main.js's obliqueProjection) and the macOS Metal renderer use - alpha=pi/4, Szx=-0.5cos, Szy=-0.5sin - injected into the DS projection matrix via glMultMatrix4x4, with Szy sign-flipped for this port's +Y-screen-down convention. The room backdrop stays a 2D bitmap on BG3, composited behind the transparent-cleared 3D layer in hardware; the top screen's text is untouched.
Each box's faces are now shaded by the DS's fixed-function lighting engine instead of a single flat color, giving the flat-colored boxes readable depth (lighter top, darker sides). Geometry3D emits a per-face normal; Renderer3D sets up one directional light matching the three.js/Metal sun direction plus a strong ambient floor (ambient+diffuse material split so a lit face reads at full color and a shadowed face at ~half, never black). The per-box non-uniform scale is applied in GL_POSITION matrix mode only, so it never reaches the vector (normal) matrix - kept at identity - which would otherwise distort the normals and wreck the shading.
- Introduced a new `Models` struct containing hand-authored low-poly models for various Junkbot entities, including bricks and characters. - Implemented a `Mesh` structure to represent the geometry of these models. - Updated the `Renderer3D` to utilize the new models, replacing the previous sprite-blit method with 3D rendering using the DS's fixed-function GPU. - Added caching for entity and brick models to optimize rendering performance. - Adjusted lighting and material settings to ensure consistent visual output across different entity types.
…w-poly models A Swift App Playground (tools/ModelStudio.swiftpm) that previews the same hand-authored low-poly entity models the Nintendo DS port renders, but with a live turntable, a sidebar list, and a fast edit/build loop instead of rebuilding a .nds and loading an emulator. Each model is written in a small Swift '3D DSL' (MeshDSL.swift): a @resultBuilder of value-type primitives - Box, Stud, CylinderY, CylinderX, Disc, Cone - that compile straight to per-color SceneKit geometry, lit with an ambient floor + directional key light chosen to match the DS renderer. One file per model under Models/, registered in ModelLibrary. The DSL mirrors the DS Mesh primitives and stud-unit conventions so a model dialed in here ports directly to the fixed-point DS builder. Materials are double-sided (the primitives don't emit a consistent winding), mirroring the DS renderer's POLY_CULL_NONE.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Metal3DManagerand supporting files) that replaces SceneKit as the live 3D play-mode rendering path on macOS: procedural brick geometry, all 15 baked LDraw entity models (including Junkbot's animated walk-cycle legs), and the level backdrop image, framed with the same oblique-shear + orthographic camera the SceneKit path used.tools/Junkbot3Dgains a parallel bake step (Metal3DExporter) that flattens each entity's LDraw model into JSON vertex data alongside the existing.scnbake output.Scene3DManagerand the rest of the SceneKit path stay in the tree, unused on macOS - iOS/tvOS are unaffected and still render 3D mode via SceneKit.Test plan
tools/Junkbot3Dbuilds and--bake-allregeneratesModels3D/*.jsonalongside.scnxcodebuild -scheme Junkbot-macOSbuilds successfully