Commit Graph
54 Commits
Author SHA1 Message Date
西风逍遥游 7ed1f25ffe fix(webgpu): align voxel validation semantics 2026-08-25 13:04:58 +08:00
西风逍遥游 9d41bdbe46 feat(webgpu): add gpu-driven depth occlusion 2026-08-25 12:50:29 +08:00
西风逍遥游 a48ad07227 fix(webgpu): align cascaded grass lighting 2026-08-25 12:36:42 +08:00
西风逍遥游 764cfc6fc0 fix(webgpu): wait for native texture readbacks 2026-08-25 12:03:02 +08:00
西风逍遥游 1250aee5bb fix(webgpu): reject silent hair shader substitution 2026-08-25 11:49:23 +08:00
西风逍遥游 80eb1ff749 fix(webgpu): preserve sprite stack shader semantics 2026-08-25 11:40:10 +08:00
西风逍遥游 73126b11bd feat(webgpu): port grass rendering 2026-08-25 11:33:43 +08:00
西风逍遥游 13d346a475 fix(webgpu): align cascaded shadow rendering 2026-08-25 10:10:30 +08:00
西风逍遥游 ebecf525b6 fix(webgpu): align texture sampling and mipmaps 2026-08-25 09:34:36 +08:00
西风逍遥游 f8d46c5d5b fix(webgpu): match Vulkan 2d lighting 2026-08-25 09:27:42 +08:00
西风逍遥游 2067d3ab89 feat(webgpu): add visibility-buffer resolve 2026-08-25 08:50:24 +08:00
西风逍遥游 76f5ffcdf6 feat(webgpu): add compute-culling indirect draws 2026-08-25 08:21:42 +08:00
西风逍遥游 cc3efcc224 feat(webgpu): enable deferred posts and macOS surfaces 2026-08-25 07:48:20 +08:00
西风逍遥游 fac833f542 feat(webgpu): add anisotropic hair rendering 2026-08-25 07:33:37 +08:00
西风逍遥游 8db82847db feat(webgpu): enable font atlas rendering 2026-08-25 07:27:23 +08:00
西风逍遥游 0002840ea1 fix(webgpu): retain custom shader modules through pipeline creation 2026-08-25 06:49:50 +08:00
西风逍遥游 2ec960db04 feat(webgpu): match deferred decals with Vulkan 2026-08-25 06:32:08 +08:00
西风逍遥游 115c9862ce feat(webgpu): support alpha-cutout deferred passes 2026-08-25 02:45:57 +08:00
西风逍遥游 16c0439989 feat(webgpu): align core resource and surface rendering 2026-08-25 02:33:12 +08:00
西风逍遥游 04b8824f56 feat(graphics): add unified transparency rendering 2026-08-24 16:00:37 +08:00
西风逍遥游 426059d299 Merge pull request #195 from EVEngine/codex/animskin-script-skinning-writeback
feat(animation): script-playable skeletal animation via AnimSkin writeback
2026-08-23 15:02:29 +08:00
西风逍遥游 c65daede2e feat(animation): script-playable skeletal animation via AnimSkin writeback
AnimSkin can now write CPU-skinning results back to the render mesh so skeletal animation actually plays from scripts:
- capture bind normals at fromModel and skin them per pose (updateSkinnedNormals / getSkinnedNormals, cofactor inverse-transpose + normalize)
- packed getSkinnedPositions() array getter, matching AnimLattice's script pattern
- one-call applyToMesh(gfx, mesh, pose): skin positions+normals then in-place gpu.updateMeshVertices
- Renderable3D.getMesh() script binding so createRenderable meshes are reachable
- Mesh::gpuVertexCount so getVertexCount() is correct for non-morph meshes (both backends)
- tests: packed positions == skinPositionsTo, normals follow pose and stay unit length, applyToMesh render test with in-place updates
- docs: animation/graphics user guides + design spec
2026-08-23 14:24:11 +08:00
西风逍遥游 5c3a4e2c0d feat(graphics): add in-place texture pixel updates (updateTexture) 2026-08-22 23:47:33 +08:00
西风逍遥游 9d4148cb6f fix(webgpu): mirror clip Y for WebGPU NDC and black default env cubemap
WebGPU NDC is Y-up while the engine feeds Vulkan-convention (Y-down) clip
matrices, so every 3D pass (mesh, clustered, gbuffer, shadow, voxel) rendered
vertically flipped - the floor appeared on top and lighting/AO landed in the
wrong places. Mirror clip Y in the vertex shaders.

