Picture in Picture Port | True PiP [Multithreaded] - #615
Draft
TheLostInPlace wants to merge 4 commits into
Draft
TheLostInPlace wants to merge 4 commits into
TheLostInPlace wants to merge 4 commits into
Conversation
…d stop the near field blur moves into its own module and rides the real circle of confusion at the svp near plane, samples a mip prefiltered source and advances geometrically so thin blur bands are not skipped. r__svp_near_pupil and r__svp_drain_clip sit default off for barrel seam testing and the ocular field stop derives its rim band from the exit pupil geometry
…lass disc the wpn dof constant zero gate now rides r__svp_wpn_dof default 1 so the sss aim blur reaches the gun again. the custom depth stamp clips to the glass disc so the housing keeps real gbuffer depth and blurs with the hands, the magnified image stays far and sharp
…ster log authored and detent base scope mins rescale to the aim fov like the max bound and the scope params floor scales the whole encoding by one factor, so ffp reticle size no longer moves with either fov slider. flat window optics with authored magnifications zoom with the click and the cfg and files report prints to pip.log for a single tester file
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 + authored per-scope optics + SVP DLSS-SR scaffolding (DX11, MT)
Summary
Adds true picture-in-picture (PiP) scope rendering to the MT 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 an authored per-scope optics layer, real objective
geometry, objective diameters from manufacturer spec sheets, and authored magnification ranges drive
the rendered image, so a 3-10x scope renders a true 3-10x and the magnification readout shows the
rendered value, plus optical realism derived from that data (exit-pupil twilight dimming,
near-field defocus, parallax focus, field curvature, veiling glare, a photometric eye model),
mechanical zoom feel (click-lever dual-state optics, analog and stepped zoom, magnification-
proportional sensitivity), per-viewport correctness (motion vectors, TAA, lighting, local
exposure), NVG and thermal support through the optic, SVP performance levers (frustum +
small-object + grass culling, adaptive scope resolution, dead-corner stencil, light cone cull,
supersample), a diagnostics suite (dedicated
pip.logchannel, one-shot config registry dump,stats overlay, crash-context ring), and all engine-side scaffolding for a future DLSS-SR upscale
of the scope render (reconstruction left as a documented stub).
The feature is additive and off by default. With
r__svpscope 0the render is byte-identical tostock MT. The true-PiP render passes live in the R4 (DX11) renderer; every shared-layer touch is
gated on the SVP pass being active, which only R4 ever raises, so R1/R2/R3 never enter a PiP path.
all-in-one-vs2022-wpo-mtRequirements
PiP renders the scene into the in-world scope lens, so it relies on the 3D Shader Scopes (3DSS)
GAMMA addon to supply the lens geometry, the reticle, and the per-scope data this feature reads.
3DSS is bundled in GAMMA, so GAMMA users have it by default. Without 3DSS (or an equivalent
scope-lens setup) there is no lens surface for the PiP image to composite into.
The per-scope data is consumed in tiers with graceful fallback at every level:
magnifications(the key 3DSS authors for PiP consumption, e.g.3-10,1,4,2.8) drives therendered zoom range directly; weapons with integrated scopes resolve their scope section the same
way 3DSS itself does. Scopes without it fall back to the singular
magnificationkey, then to thelegacy
scope_zoom_factorderivation.scope_objective_lens_offset(authored objective geometry) drives the front plane and aperture;s3ds_objective_mm(real spec-sheet objective diameters, shipped in this PR for common optics)drives the true exit pupil. Scopes without either fall back to measured lens geometry.
A small companion patch to the 3DSS scope-glass headers (integrating the shader hook layer shipped
in this PR) is distributed alongside the builds rather than inside this PR, since those files belong
to the 3DSS mod; every hook in it is inert without a PiP exe.
What's new (user-facing)
depth, and lighting inside the optic).
r__svpscope 1renders from the eyepiece;r__svpscope 2renders from the optic's entrance pupil, with the weapon drained through the same camera so the
barrel's visibility through the glass is decided by geometry, not a shader trick
magnificationsrange render it as truemagnification; the readout, wheel steps, click levers, and scoped sensitivity all follow. Nothing
is fudged to match tooltips: the number shown is the number rendered
zoom_step_count = 1or a commamagnifications pair) throw between their two detents like the real lever, with a brief transition
shadow sweep; variable scopes keep smooth, stepped, or analog zoom (
g_zoom_smooth,g_zoom_analog,g_zoom_clicks)and hands, thin-lens parallax focus, field-curvature edge softness, lens coating transmission,
off-axis veiling glare (Stiles-Holladay falloff), a Moon-Spencer photometric eye model,
illuminated-reticle washout, heat mirage under magnification, and rain droplets on the objective
dialed magnification held through the raise, an auto-zero cap so shots converge on the aimed
surface, and camera-effector unification so kicks move the world and the weapon coherently
highlight bleach roll-off), thermal displays get a digital-sensor simulation
subtense; reflex/holo dots can render as a collimated proxy under a magnifier
composited lens, scope-local eye adaptation, bloom and emissive replay so lamps glow through the
glass, and contrast-adaptive sharpening
grass cone culling, adaptive scope resolution sized to the on-screen lens disc, dead-corner
stenciling outside the disc, light cone culling, and optional supersampling
pip.logchannel, a one-shot[SVP-CFG]dump of every PiP cvar onthe first scoped frame (any tester log identifies its build and config), a per-viewport stats
overlay, and an SVP crash-context ring copied into crash dumps
Console variables
Console variables (92 total: 75
r__svp/r__scope, 13g_, 3s3ds_, 1 vector)Defaults are the shipped values; every default is chosen so the out-of-box result is the physical
behavior.
r__svpscope 0makes all of them inert.Core
r__svpscoper__scope_debugAuthored / per-scope optics
r__svp_authored_opticsscope_objective_lens_offsetfor front plane + aperture (0 = measured geometry only)g_svp_authored_magsscope_zoom_factor)r__svp_measured_opticsr__svp_obj_distr__svp_obj_sizer__svp_focal_deriver__svp_ratio_deriver__svp_settle_derives3ds_objective_mms3ds_middle_greys3ds_adapt_speedscope_objective_lens_offsetOptical realism
r__svp_twilightr__svp_near_blurr__svp_focus_mr__svp_parallaxr__svp_chromar__svp_field_curver__svp_coatingr__svp_veiling_glarer__svp_glare_modelr__svp_photo_modelr__svp_reticle_washoutr__svp_acog_fiberr__svp_mirager__svp_rain_opticr__svp_roll_stabilizer__svp_autoflipr__svp_autoflip_reticler__svp_clean_opticsg_svp_crescentZoom and feel
g_svp_zoom_baseg_zoom_clicksg_zoom_smoothg_zoom_analogg_svp_sensg_svp_sens_curveg_svp_zoom_syncg_svp_zerog_svp_unify_cam_fxg_svp_world_cam_fxg_svp_hud_true_fovr__svp_recoil_holdr__svp_lens_rejectr__svp_drain_anchorr__svp_hud_fov_matchr__svp_hud_fullImage pipeline
r__svp_taa_maskr__svp_jitterfixr__svp_distort_guardr__svp_sharpenr__svp_sharpen_falloffr__svp_sharpen_innerr__svp_local_exposurer__svp_exposure_biasr__svp_bloomr__svp_emissiver__svp_skip_motionblurr__svp_skip_hud_distortr__svp_skip_dofr__svp_skip_lutr__svp_skip_ssrr__svp_skip_volumetricr__svp_skip_grassNVG / thermal
r__svp_thermal_simr__svp_nvg_bleachr__svp_nvg_sensitivityPerformance
r__svp_cullr__svp_cull_ssar__svp_cull_grassr__svp_lodr__svp_adaptive_resr__svp_adaptive_growr__svp_supersampler__svp_light_cullr__svp_corner_maskr__svp_npc_detailr__svp_light_capturer__svp_sss_sunDiagnostics
r__svp_diagr__svp_cop_diagr__svp_statsr__svp_reportr__svp_uv_debugr__svp_rain_debugr__3db_debugDLSS scaffolding
r__svp_dlssrender_scaleinert)r__svp_render_scalevid_restartMisc
r__svp_flat_windowr__svp_reflex_captureHow it works
Second viewport. When PiP is active the frame runs an extra scene pass for the optic camera into
a dedicated second-viewport target. At
r__svpscope 0the legacy throttled SVP behaviour isunchanged; when on, per-pass selection routes work between the scope pass and the main pass.
Entrance-pupil camera (
r__svpscope 2). One camera renders both world and weapon: the worldrenders from the entrance pupil slid up the optical axis to the scope's front plane (authored
geometry when present, measured otherwise), and the weapon drains through the same camera, so
geometry behind the pupil falls behind the near plane and the barrel's visibility through the glass
is decided by real projection, not a shader guess.
Lens composite. The scope target is sampled by the lens shader and
composited on-screen with the reticle. The render FOV is solved through the on-screen eyepiece fit
ratio so that the displayed magnification, the rendered magnification, and the authored
magnification are the same number - a factor-100 scope renders exactly naked-eye 1x at any user FOV,
and an authored
3-10renders a true 3x to 10x.Authored data flow. A companion script pushes per-scope objective geometry, spec-sheet objective
diameters, and optional tonemap overrides to the engine on aim change; the engine reads authored
magnification ranges directly from the scope section at zoom setup, resolving integrated-scope
weapon variants through their parent section exactly the way 3DSS itself does. Every consumer falls
back cleanly when data is absent.
Per-viewport correctness. Previous-frame matrices, foliage transforms, and the sky reprojection
are tracked per viewport; the scope pass writes its own motion vectors and the composited lens is
protected from the main TAA resolve by a mask stamp, so the image stays temporally stable while
panning. Scope-local exposure adapts to what the optic actually sees.
Performance. The scope geometry is frustum-culled to the cone, a magnification-aware
small-object cull drops clutter the magnified cone cannot resolve (the SVP g-buffer is draw-call
bound, so this is the main lever), grass is cone-culled, lights are cone-culled, the corners outside
the disc are stenciled dead, and adaptive resolution sizes the render to the on-screen lens disc.
Diagnostics. PiP logs to its own
pip.log. The first scoped frame prints a one-shot[SVP-CFG]registry dump of every PiP cvar (registry-driven, so it cannot drift from the code), and every
behavioral subsystem has a proof line, so any tester log identifies its build, config, and which
paths actually ran. An SVP state ring is copied into crash dumps.
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:SvpDlss.h) carrying color, depth, and motion-vector SRVs, the outputtarget, matrices, jitter, and camera params, with zero
sl::/ NGX dependenciesInvariants held: at
r__svp_dlss 0the output and GPU work are byte-identical to the non-DLSSpath for any
r__svp_render_scale; the single game-to-render flag is astd::atomic.Compatibility and safety
svp_translation units compile there, but the PiP passes aredriven only by the R4 renderer, so every shared gate stays cold and the paths collapse to stock
r__svpscope 0is stock behaviour, verified byte-identical at the gatesvp_*translation units (27 new files) with the stocktouch points kept small and individually gated, so the diff is reviewable by subsystem
Testing
Tested on Anomaly 1.5.3 with GAMMA 0.9.5 (3D Shader Scopes, SSS, Atmospherics) through an extended
release-candidate cycle with external testers:
r__svpscope 0magnification ranges verified against the log proof lines across the scope roster (LPVOs,
dual-state levers, fixed magnifiers, integrated-scope weapon variants)
bottom detent at any user FOV, magnification-proportional sensitivity
vectors confirmed
Known limitations
r__svp_dlss 1runs a passthrough stubsharing one rim; near-field defocus is the shipped mitigation and a fuller continuity program is
designed and in progress
r__svp_measured_optics) ships default-off as a diagnosticpath; authored data is the production path
here) is distributed with the builds rather than in this PR, since those files belong to the 3DSS
mod; all hooks are inert without a PiP exe
Attribution
The true picture-in-picture scope code was written by m22spencer. This work is a port and
continuation of it from the gc64 fork that adopted it
(CnRJay/xray-monolith-gc64): the DX11 second-viewport
rendering, the lens composite, and the per-viewport history follow that implementation. The
entrance-pupil camera, the authored per-scope optics and magnification layer, the optical realism
set, the zoom mechanics, the per-viewport TAA/MV work, the performance levers, the diagnostics
suite, and the DLSS contract were added on top.
magnifications, objective lens geometry)xray-monolithengine this targetsFiles changed
151 files, grouped by area
Gamedata — scripts
gamedata/scripts/zzz_extra_scope_features.script(new): pushes per-scope optics data to the engine on aimgamedata/scripts/options_modded_exes_pip.script(new): the PiP options page in the Modded Exes menugamedata/scripts/_imgui_groups.script,options_modded_exes_visual.script: options wiringGamedata — configs
gamedata/configs/pip_objective_mm.ltx(new): real objective diameters from spec sheetsgamedata/configs/mod_system_pip_tonemap.ltx(new): optional per-scope svp tonemap overridesgamedata/configs/text/eng/ui_mm_modded_exes.xml: option stringsGamedata — shaders (r3, all new)
svp_hooks_{common,image,lens,reticle,shadow}.h: the shader hook layer the 3DSS glass patch calls intosvp_nearblur.{ps,s}: near-field defocus;svp_distort_stamp.{ps,s},svp_taa_stamp.{ps,s}: distort/TAA mask stamps over the composited lensscope_color_write.s,scope_vertex.vs,scope_depth_write.{ps,s},scope_custom_depth.h,scope_defines.h,scope_debug.{ps,s}: the second viewport's own render, depth, and debug passesgamedata/textures/fx/svp_rain.dds(new): rain-on-objective textureConsole / cvars
src/Layers/xrRender/svp_console.cpp/.h(new): ther__svp_*cvar set + the inert-path ledger sweepsrc/xrEngine/svp_gameplay_cvars.cpp/.h(new): theg_svp_*/g_zoom_*gameplay cvarsxrRender_console.cpp/.h,xr_ioc_cmd.cpp,XR_IOConsole.cpp,console_registrator_script.cpp,level_script.cppShared render layer (xrRender)
svp_constants.cpp/.h(shader constant binders + boot validation),svp_dsgraph_cull.cpp(scope frustum cull),svp_hud_latch.cpp(hud pose latch + weapon drain),svp_lens_detect.cpp/.h+svp_lens_detect_math.cpp/.h(per-visual lens auto-detection),Debug/renderdoc_app.h(in-app capture API)rendertarget_phase_nightvision.cpp(scope capture seam + NVG),rendertarget_phase_smaa.cpp(TAA resolve seams),dxEnvironmentRender.cpp(per-viewport sky),R_sun.cpp+lights_render.cpp+Light_DB.cpp(per-viewport lighting),R_Backend*+Blender_Recorder_StandartBinding.cpp(per-viewport matrices + binders),DetailManager_VS.cpp,FTreeVisual.cpp,SkeletonX.cpp/.h,SkeletonCustom.h,Shader.h,HW.h,dxRenderDeviceRender.cpp, particle files (scoped distort handling),Include/xrRenderinterface headersDX11 / R4 (the PiP engine)
svp_camera.cpp/.h(the scope camera build),svp_optics.cpp(scope render passes + optics derivation),svp_target.cpp/.h(SVP render-target policy),svp_stats.cpp/.h(stats overlay + counters),SvpDlss.h(DLSS input contract)r4.cpp/.h,r4_R_render.cpp,r4_rendertarget.cpp/.h,r4_rendertarget_phase_combine.cpp,r4_rendertarget_phase_luminance.cppDX10 layer
dx10DetailManager_VS.cpp,dx10EventWrapper.cpp/.h,dx10HW.cpp,dx10ResourceManager_Scripting.cpp,dx10SH_RT.cppEngine (xrEngine)
svp_state.h(the cross-thread second-viewport state block),svp_crash_context.cpp/.h(SVP state ring in crash dumps)device.cpp/.h,CameraManager.cpp/.h,x_ray.cpp,bone.h,imgui_base.cppCore (xrCore)
svp_log.cpp/.h(thepip.logchannel)Xr_ini.cpp,xr_ini.h,_matrix.h,log.hGame (xrGame)
svp_mags.cpp/.h(authored magnification parsing + zoom range resolve),svp_weapon.cpp(weapon-side svp state publish)Weapon.cpp/.h,WeaponAK74.cpp,WeaponBinoculars.cpp/.h,WeaponBinocularsVision.cpp,Actor.cpp/.h,ActorCameras.cpp,ActorEffector.cpp,ActorInput.cpp,Actor_Weapon.cpp,HudItem.cpp,ShootingObject.cpp,ParticlesObject.cpp/.h,Level.cpp,UIGameCustom.cpp/.hBuild
.gitignore, the sevenvcxproj/.filtersproject files registering the newsvp_translation units (R1/R2/R3 project files are insertion-only)