unpredicted world blend wip

This commit is contained in:
jacob 2026-02-26 13:04:42 -06:00
parent 55311f7b98
commit 1397c4a7a4
7 changed files with 212 additions and 60 deletions

View File

@ -60,6 +60,21 @@
#define IsGpu 0 #define IsGpu 0
#endif #endif
//- Language
#if defined(__HLSL_VERSION)
#define IsLanguageHLSL 1
#define IsLanguageCpp 0
#define IsLanguageC 0
#elif defined(__cplusplus)
#define IsLanguageHLSL 0
#define IsLanguageCpp 1
#define IsLanguageC 0
#else
#define IsLanguageHLSL 0
#define IsLanguageCpp 0
#define IsLanguageC 1
#endif
//- Platform //- Platform
#if IsGpu #if IsGpu
#define IsPlatformWindows 0 #define IsPlatformWindows 0
@ -176,7 +191,7 @@
//~ Common utility macros //~ Common utility macros
//- Zero initialization //- Zero initialization
#if IsCpu #if IsLanguageC
#define Zi {0} #define Zi {0}
#else #else
#define Zi {} #define Zi {}
@ -245,10 +260,10 @@
#define Stringize(x) Stringize1(x) #define Stringize(x) Stringize1(x)
//- Sizes //- Sizes
#define Kibi(n) ((n) * (1ULL << 10)) #define Kibi(n) ((n) * (1ull << 10))
#define Mebi(n) ((n) * (1ULL << 20)) #define Mebi(n) ((n) * (1ull << 20))
#define Gibi(n) ((n) * (1ULL << 30)) #define Gibi(n) ((n) * (1ull << 30))
#define Tebi(n) ((n) * (1ULL << 40)) #define Tebi(n) ((n) * (1ull << 40))
//- Time //- Time
#define NsFromSeconds(s) ((i64)((s) * 1000000000.0)) #define NsFromSeconds(s) ((i64)((s) * 1000000000.0))
@ -499,17 +514,17 @@
#define U8Max (0xFF) #define U8Max (0xFF)
#define U16Max (0xFFFF) #define U16Max (0xFFFF)
#define U32Max (0xFFFFFFFF) #define U32Max (0xFFFFFFFF)
#define U64Max (0xFFFFFFFFFFFFFFFFULL) #define U64Max (0xFFFFFFFFFFFFFFFFull)
#define I8Max (0x7F) #define I8Max (0x7F)
#define I16Max (0x7FFF) #define I16Max (0x7FFF)
#define I32Max (0x7FFFFFFF) #define I32Max (0x7FFFFFFF)
#define I64Max (0x7FFFFFFFFFFFFFFFLL) #define I64Max (0x7FFFFFFFFFFFFFFFll)
#define I8Min ((i8)-0x80) #define I8Min ((i8)-0x80)
#define I16Min ((i16)0x8000) #define I16Min ((i16)0x8000)
#define I32Min ((i32)0x80000000) #define I32Min ((i32)0x80000000)
#define I64Min ((i64)0x8000000000000000LL) #define I64Min ((i64)0x8000000000000000ll)
//- Float infinity / nan //- Float infinity / nan
#if IsCpu #if IsCpu

View File