The default env cubemap was pure white while RenderSystem3D passes
envIntensity=1.0 by default, washing the whole scene toward white; make the
default black so only an explicitly set envMap contributes IBL.

Also fix the half-res AO UV mapping (was overrunning into [0,2] and clamping
to the AO edge) and add the missing Vulkan setMesh3DSSAO override so the
native desktop build compiles.
2026-08-22 02:25:29 +08:00
西风逍遥游 83c0c2044e fix(webgpu): denoise SSAO with half-res target and softer weights 2026-08-22 01:37:38 +08:00
西风逍遥游 be4b8af5f1 feat(webgpu): 2D custom shader entry via newShaderFromWgsl 2026-08-22 00:18:29 +08:00
西风逍遥游 35499fbad8 feat(webgpu): clustered-forward lighting with SSBO light tables 2026-08-22 00:10:43 +08:00
西风逍遥游 b9af46b315 feat(webgpu): voxel vertex AO baking with fixed instance vertex layout 2026-08-21 23:43:03 +08:00
西风逍遥游 d15fd74359 feat(webgpu): screen-space ambient occlusion via G-buffer depth 2026-08-21 23:27:45 +08:00
西风逍遥游 acb5fbe09a feat(webgpu): render 3D scenes into offscreen canvases
begin3DFrameToCanvas no longer throws: the 3D pass renders into the target
canvas (RGBA8Unorm, 1-sample) using a dedicated 1x mesh3d pipeline variant,
since the scene pipelines follow the active MSAA count. renderScene3DToCanvas
also gets validation scopes matching render3D. The async frame readback now
follows the last 3D target (scene color or canvas) so screenshots work for
canvas-rendered frames too.

Known limitation: reading back a canvas that was also drawn as a 2D overlay in
the same frame can return black (emdawnwebgpu resource-state quirk).
2026-08-21 21:53:38 +08:00
西风逍遥游 59234f4931 feat(webgpu): MSAA for the 3D scene target
The scene color pass now renders into a multisampled attachment and resolves
to the single-sample color texture used by compositing and frame readback.
The mesh3d/voxel/custom-shader pipelines follow the active sample count and
are rebuilt when setMsaaSamples changes; WebGPU supports 1x/4x only, so values
>= 2 clamp to 4. setMsaaSamples also recreates the offscreen targets.
2026-08-21 21:15:52 +08:00
西风逍遥游 655672590f perf(webgpu): cache mesh3d bind groups per texture set
makeMeshBindGroup created a new bind group for every mesh draw every frame.
Dynamic UBO offsets are supplied at SetBindGroup time, so one bind group
serves all draws sharing the same texture views + shadow resources. Cache is
keyed by the 7 view/sampler pointers, capped at 128 entries, and cleared when
the mesh3d pipeline layout is recreated.
2026-08-21 20:52:19 +08:00
西风逍遥游 cffe868416 feat(webgpu): async frame readback + playground screenshot
Frame readback (saveFramePng/getPixel) previously crashed the WASM runtime
when called from the playground bridge: emscripten_sleep inside a deep
JS->Squirrel->Graphics call chain breaks ASYNCIFY (rewind hits 'unreachable').

- add async two-phase readback to the webgpu backend (beginFrameReadback /
  frameReadbackStatus, pumped from present() so the map callback is delivered
  on the browser event loop without sleeping)
- bridge: eve_playground_capture / eve_playground_readback_status /
  eve_playground_read_bytes (binary-safe VFS read)
