Picture in Picture Port | True PiP [Regular Branch]#579
Draft
TheLostInPlace wants to merge 16 commits into
Draft
Picture in Picture Port | True PiP [Regular Branch]#579TheLostInPlace wants to merge 16 commits into
TheLostInPlace wants to merge 16 commits into
Conversation
…le fixes PiP/SVP scope rendering (DX11), DLSS-SR scaffolding behind r__svp_dlss, smooth/analog scope zoom, hybrid reticle fixes, per-viewport motion vectors, AVX2 build flags, 3DSS magnification script.
Contributor
Author
|
Temporarily putting the PR on draft while I investigate an edge case of scopes not rendering their PiP viewport onto the eyepiece properly on (1) weapon that I have found so far, I thought I fixed the error for all weapons ;-; |
Contributor
Author
|
Alright that was a quick investigation, turns out that weapon had an improperly positioned eyepiece mesh resulting in the PiP drawing incorrectly |
Contributor
Author
37bec70 to
7ef0ff6
Compare
- derive the eyepiece from the lens bone skinning matrix instead of the kinematics root, so a scope skinned to an offset bone sits on the glass and tracks ADS instead of landing at a fixed offset - force the SVP camera up to world up so a canted scope renders upright while its reticle stays canted - among multiple lens surfaces keep the eye-nearest in-front one (the ocular) - take the eyepiece center from the lens AABB
New options_modded_exes_pip.script page exposing the SVP scope cvars as dropdowns/sliders: r__svpscope (OFF/Eyepiece/Objective), g_zoom_smooth, g_zoom_analog, r__svp_render_scale, r__svp_dlss, r__scope_debug. Registered in the Visual group next to 3D Scopes. Adds the eng localization in ui_mm_modded_exes.xml: page title, menu entry, control labels and hints, plus the ui_mm_lst_Eyepiece/ui_mm_lst_Objective list-value strings the r__svpscope dropdown resolves through.
Engine scope_lensfx pass over the composited disc (works with any scope mod, never touches 3DSS): magnification tunnel, radial blur, barrel distortion and exit-pupil dimming, plus a dynamic eye-box crescent. Gated by r__svp_lensfx / r__svp_eyebox, every value a cvar. r__svp_recoil_comp pulls the SVP camera orientation toward the main view in proportion to the live recoil so a PiP scope tracks your aim instead of the weapon bone during fire. SVP-only, the real recoil is untouched. In-game tuner overlay (lens_fx_tune.script + ui_lens_fx_tune.xml) plus the lens cvars and the tuner open key in the Modded Exes Picture in Picture page, and the CWeapon zoom methods exposed to Lua so the tuner can drive the scope.
r__svp_recoil_hold (0-1): while a PiP/SVP scope is up, damp the weapon shoot-shake and inertion in CWeapon::UpdateHudAdditional so the optic stays on the eyeline during fire instead of riding the gun. SVP-only, default off; iron sights / 3DSS / hipfire keep their full movement. recoil-comp (added in the previous commit) is orientation-only, so the magnified view never zooms with recoil. The MT intermediate that also blended the eyepiece position (which fought svpCamera's FOV sizing and caused the drift) was not introduced in this port, so position steadiness is recoil_hold's job.
The scene is captured against the main frustum and rendered twice, so the SVP resubmitted the whole main frustum world through a magnified cone that sees only a fraction of it, paying full vertex and draw cost for geometry the GPU then clips. Reject each item whose world bounding sphere is fully outside the SVP frustum, built from the same matrices[1] SetActive renders the SVP with so it removes exactly what the GPU would clip. Static world geometry carries no per item matrix so its world space vis.sphere is tested directly, dynamics scale the object space sphere by their world matrix. Gated to the SVP gbuffer pass so the main view and non PiP renderers stay byte identical. Measured on MT the SVP gbuffer drops from about 17ms to 2 to 8ms scaling with zoom. Default on, r__svp_cull 0 restores the old path. Keeps a temporary [SVPCULL] tested and culled diagnostic, stripped once the in game numbers check out.
…ter + SSS fixes Recoil - Add r__svp_pupil_boost (default 6), enlarges the 3DSS scope exit pupil while a PiP scope is up so full auto recoil no longer collapses the lens to black. The blackout is the 3DSS parallax exit pupil shadow driven by V_tangent, a larger EXIT_PUPIL widens the clear disc and divides down the recoil shift. - Remove r__svp_recoil_comp, recoil_hold and recoil_smooth plus the g_pip_recoil plumbing, they steered the SVP image not the shadow and never fixed the blackout. - Default stabilize and zoom_smooth to 1, pupil_boost to 6, eyebox_shift to 0. Performance - Add r__svp_cull_grass, per instance frustum reject so the SVP grass is culled to the scope cone, the cull frustum arming decoupled so grass and geometry cull toggle apart. - Add r__svp_skip_motionblur, skip_volumetric and skip_grass for the scope pass. Reflections and water - Add r__svp_skip_ssr, 0 reflective water, 1 flat water plus SSR (default), 2 matte. force_water_reflect un-flattens the SVP water at level 0. - The scope water SSR temporal reprojection already reprojects against the per viewport history here (mm_saved_viewproj and saved_position indexed by viewport) so the matte vs reflective flicker the MT fix targets does not occur, no port. SSS - Add r__svp_sss_sun (default off). The non-MT already runs the SVP SSS pass per viewport, this sets force_svp_sss around the SVP sun cascade accum so the scope sun keeps the SSS contact term. Ported from MT 3463300, adapted to the non-MT render structure: the recoil removal lands in the inline lens derive (no deriveScopeLens), the SSS sun hook in render_sun_cascades (no dual_accum), and the combine gates key on IsSVPFrame.
…l-pip-regular # Conflicts: # src/Layers/xrRenderPC_R4/r4.cpp
Contributor
Author
|
Mmm... something broke here while I was porting MT code fixes and optimizations, I decide to try and run non-mt and it's busted Trying to figure out, might not get to it till tomorrow |
…cull - Eyepiece derives from the captured N.val.Matrix, not get_xform_world (post V->Render), which sat ~15cm off and blacked the exit pupil - r__svp_occlude (default 0): rebuild HOM from the scope cone for indoor occlusion - SVP frustum-cull reject hooks across the static/dynamic/landscape draw loops
- r__svp_pupil_track ramps pupil_boost with the live bore off-axis drift, so the exit pupil stays tight when steady and opens only under recoil (default 0) - r__svp_reticle_mag drives shader_scope_params (curMag/min/max) from the engine each SVP frame, so the FFP reticle scales with zoom regardless of the 3DSS zoom script state (default 1) Ported from MT 08479f9, adapted to non-MT (no true_pip_on, gate on IsSVPActive)
svp_cull_reject tested dynamic objects by transforming their vis.sphere, but a skinned sub-visual sphere is baked at the rest pose and does not track the animated bones, so a close NPC (a bent head, a hood) read outside the scope cone and got dropped. Skip the cull for dynamic entirely, only ~57 objects so the savings are negligible, and the static world (no skinning) is unaffected. Ported the NPC-cull half of MT e01733a. The other half (shared wmark/sorted list consumption) does not apply to non-MT: it re-traverses the dsgraph per viewport instead of sharing one capture, so each pass rebuilds and clears its own lists.
per-scope optics + two-zone eye-box + scope_lensfx cosmetics, SVP small-object cull, 3DSS cosmetic gate, per-viewport skybox motion vectors, recoil gate via is_svp_active engine binding, svpscope-2 aliased to the eyepiece (no objective camera on regular), LTCG:INCREMENTAL on the WPO configs, dead-cvar cleanup
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.
True picture-in-picture scopes + per-scope optics + SVP DLSS-SR scaffolding (DX11)
Summary
Adds true picture-in-picture (PiP) scope rendering to the engine: the scoped image is a real
second render of the scene from the optic's camera, composited through the lens instead of the flat
FOV/zoom trick. On top of that it adds a physically-derived optics layer (real per-scope eye
relief / exit pupil, two-zone eye-box, lens cosmetics), a 3DSS cosmetic gate that removes the
flat-scope parallax-shadow crescent for optical scopes, SVP culling (frustum + small-object), and
all engine-side scaffolding for a future DLSS-SR upscale of the scope render (reconstruction left
as a documented stub).
The feature is DX11-only (R4), additive, and off by default. With
r__svpscope 0the render isbyte-identical to stock, and the DX10/9/8 renderers (R1/R2/R3) are fully insulated. This is the
single-threaded (non-MT) renderer, so all of the added state is plain, with no atomics or
cross-thread synchronization.
all-in-one-vs2022-wpoRequirements
PiP renders the scene into the in-world scope lens, so it relies on the 3D Shader Scopes (3DSS)
GAMMA addon to supply that lens geometry and reticle. 3DSS is already bundled in GAMMA, so GAMMA
users have it by default and no extra setup is needed. Without 3DSS (or an equivalent scope-lens
setup) there is no lens surface for the PiP image to composite into, and
r__svpscopehas nothingto draw. The real per-scope optics path (
r__svp_optics_real) reads the eye-relief / exit-pupilvalues from the 3DSS scope config; scopes without those entries fall back to geometry-derived values.
What's new (user-facing)
parallax, depth, and lighting inside the optic), with smooth and analog (variable) zoom, magnifier
reticle, integrated/variant scope fixes, and an over-zoom guard
physical eye-box (the dark vignette tightens as you move off the exit pupil and as magnification
rises), with an optional two-zone (exit-pupil + eye-relief) model
shadow crescent / blackout, chromatism, and NVG blur at the source (thermals and see-through optics
keep their stock look)
chromatic fringing, radial vignette, procedural dirty-glass grunge + edge rim, and a field-curvature
edge ring blur, all gated and tunable, with an in-game tuner page
(the SVP g-buffer is draw-call bound, so this is the main performance lever), plus optional cone
occlusion culling and supersample
and TAA-stable while panning (including a per-viewport sky-prev fix so the sky reprojects correctly
under the scope camera)
on the eyeline; base engine/weapon recoil is untouched
Console Variables (default collapsed)
Console variables
The
r__cvars are registered only under DX11, so they do not exist on DX10/9/8. Theg_zoom_*cvars are engine-side and apply on every renderer.Core
r__svpscopeReal optics & eye-box (the physical model, master-gated by
r__svp_truepip)r__svp_truepipr__svp_optics_realr__svp_optics_softr__svp_optics_gainr__svp_optics_zoomvigr__svp_optics_zoomvig_blendr__svp_eyebox_reliefr__svp_eyebox_relief_sizer__svp_eyebox_relief_softr__svp_eyebox_aspectLens FX (gated by
r__svp_lensfx; cosmetics also active underr__svp_truepip)r__svp_lensfxr__svp_lensfx_strengthr__svp_lens_car__svp_lens_distortr__svp_lens_floorr__svp_lens_refmagr__svp_lens_vigkr__svp_lens_blurr__svp_lens_fringer__svp_lens_vignetter__svp_lens_vignette_rr__svp_glass_dirtr__svp_glass_rimr__svp_dofr__svp_dof_onsetr__svp_eyeboxr__svp_eyebox_shiftr__svp_lens_menu_keyr__svp_stabilizePerformance
r__svp_cullr__svp_cull_ssar__svp_cull_grassr__svp_occluder__svp_supersampler__svp_adaptive_resr__svp_lodr__svp_skip_motionblurr__svp_skip_ssrr__svp_skip_volumetricr__svp_skip_grassr__svp_sss_sunr__svp_diagRecoil
r__truepip_recoilReticle / DLSS scaffolding / debug / dynamic zoom
r__svp_obj_distr__svp_obj_sizer__svp_reticle_magr__svp_dlssr__svp_render_scaler__scope_debugg_zoom_smoothg_zoom_analogHow it works
Second viewport / double-pass. When PiP is active the optic camera is built into
Device.matrices[1](svpCamera) and the scene is rendered a second time into a dedicatedsecond-viewport target (
TargetSVP) with its own per-target g-buffer, depth, and color. The pass isselected by the existing second-viewport frame flag (
IsSVPFrame), so the main pass and the scopepass each render with the correct camera and targets.
Lens composite. The scope target is sampled by the lens shader and composited on-screen through
phase_3DSSReticlewith the reticle, supporting smooth and analog zoom. Withr__svpscope 0thelegacy see-through scope path is preserved as the fallback.
Real optics & cosmetic gate. With
r__svp_truepipon, the eye-box is built from real geometry:eye relief and exit pupil come from the 3DSS scope config (
r__svp_optics_real), the clear zone growswith the exit pupil and tightens with magnification, and the eye offset is the real bore-vs-aim drift.
For optical scopes it also clears the 3DSS flat-scope SETTINGS bits (parallax shadow, chromatism, NVG
blur) and strips the fisheye so the magnified image is clean, while thermals and see-through optics are
left untouched.
Per-viewport correctness. Lighting, shadows (via the shared shadow-map accumulation), motion
vectors, and the skybox previous-frame transform are tracked per viewport. Previous-frame matrices,
foliage / skinned transforms, and the sky-prev matrix live in
[2]arrays indexed by the activeviewport, so the scope image is correctly lit and stays motion-vector / TAA stable when panning.
Culling. The scope geometry is frustum-culled to the cone, and a magnification-aware small-object
cull (
r__svp_cull_ssa) drops tiny distant clutter the magnified cone can't resolve; grass is culledto the cone, with optional cone occlusion culling for indoor/urban scenes.
Recoil gate.
r__truepip_recoilcontrols a small runtime gate (zzz_truepip_recoil_gate.script,backed by an
is_svp_active()Lua binding) that neutralizes a script recoil mod's per-shotcamera/PP/FOV kick while a true-PiP scope is active. It is a runtime monkey-patch only — it edits no
files, and the base Anomaly engine/weapon recoil is untouched.
DX11-only insulation. Every PiP/DLSS code path in the shared
Layers/xrRenderfiles is wrappedin
#if defined(USE_DX11), and the cvars above are not registered on DX10/9/8, so every sharedrender path collapses to stock for R1/R2/R3.
DLSS-SR scaffolding (gated, eval stubbed)
All engine-side plumbing for a Streamline DLSS-SR upscale of the scope render is present behind
r__svp_dlss, with the reconstruction itself left as a documented stub:lens first appears, zoom-type change, target re-create), read and cleared at the seam
SvpDlss.h) carrying color, depth, and motion-vector SRVs, the outputtarget, matrices, jitter, and camera params, with zero
sl::/ NGX dependenciesEvalSVP_DLSSis a 1:1 copy passthrough, and replacing its body is the only remaining stepSvpDlss.hdocuments the open interface items (depth form, output format, exposure, colour space,jitter convention, resource state) for whoever wires up the actual eval. The contract is identical
to the MT branch's, so the eval body is shared between them.
Invariants held:
r__svp_dlss == 0the output and GPU work are byte-identical to the non-DLSS path for anyr__svp_render_scale(the scale is forced to 1.0 at the gate)with no atomics or cross-thread synchronization needed
Compatibility & safety
#if defined(USE_DX11),cvars unregistered, shared gates collapse to stock
r__svpscope 0is stock behaviourTesting
Tested on GAMMA (Anomaly 1.5.3 base, with 3D Shader Scopes, SSS, Atmospherics):
reticle, smooth zoom, real per-scope eye-box, and the 3DSS cosmetic gate all working
r__svpscope 1and2) confirmed clean in-gameKnown limitations
r__svp_dlss 1runs a passthrough stubr__svpscope 2) is aliased to the eyepiece (1) on this branch: thesecond-viewport composite paints onto the eyepiece lens without reprojecting the objective view, so
true objective mode isn't supported here (the objective derivation is kept for a future
reprojection-aware path)
r__svp_adaptive_res) and LOD scaling (r__svp_lod) are presentbut currently inert on this single-threaded branch (the per-frame scope-target resize hook is
MT-only); the small-object cull (
r__svp_cull_ssa) is the active performance lever, and supersampleapplies on vid_restart
r__truepip_recoil) targets a script recoil mod's camera kick; with no such modpresent it is a no-op (base engine recoil is never touched)
Attribution
The true picture-in-picture scope code was written by m22spencer. This is a port of it from the
gc64 fork that adopted it (CnRJay/xray-monolith-gc64).
The DX11 second-viewport rendering, the lens composite (
draw_scope), the per-viewport history, andthe DLSS input contract all follow that implementation. The per-scope optics, cosmetic gate, lens
cosmetics, and SVP culling were added on top.
xray-monolithengine this targetsFiles changed
117 files, grouped by area
Gamedata (new)
gamedata/scripts/zzz_extra_scope_features.script: magnification and zoom utilitygamedata/scripts/zzz_truepip_recoil_gate.script: optional script-recoil gategamedata/scripts/lens_fx_tune.script,gamedata/configs/ui/ui_lens_fx_tune.xml: in-game lens FX tuner pagegamedata/scripts/options_modded_exes_pip.script: PiP options pagegamedata/shaders/r3/scope_lensfx.{ps,s}: lens FX (CA, barrel, dim, eye-box, cosmetics)gamedata/shaders/r3/scope_{debug,depth_write,color_write,vertex,custom_depth,defines}.*: scope debug and depth/colour-write shadersConsole / cvars
xrRender_console.cpp/.h,xrEngine/xr_ioc_cmd.cppxrGame/console_registrator_script.cpp:is_svp_active()Lua binding for the recoil gateShared render layer (xrRender, all renderers)
r__dsgraph_build.cpp,r__dsgraph_render.cpp,r__dsgraph_structure.h: scope-pass routing, SVP cull + objective capturerendertarget_phase_nightvision.cpp: scope camera, lens composite, optics/eye-box, capture seam, DLSS eval calldxEnvironmentRender.cpp: per-viewport skybox previous-frame transformBlender_Recorder_StandartBinding.cpp: 3DSS cosmetic gate (parallax shadow / chromatism / NVG bits)R_Backend.h,R_Backend_Runtime.cpp/.h,R_Backend_xform.cpp/.h: per-viewport matricesSkeletonCustom.h,SkeletonX.cpp,FTreeVisual.cpp: per-viewport skinned/foliage transformsLight_DB.cpp/.h,r__occlusion.cpp,rendertarget_phase_blur.cpp: per-viewport lighting/occlusion/blurShader.h,HW.h,dxFontRender.cpp,dxRenderDeviceRender.cpp,Debug/dxPixEventWrapper.hDX11 / R4 (PiP engine)
SvpDlss.h(new): DLSS input contractr4.cpp/.h,r4_R_render.cpp,r4_rendertarget.cpp/.h,r4_rendertarget_phase_combine.cppr2_R_calculate.cpp,r2_R_lights.cpp,r2_R_sun.cpp,r4_R_rain.cpp,r4_loader.cpp,r4_rendertarget_phase_smap_D.cpp,r4_rendertarget_phase_smap_S.cpp,r4_rendertarget_phase_ssao.cppDX10 layer
dx10EventWrapper.cpp/.h,dx10HW.cpp,dx10ResourceManager_Scripting.cpp,dx10SH_RT.cppEngine (xrEngine)
device.cpp/.h: second viewport, per-viewport matrices, history-reset flagCameraManager.cpp,x_ray.cpp,bone.h,Stats.cpp/.h,GameFont.hCore (xrCore)
_matrix.h,Xr_ini.cpp,xr_ini.h,_stl_extensions.hGame (xrGame)
Actor.cpp/.h,ActorInput.cpp,Level.cpp,Weapon.cpp/.h,WeaponAK74.cpp,game_cl_single.hInclude / build
Include/xrRender/FactoryPtr.h,.gitignore,/LTCG:INCREMENTALon the WPO link configs, project files (.vcxproj)