@ -156,7 +156,7 @@ void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size) BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
{ {
if (size > 0x00FFFFFFFFFFFFFFULL) if (size > 0x00FFFFFFFFFFFFFFull)
{ {
// TODO: Error // TODO: Error
Assert(0); Assert(0);

View File

@ -12,6 +12,8 @@ Readonly P_Constraint P_NilConstraint = {
}; };
Readonly P_Frame P_NilFrame = { Readonly P_Frame P_NilFrame = {
.next = &P_NilFrame,
.prev = &P_NilFrame,
.first_ent = &P_NilEnt, .first_ent = &P_NilEnt,
.last_ent = &P_NilEnt, .last_ent = &P_NilEnt,
}; };
@ -1948,6 +1950,11 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
dst->created_at_ns = frame->time_ns; dst->created_at_ns = frame->time_ns;
dst->created_at_tick = frame->tick; dst->created_at_tick = frame->tick;
++frame->ents_count; ++frame->ents_count;
if (!P_tl.is_predicting)
{
dst->sim = 1;
}
} }
} }
} }
@ -2183,6 +2190,27 @@ void P_StepFrame(P_Frame *frame)
P_Ent *local_player = P_EntFromKey(frame, P_tl.local_player); P_Ent *local_player = P_EntFromKey(frame, P_tl.local_player);
P_Ent *local_guy = P_EntFromKey(frame, local_player->guy); P_Ent *local_guy = P_EntFromKey(frame, local_player->guy);
//////////////////////////////
//- Mark simulated ents
if (is_predicting)
{
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
P_EntKey key = ent->key;
b32 sim = 0;
if (
P_MatchEntKey(key, local_player->key) ||
P_MatchEntKey(key, local_guy->key) ||
P_MatchEntKey(key, local_guy->weapon)
)
{
sim = 1;
}
ent->sim = sim;
}
}
////////////////////////////// //////////////////////////////
//- Spawn guys //- Spawn guys
@ -2297,8 +2325,8 @@ void P_StepFrame(P_Frame *frame)
weapon->is_weapon = 1; weapon->is_weapon = 1;
weapon->key = P_RandEntKey(); weapon->key = P_RandEntKey();
weapon->source = guy->key; weapon->source = guy->key;
// weapon->1is_uzi = 1; weapon->is_uzi = 1;
weapon->is_launcher = 1; // weapon->is_launcher = 1;
guy->weapon = weapon->key; guy->weapon = weapon->key;
} }
} }
@ -2306,7 +2334,6 @@ void P_StepFrame(P_Frame *frame)
P_SpawnEntsFromList(frame, queued_ents); P_SpawnEntsFromList(frame, queued_ents);
} }
////////////////////////////// //////////////////////////////
//- Update guy controls from player controls //- Update guy controls from player controls
@ -2377,7 +2404,7 @@ void P_StepFrame(P_Frame *frame)
for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy)) for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy))
{ {
if (guy->is_guy && (!is_predicting || guy == local_guy)) if (guy->is_guy && guy->sim)
{ {
P_Control control = guy->control; P_Control control = guy->control;
@ -2385,7 +2412,8 @@ void P_StepFrame(P_Frame *frame)
{ {
if (Vec2Len(guy->v) > 0.001) if (Vec2Len(guy->v) > 0.001)
{ {
f32 damp_force = TweakFloat("Guy damp force", 50, 0, 100); // f32 damp_force = TweakFloat("Guy damp force", 50, 0, 100);
f32 damp_force = TweakFloat("Guy damp force", 0, 0, 100);
Vec2 damp = MulVec2(NegVec2(guy->v), damp_force * sim_dt); Vec2 damp = MulVec2(NegVec2(guy->v), damp_force * sim_dt);
guy->v = AddVec2(guy->v, damp); guy->v = AddVec2(guy->v, damp);
} }
@ -2575,12 +2603,12 @@ void P_StepFrame(P_Frame *frame)
f32 inv_i1 = 0; f32 inv_i1 = 0;
// Treat statics / non-predicted ents as infinite-mass // Treat statics / non-predicted ents as infinite-mass
if (!ent0->is_guy || (is_predicting && !P_MatchEntKey(ent0->key, local_guy->key))) if (!ent0->is_guy || !ent0->sim)
{ {
inv_m0 = 0; inv_m0 = 0;
inv_i0 = 0; inv_i0 = 0;
} }
if (!ent1->is_guy || (is_predicting && !P_MatchEntKey(ent1->key, local_guy->key))) if (!ent1->is_guy || !ent1->sim)
{ {
inv_m1 = 0; inv_m1 = 0;
inv_i1 = 0; inv_i1 = 0;
@ -2957,7 +2985,7 @@ void P_StepFrame(P_Frame *frame)
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{ {
if (!ent->is_bullet && (!is_predicting || ent == local_guy)) if (!ent->is_bullet && ent->sim)
{ {
Xform xf = ent->xf; Xform xf = ent->xf;
xf.t = AddVec2(xf.t, MulVec2(ent->v, solver_dt)); xf.t = AddVec2(xf.t, MulVec2(ent->v, solver_dt));
@ -2997,8 +3025,8 @@ void P_StepFrame(P_Frame *frame)
for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer)) for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer))
{ {
P_Ent *weapon = P_EntFromKey(frame, firer->weapon); P_Ent *weapon = P_EntFromKey(frame, firer->weapon);
// if (weapon->is_weapon && (firer->control.fire_held || firer->control.fire_presses)) if (weapon->is_weapon && (firer->control.fire_held || firer->control.fire_presses))
if (weapon->is_weapon && firer->control.fire_presses) // if (weapon->is_weapon && firer->control.fire_presses)
{ {
f32 fire_rate = 50; f32 fire_rate = 50;
f32 bullets_per_fire = 1; f32 bullets_per_fire = 1;

View File

@ -119,6 +119,7 @@ Struct(P_Ent)
//- Build data //- Build data
f32 exists; f32 exists;
b32 sim;
b32 is_guy; b32 is_guy;
b32 is_bot; b32 is_bot;
@ -338,6 +339,7 @@ Struct(P_Frame)
////////////////////////////// //////////////////////////////
//- Frame state //- Frame state
i64 src_tick;
i64 tick; i64 tick;
i64 time_ns; i64 time_ns;

View File

@ -417,7 +417,7 @@ void S_TickForever(WaveLaneCtx *lane)
//- Apply bot controls //- Apply bot controls
{ {
b32 bot_movement_enabled = TweakBool("Bot movement enabled", 0); b32 bot_movement_enabled = TweakBool("Bot movement enabled", 1);
for (P_Ent *bot = P_FirstEnt(world_frame); !P_IsEntNil(bot); bot = P_NextEnt(bot)) for (P_Ent *bot = P_FirstEnt(world_frame); !P_IsEntNil(bot); bot = P_NextEnt(bot))
{ {
if (bot->is_bot) if (bot->is_bot)

View File

@ -377,6 +377,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Which tick snapshots we have received and finished assembling from the server // Which tick snapshots we have received and finished assembling from the server
i64 ack = 0; i64 ack = 0;
i64 ack_mirror = 0; i64 ack_mirror = 0;
i64 ack_received_at_ns = 0;
f64 most_recent_rtt = 0; f64 most_recent_rtt = 0;
// i64 smoothed_rtt_ns = 0; // i64 smoothed_rtt_ns = 0;
@ -1292,6 +1293,7 @@ void V_TickForever(WaveLaneCtx *lane)
if (dst_frame->received_fragments_count >= dst_frame->fragments_count) if (dst_frame->received_fragments_count >= dst_frame->fragments_count)
{ {
ack = dst_tick; ack = dst_tick;
ack_received_at_ns = frame->time_ns;
} }
} }
} }
@ -1612,7 +1614,7 @@ void V_TickForever(WaveLaneCtx *lane)
bottom_tick = MinI64(bottom_tick, first_predict_tick); bottom_tick = MinI64(bottom_tick, first_predict_tick);
bottom_tick = MinI64(bottom_tick, last_predict_tick); bottom_tick = MinI64(bottom_tick, last_predict_tick);
bottom_tick = MinI64(bottom_tick, ack); bottom_tick = MinI64(bottom_tick, ack);
P_ClearFrames(sim_world, I64Min, bottom_tick - 1); // P_ClearFrames(sim_world, I64Min, bottom_tick - 1);
} }
// P_ClearFrames(sim_world, I64Min, ack - SIM_TICKS_PER_SECOND); // P_ClearFrames(sim_world, I64Min, ack - SIM_TICKS_PER_SECOND);
// P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1); // P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
@ -1633,12 +1635,14 @@ void V_TickForever(WaveLaneCtx *lane)
} }
predict_world->seed = sim_world->seed; predict_world->seed = sim_world->seed;
P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 1, prev_frame->blend_from_tick - 1)); // P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 1, prev_frame->blend_from_tick - 1));
P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 2, prev_frame->blend_from_tick - 1));
predict_frame = P_PushFrame(predict_world, P_FrameFromTick(sim_world, first_predict_tick), first_predict_tick); predict_frame = P_PushFrame(predict_world, P_FrameFromTick(sim_world, first_predict_tick), first_predict_tick);
for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick) for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick)
{ {
predict_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_tick); predict_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_tick);
predict_frame->src_tick = first_predict_tick;
P_Ent *predict_player = P_EntFromKey(predict_frame, V.player_key); P_Ent *predict_player = P_EntFromKey(predict_frame, V.player_key);
if (!P_IsEntNil(predict_player)) if (!P_IsEntNil(predict_player))
{ {
@ -1836,6 +1840,11 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Update local world //- Update local world
P_Frame *prev_local_frame = prev_frame->local_world->last_frame; P_Frame *prev_local_frame = prev_frame->local_world->last_frame;
P_Frame *local_frame = &P_NilFrame; P_Frame *local_frame = &P_NilFrame;
{ {
@ -1849,6 +1858,7 @@ void V_TickForever(WaveLaneCtx *lane)
P_ClearFrames(frame->local_world, I64Min, I64Max); P_ClearFrames(frame->local_world, I64Min, I64Max);
i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor;
// i64 target_blend_dt_ns = frame->dt_ns;
i64 blend_dt_ns = frame->dt_ns; i64 blend_dt_ns = frame->dt_ns;
V.target_blend_time_ns += target_blend_dt_ns; V.target_blend_time_ns += target_blend_dt_ns;
@ -1874,35 +1884,61 @@ void V_TickForever(WaveLaneCtx *lane)
if (TweakBool("Interpolation enabled", 1)) if (TweakBool("Interpolation enabled", 1))
{ {
P_Frame *left_frame = &P_NilFrame; P_Frame *left_predict_frame = &P_NilFrame;
P_Frame *right_frame = &P_NilFrame; P_Frame *right_predict_frame = &P_NilFrame;
for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
{ {
if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
{ {
right_frame = tmp; right_predict_frame = tmp;
left_frame = tmp->prev; left_predict_frame = tmp->prev;
break; break;
} }
} }
if (P_IsFrameNil(left_frame) || P_IsFrameNil(right_frame)) if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame))
{ {
right_frame = predict_world->last_frame; right_predict_frame = predict_world->last_frame;
left_frame = right_frame->prev; left_predict_frame = right_predict_frame->prev;
} }
frame->blend_from_tick = left_frame->tick; frame->blend_from_tick = left_predict_frame->tick;
frame->blend_to_tick = right_frame->tick; frame->blend_to_tick = right_predict_frame->tick;
local_frame = P_PushFrame(frame->local_world, left_frame, left_frame->tick); local_frame = P_PushFrame(frame->local_world, left_predict_frame, left_predict_frame->tick);
{ {
f64 blend_t = (f64)(V.blend_time_ns - left_frame->time_ns) / (f64)(right_frame->time_ns - left_frame->time_ns); // P_Frame *left_sim_frame = predict_world->first_frame;
// P_Frame *right_sim_frame = left_sim_frame->next;
// P_Frame *right_sim_frame = P_FrameFromTick(predict_world, first_predict_tick);
// P_Frame *left_sim_frame = right_sim_frame->prev;
// P_Frame *right_sim_frame = P_FrameFromTick(sim_world, ack - 1);
// P_Frame *left_sim_frame = right_sim_frame->prev;
P_Frame *right_sim_frame = P_FrameFromTick(sim_world, right_predict_frame->src_tick);
P_Frame *left_sim_frame = right_sim_frame->prev;
f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns);
LogDebugF("blend_t: %F", FmtFloat(blend_t));
for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{ {
P_Ent *left = ent; P_Ent *left = ent;
P_Ent *right = P_EntFromKey(right_frame, ent->key); P_Ent *right = ent;
// if (ent->sim)
if (0)
{
left = ent;
right = P_EntFromKey(right_predict_frame, ent->key);
}
else
{
left = P_EntFromKey(left_sim_frame, ent->key);
right = P_EntFromKey(right_sim_frame, ent->key);
}
ent->exists = LerpF32(left->exists, right->exists, blend_t); ent->exists = LerpF32(left->exists, right->exists, blend_t);
if (!P_IsEntNil(right)) if (!P_IsEntNil(right))
@ -1935,7 +1971,12 @@ void V_TickForever(WaveLaneCtx *lane)
// // TODO: Remove this
// P_Frame *prev_local_frame = prev_frame->local_world->last_frame;
// P_Frame *local_frame = &P_NilFrame; // P_Frame *local_frame = &P_NilFrame;
// { // {
// if (frame->local_world->tiles_hash != predict_world->tiles_hash) // if (frame->local_world->tiles_hash != predict_world->tiles_hash)
@ -1945,11 +1986,98 @@ void V_TickForever(WaveLaneCtx *lane)
// frame->tiles_dirty = 1; // frame->tiles_dirty = 1;
// } // }
// frame->local_world->seed = predict_world->seed; // frame->local_world->seed = predict_world->seed;
// P_ClearFrames(frame->local_world, I64Min, I64Max);
// P_ClearFrames(frame->local_world, I64Min, frame->local_world->last_frame->tick - 1); // i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor;
// i64 blend_dt_ns = frame->dt_ns;
// V.target_blend_time_ns += target_blend_dt_ns;
// V.blend_time_ns += blend_dt_ns;
// // How many ticks back in time should the user thread blend between?
// // <Delay> = <USER_INTERP_RATIO> * <Tick interval>
// // E.g: At 1.5, the world will render 75ms back in time if the sim runs at 50tps
// f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, 5);
// if (predict_to != prev_frame_predict_to)
// {
// i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio;
// V.target_blend_time_ns = predict_world->last_frame->time_ns - delay_ns;
// }
// f64 blend_to_target_lerp_rate = 0.05;
// V.blend_time_ns = LerpI64(V.blend_time_ns, V.target_blend_time_ns, blend_to_target_lerp_rate);
// if (AbsI64(V.blend_time_ns - V.target_blend_time_ns) > (SIM_TICK_INTERVAL_NS * interp_ratio * 2))
// {
// LogDebugF("Blend reset");
// V.blend_time_ns = V.target_blend_time_ns;
// }
// if (TweakBool("Interpolation enabled", 1))
// {
// P_Frame *left_predict_frame = &P_NilFrame;
// P_Frame *right_predict_frame = &P_NilFrame;
// for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// {
// if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
// {
// right_predict_frame = tmp;
// left_predict_frame = tmp->prev;
// break;
// }
// }
// if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame))
// {
// right_predict_frame = predict_world->last_frame;
// left_predict_frame = right_predict_frame->prev;
// }
// frame->blend_from_tick = left_predict_frame->tick;
// frame->blend_to_tick = right_predict_frame->tick;
// local_frame = P_PushFrame(frame->local_world, left_predict_frame, left_predict_frame->tick);
// {
// f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns);
// // P_Frame *left_sim_frame = predict_world->first_frame;
// // P_Frame *right_sim_frame = left_sim_frame->next;
// P_Frame *right_sim_frame = P_FrameFromTick(sim_world, ack);
// P_Frame *left_sim_frame = right_sim_frame->prev;
// for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
// {
// P_Ent *left = ent;
// P_Ent *right = ent;
// // if (ent->sim)
// if (0)
// {
// left = ent;
// right = P_EntFromKey(right_predict_frame, ent->key);
// }
// else
// {
// left = P_EntFromKey(left_sim_frame, ent->key);
// right = P_EntFromKey(right_sim_frame, ent->key);
// }
// ent->exists = LerpF32(left->exists, right->exists, blend_t);
// if (!P_IsEntNil(right))
// {
// ent->health = LerpF32(left->health, right->health, blend_t);
// ent->xf.t = LerpVec2(left->xf.t, right->xf.t, blend_t);
// ent->xf.r = SlerpVec2(left->xf.r, right->xf.r, blend_t);
// ent->walk_time_accum_ns = LerpI64(left->walk_time_accum_ns, right->walk_time_accum_ns, blend_t);
// ent->v = LerpVec2(left->v, right->v, blend_t);
// ent->w = LerpF32(left->w, right->w, blend_t);
// }
// }
// }
// }
// else
// {
// local_frame = P_PushFrame(frame->local_world, predict_world->last_frame, predict_world->last_frame->tick); // local_frame = P_PushFrame(frame->local_world, predict_world->last_frame, predict_world->last_frame->tick);
// }
// // LogDebugF("First frame: %F, Last frame: %F", FmtSint(frame->local_world->first_frame->tick), FmtSint(frame->local_world->last_frame->tick));
// P_DebugDrawFrame(local_frame); // P_DebugDrawFrame(local_frame);
@ -1960,27 +2088,6 @@ void V_TickForever(WaveLaneCtx *lane)
// {
// i64 delay_ns = NsFromSeconds(100);
// P_Frame *right_frame = &P_NilFrame;
// P_Frame *left_frame = &P_NilFrame;
// for (P_Frame *tmp =
// P_Frame *right_frame = predict_world->last_frame;
// P_Frame *left_frame = predict_world->left_frame;
// }
////////////////////////////// //////////////////////////////
//- Query local player //- Query local player

View File

@ -744,7 +744,7 @@ ImplComputeShader2D(V_CompositeCS)
Vec4 backdrop_color = 0; Vec4 backdrop_color = 0;
{ {
if (!frame.is_editing) if (!frame.is_editing || !is_in_world)
{ {
backdrop_color = backdrop.SampleLevel(bilinear_sampler, screen_uv, 0); backdrop_color = backdrop.SampleLevel(bilinear_sampler, screen_uv, 0);
} }