- playground: 截图 button captures the current frame and previews the PNG
- bump ASYNCIFY_STACK_SIZE and TOTAL_STACK (1 MiB) for deep native chains
- export HEAPU8 for binary reads from the page
2026-08-21 20:49:29 +08:00
西风逍遥游 63445728e1 feat(webgpu): online playground with live script hot-reload
Adds a self-contained browser playground (editor + canvas + console + REPL)
around the Emscripten WebGPU build, plus the engine fixes required to render:
- JS<->Squirrel bridge (apply/eval/read/pause) and Emscripten 6 exports
- soft hot-reload via load.nut handle_change with __pg state preservation
- fix Uint16 index buffer byte sizes in SetIndexBuffer calls
- fix dangling GbufferSlot/SceneColorSlot gpuHandle pointers (std::move bug)
- fallback shadow depth texture when no shadow map is configured
- fix WGSL syntax (mod/ivec2) and default shadow sampler maxAnisotropy
- serve_webgpu.py COOP/COEP server and playground docs/demos/assets
2026-08-21 20:35:20 +08:00
西风逍遥游 34d1fdb63b refactor(modules): clear remaining back-edges and split the largest TUs (#127)
* chore(ci): add clang-format gate, CODEOWNERS and agent collaboration rules

* refactor(modules): clear remaining back-edges and split the largest TUs

Three known dependency back-edges are gone (module_depgraph.py KNOWN_BACK_EDGES
is now empty; --check passes with 0 violations, 0 cycles):

- window -> graphics: window queries the new IWindowSurfaceHost capability
  (common/WindowSurfaceHost.h) instead of holding a Graphics pointer;
  Window::setGraphics was removed and all call sites updated.
- window -> image: Window::setIcon was replaced by setIconRGBA(const uint8_t*,
  w, h); the window no longer decodes ImageData.
- scene -> graphics: pickScreenAt / collectFrustumIdsAt implementations moved
  to graphics/ScenePicking.cpp (graphics -> scene is a legal downward edge);
  scene now depends only on spatial.

TU splits (pure moves, verified identical method sets and brace balance):

- vulkan/Graphics.cpp (5118 lines) -> Graphics.cpp (lifecycle), GraphicsPipeline,
  Graphics2D, Graphics3D, GraphicsMesh + shared GraphicsInternal.h.
- scene/Scene.cpp -> Scene.cpp (script layer / host lifecycle / serialization)
  + SceneNodes.cpp + shared SceneInternal.h.

Verified with a real build (MSVC 19.51, prebuilt third-party): full build green;
window.* and Scene.* suites pass, including scene picking/culling and GPU cases.

* refactor(graphics): narrow Graphics interfaces and clear public-header leaks

Step 4 — interface segregation:
- New lean interfaces: IGraphics2D, IGraphics3D, IResourceFactory, IPostFX
  (pure virtuals, forward-declared types only; graphics/Color.h extracted from
  Canvas.h so modules that only need the color type stop pulling Canvas.h).
- Graphics now implements all four facets; consumers can depend on the narrow
  interface they use instead of the 129-method god class.
- Migrated voxel (VoxelWorld::drawVisible -> IGraphics3D*) and model3d
  (ModelRenderer::buildRenderable(s) -> IResourceFactory&).
- Graphics.h slims from 24 sub-header includes to a handful of small type
  headers + forward declarations; the destructor moved out-of-line so
  unique_ptr effect members are destroyed where types are complete.

Step 5 — header leaks (module_depgraph.py '*' marks: 14 -> 7):
- map/TileLayer.h, particles/ParticleEmitter.h, avatar/AvatarInstance.h,
  animation/SpineAnim.h, map/TileSystem.h, model3d/ModelData.h,
  model3d/ModelRenderer.h, audio/Audio.h + Source.h, image/ImageData.h +
  Image.h, dialogue/Dialogue.h, procgen Palette/OutputSpec/TextureRecipe/
  PbrMaterial -> forward declarations, includes moved to .cpp.
- voxel/VoxelWorld.h: terrain sampler Pimpl'd (unique_ptr + out-of-line
  destructor), removing the procgen header dependency.
- gpgpu/vulkan backend headers stop pulling graphics/vulkan/Graphics.h.
- Remaining '*' marks are deliberate: tiny POD/enum headers (GridConfig,
  MapObject, BlendMode, Color), an internal backend header
  (GraphicsInternal.h -> filesystem), and lean interface references.

Verified with a full clean build (MSVC) and tests: window/Scene/voxel/
RenderSystem/Quad/shader/TextureSampler/resourceLifetime pass; broad suite
only shows the pre-existing PHYSFS-init filesystem-environment failures.

* feat(resources): revive ResourceManager as unified IAssetReloader-backed cache

* fix(resources): leak ResourceManager singleton to avoid exit-time teardown crashes

Cached CPU resources may own third-party handles (FreeType faces, Assimp
scenes, image decode handlers) whose libraries are torn down at process
exit in an unspecified TU order; destroying cached entries from the
singleton destructor can segfault at exit (seen on CI Windows in
model3d.materialApi.objMtl). Keep the singleton alive until OS reclaim;
explicit unload()/clear() still release entries during the run.

* refactor(devtools): consume business modules through capability interfaces

DevTools / cmdline no longer include business-module headers, so trimming
scene / physics / procgen / particles / audio / ui / graphics no longer
requires disabling devtools, and devtools can be switched off with
-DEVENGINE_MODULE_DEVTOOLS=OFF.

New capability interfaces in common/:
- ISceneQuery (scene) - host/node inspection + mutation + transform sync
- IRenderCapture (graphics) - render status, PNG capture, camera control,
  visible-entity snapshot, entity-ID mask, G-buffer PNGs
- IPhysicsQuery (physics) - 2D world lifecycle + ray casts
- IProcgenQuery (procgen) - recipe listing, map/mesh generation
- IParticlesQuery (particles) - emitter status + one-shot emit
- IAudioQuery (audio) - volume / stop-all
- IEditorHost (ui) - declarative editor host (used by cmdline too)

Providers register in their module constructors. DevTools rewires McpServer
(render/scene/procgen/physics/particles/audio/host tools), SceneInspect
(now delegates to ISceneQuery + IRenderCapture) and RenderVision (uses
IRenderCapture::capturePngDataUrl); cmdline/Mcp.cpp uses IEditorHost.

manifest: devtools DEPS graphics scene physics procgen particles audio ui
image event filesystem -> event; cmdline DEPS filesystem ui -> filesystem.

Verified: full build green; devtools.mcp.* tests pass; broad suite shows
only the pre-existing PHYSFS-init filesystem-environment failures.

* style: apply clang-format to changed lines after dev merge

* fix(webgpu): include RenderControl/TextureSampler explicitly after Graphics.h slimming

* fix(webgpu): provide newFont/print stubs to satisfy IGraphics2D/IResourceFactory vtables

* fix(common): make ProcgenQuery.h self-sufficient (cstdint/utility for GCC)
2026-08-20 05:53:33 +08:00
西风逍遥游 da57cce5bb perf(graphics): frustum culling, once-per-frame lighting, drop GPU particle round-trip
- Mesh gains a model-space bounding sphere; RenderSystem3D now walks the ECS
  once per frame and culls draw units against the camera frustum (forward /
  G-buffer) and per-cascade light frustums (CSM) instead of re-walking the
  whole scene five times with no culling.
- Camera matrices, lighting packs and the clustered light table are resolved
  once per camera per frame; per-draw lighting becomes a cheap state toggle
  via the new Graphics::setMesh3DClusteredActive (Vulkan + WebGPU).
- The pseudo-GPU particle path (per-emitter upload -> dispatch -> synchronous
  readback every frame) is disabled; particles integrate on the CPU until a
  GPU-resident render path exists.
2026-08-19 23:46:16 +08:00
西风逍遥游 ff050687f4 fix(graphics): unify resource ownership, scope Color, make draw hooks pure
Add releaseTexture/releaseMesh/releaseShader to both backends and fix the contradictory ownership comments: handles returned by newTexture/newMesh/newShader are borrowed and Graphics owns the GPU resources until shutdown or an explicit release. Move the Color typedef into eve::graphics and migrate all module/test users. Turn the silently no-op drawSolidRectRotated / drawTexturedRectShaderUVRotated / drawTexturedRectShaderDepth and the validation-scope hooks into pure virtuals so a backend can never silently skip a draw.
2026-08-19 22:44:51 +08:00
西风逍遥游 e98f125f21 feat(voxel): close feature/perf gap vs mainstream voxel engines
- Cross-chunk seam culling via GreedyMesher::ChunkSampler; border edits now
  invalidate the adjacent chunk; air writes no longer allocate chunks
- selectVisible meshes only after range/frustum culling
- DDA voxel raycast (CPU + script getters)
- Parallel remeshDirty(maxThreads) with serial fallback; output equals serial
- Vertex AO: Minecraft-style 4-corner AO packed 2bit x 4, Vulkan instancing +
  voxel_rect shaders (SPIR-V .inc regenerated); WebGPU accepts params (TODO)
- Persistence: serializeWorld/deserializeWorld (EVVX LE) + saveWorld/loadWorld;
  unloadChunksOutside + streamAround for player-centered streaming
- Terrain: reuse procgen::TerrainSampler (no new module), setTerrainParams +
  terrainHeightAt; script setTerrain/streamAround
- CPU tests + gap-analysis/module/user docs; local MSVC harness 1741 checks pass
2026-08-19 04:13:21 +08:00
西风逍遥游 6199d94b9e feat(scene): optimize 3d scene loading pipeline 2026-08-18 09:47:19 +08:00
西风逍遥游 f07774109b Merge pull request #96 from EVEngine/codex/sprite-stacking
feat(spritestack): sprite-stacking pseudo-3D rendering
2026-08-17 16:28:59 +08:00
西风逍遥游 d71b126636 feat(particles): particle system feature set (P0-P2)
Rendering: rotation render fix, additive/opaque blend modes, flipbook animation, gradients and lifetime curves, unified DrawItem2D render path (Vulkan + WebGPU).

Simulation: timed bursts, prewarm, line/ring shapes, gravity, damping, velocity limits/curves, inherit velocity, local/world space, collision (bounds + resolver), CPU noise, sub-emitters, stretched trails, overflow policies, dt caps, offscreen sim skip.

Advanced: radial force fields, custom particle shaders, pooled Light2D particle lights, opt-in GPU-accelerated simulation with automatic CPU fallback.

Fixes: Vulkan pipeline builder lifetime bug (crash on window init), emitter-life emission timing, emit() syncs attachment position.

Tests: new coverage incl. scale regression (128 emitters).
2026-08-17 15:27:43 +08:00
西风逍遥游 fe7b68deb4 feat(spritestack): sprite-stacking pseudo-3D rendering 2026-08-17 13:58:03 +08:00
西风逍遥游 3cd783305b Merge pull request #70 from EVEngine/feature/cloud-shadows
feat(procgen): dynamic clouds + real-time cloud shadows on ground
2026-08-16 21:24:25 +08:00
sunxfancy 9d860e2d66 Merge remote-tracking branch 'origin/main' into feature/water-shader
# Conflicts:
#	src/modules/graphics/Graphics.cpp
2026-08-16 19:47:03 +08:00
西风逍遥游 812e932568 Merge remote-tracking branch 'origin/main' into HEAD 2026-08-16 15:58:51 +08:00
sunxfancy 166a956724 feat(graphics): render 3D scene into an offscreen Canvas (render-to-canvas)
Add begin3DFrameToCanvas / end3DFrameToCanvas on Graphics: open a 3D render
pass targeting an offscreen Canvas (color + D32 depth) at the canvas size,
using setMesh3DViewProj/View/CameraPos/Env as the camera. Rendered on a
dedicated command buffer and submitted directly to the graphics queue, so it
does not touch the swapchain / present flow. Enables render targets such as a
mirror-camera planar reflection (reflection captured, though compositing it
into a live scene is a follow-up).

Vulkan: offscreen3D render pass + mesh3d pipeline + pool/cb/fence, canvas
gets a depth attachment + color+depth framebuffer; currentPresentCb/frameToken
route to the offscreen cb during the pass. WebGPU: unsupported (throws).

Test: graphics.render3d.toCanvas renders a red box into a canvas and reads it
back to confirm the scene lands in the offscreen target.
2026-08-16 14:59:03 +08:00
西风逍遥游 5771b193b7 feat(graphics): x-ray occluded-character shader (vulkan + webgpu)
Show only the part of a marked character that is hidden behind a building,
as a filled highlight silhouette (Overwatch-style). Visible parts render
normally.

- Shader: xray_mesh.frag samples G-buffer hardware depth (binding 7) and
  compares it against its own fragment depth: occluded (behind) pixels emit
  the highlight, visible pixels discard. Drawn as a second pass over the
  scene with depth test/write off + alpha blend.
- RenderSystem3D: MeshRenderer gains xrayShader + xrayHighlight. X-ray
  targets are skipped in the G-buffer (their pixels record occluder depth),
  then redrawn with the X-ray shader; scene depth is bound via
  Graphics::setMesh3DSceneDepth.
- Graphics: new setMesh3DSceneDepth + Shader::setXray. Vulkan adds binding 7
  to the mesh3d set layout and a dedicated X-ray pipeline variant.
- WebGPU: new newMeshShaderFromWgsl (WGSL custom mesh shaders), scene-depth
  binding 9, X-ray pipeline variant, xray params packed into the Frame UBO,
  and the G-buffer hardware depth is exposed/sampleable (getHwDepthTexture).
  AO (SPIR-V) is skipped on WebGPU via supportsGBufferPost.
- stylize: 'xray' style registered (createMeshShader dispatches SPIR-V on
  Vulkan / WGSL on WebGPU) with push-constant params.
- Tests: test/Xray.cpp (shader/flags + occluded-silhouette render smoke).
2026-08-16 04:08:55 +08:00
西风逍遥游 d3636c7e4e Merge branch 'main' into feature/cloud-shadows 2026-08-15 23:45:14 +08:00
西风逍遥游 d128760985 feat(graphics): enhance 3D rendering with scene color resolve and canvas support
- Introduced `drawScene3DRGBA` and `drawCanvasRGBA` methods for improved 3D scene rendering and canvas drawing.
- Added `prepareSceneColorResolveShader` to handle FXAA settings for scene color resolution.
- Updated `Graphics` class to manage overlays and batch rendering more effectively.
- Enhanced exposure of new methods to scripting for better integration and usability.
2026-08-15 21:59:15 +08:00
sunxfancy 4fdacceadd feat(procgen): dynamic clouds + real-time cloud shadows on ground
Add procedural cloud generation and dynamic cloud shadows that darken the
ground as clouds drift overhead.

Procgen (CPU, fully testable):
- CloudField: deterministic, seamlessly-tiling, time-animated 2D cloud
  coverage over the XZ plane (domain-warped value-noise fBm, wind drift,
  wisp detail). coverageAt(x,z,t), sample(...).
- CloudShadow: projects clouds along the sun onto the ground plane
  (coverageAt / shadowFactorAt / bake), accounting for sun direction and
  cloud altitude.
- New recipes: tex.cloud (cloud cover), tex.cloud_shadow (projected
  ground shadow coverage).
- Procgen module + script API: newCloudField/newCloudShadow,
  cloudCoverageAt/cloudShadowFactor, sampleCloud/sampleCloudShadow.

Graphics (real-time):
- setCloudShadows() packs {strength, worldCell, time, wind, coverage,
  detail} into the Mesh3D UBO (default strength 0 = no change).
- mesh3d PBR shaders (Vulkan GLSL + regenerated SPIR-V, and WebGPU WGSL)
  sample an inline seamless cloud field in world XZ and modulate the
  primary directional light.

Tests: CloudField reproducibility/animation/seamless tiling, wind drift,
shadow projection & factor bounds, recipe generation, module API, and a GPU
render test proving clouds darken the ground and the effect resets when
disabled. Verified no regression on the default PBR path (ClassicScenes
pbrChart + hexplanet render tests).
2026-08-15 21:42:07 +08:00