Untitled

lang: “en”

UE “Reflection” Concept

  • Reflection: UE provides runtime type information and dynamic access capabilities through systems like UClass and UProperty.
    UE’s reflection system is a code-generation mechanism implemented via the UHT tool and specific macros. You mark classes with UCLASS, variables with UPROPERTY, and functions with UFUNCTION — these macros are recognized by UHT.
    Before compilation, UHT scans these markers and generates .generated.h and .cpp files containing the reflection registration code for each class, such as the StaticClass() function and the construction logic for UClass objects.
    The generated code registers class information into the engine’s global GObjectClasses array, enabling the engine at runtime to dynamically retrieve class structure, invoke functions, or access properties — which in turn powers blueprint interaction, garbage collection, and other core features.

This exists because UE needs to dynamically process code information at runtime. Blueprint visual scripting, for example, requires the engine to know via reflection which functions and variables a C++ class exposes so that blueprints can call them.

Say you write a character class in C++ with a Jump() function marked with UFUNCTION. Without reflection, the blueprint editor has no idea Jump() exists — the function name, parameters, and all that metadata get optimized away in the compiled machine code.
With reflection, UHT generates reflection metadata for Jump() at compile time, including its name, parameter types, return value, and which class it belongs to. At runtime, the engine uses this metadata to surface Jump() in the blueprint editor as a callable node you can drag in.
If you later add a height parameter to Jump() in C++, the reflection system automatically updates the metadata, and the corresponding blueprint node syncs up to show the new parameter — no manual binding code between blueprint and C++ required.

Undo/Redo — Command Pattern (Lightweight)

1
2
3
4
Wrap each operation as ICommand { Do(); Undo(); }
Maintain undoStack and redoStack
Execute operation → push to undoStack, clear redoStack
Undo → pop from undoStack, call Undo(), push to redoStack

2. Snapshot Pattern (for complex scenarios):

1
2
3
4
Serialize a snapshot of the entire object state before each operation
On Undo, restore the snapshot directly
Pros: simple to implement, less prone to bugs
Cons: high memory overhead

Hybrid approach for real projects:

  • Simple property edits → Command pattern (record oldValue/newValue)
  • Complex operations (node graph changes, scene edits) → Snapshot or Diff pattern
  • Merge mechanism: collapse consecutive operations of the same type (e.g., dragging a slider merges into a single history entry)

UE Smart Pointer Comparison

Pointer Type Managed Object Ownership Core Role Use Case
TObjectPtr UObject-derived Shared Safe UObject access, participates in garbage collection automatically Replaces traditional UPROPERTY pointers; everyday UObject references
TWeakObjectPtr UObject-derived None Weak reference to UObject, does not prevent GC Avoids circular references; temporary access to UObjects that may be destroyed
TSoftObjectPtr UObject-derived None Soft reference to UObject, supports async asset loading References assets that may not be loaded, e.g., meshes or textures outside the current level
TSharedPtr Non-UObject types Shared Manages lifetime via reference counting Multiple owners sharing a non-UObject resource
TUniquePtr Non-UObject types Exclusive Sole ownership, non-copyable Managing non-UObject resources that don’t need sharing, e.g., custom data structures
TWeakPtr Non-UObject types None Weak reference to a TSharedPtr, does not increment ref count Avoids circular references when used alongside TSharedPtr

Key Distinctions

  1. Object boundary: The first three are strictly for UObject-derived classes and rely on UE’s garbage collection system; the last three are for non-UObject types and use manual memory management.

  2. UObject pointer breakdown:

    • TObjectPtr is a strong reference that keeps the UObject alive — the go-to choice for everyday development.
    • TWeakObjectPtr is a weak reference; when a UObject is marked for collection, the pointer is automatically nulled. Common in scenarios like UI widgets holding references to character objects.
    • TSoftObjectPtr stores a resource path rather than a direct memory address. The asset can be asynchronously loaded when it isn’t in memory, making it ideal for open-world games referencing distant assets.
  3. Non-UObject pointer breakdown:

    • TSharedPtr shares an object via reference counting, automatically freeing memory when the count reaches zero. Be mindful of circular references — they must be avoided manually.
    • TUniquePtr is an exclusive pointer: no copying allowed, ownership transfers only through move semantics. Lowest performance overhead.
    • TWeakPtr must be bound to a TSharedPtr. Once TSharedPtr releases the object, TWeakPtr automatically becomes invalid, resolving circular reference issues.

What is ECS Architecture? How Does It Differ from Traditional OOP?

OOP ECS
Data layout Objects scattered on the heap Components laid out in contiguous memory
Cache friendliness Poor (pointer chasing) Good (data locality)
Logic organization Methods bound to classes Systems iterate over Components independently
Composability Requires multiple inheritance / composition patterns Natural composition (just attach Components)

ECS essentially saves CPU time on data lookups.

Core concepts:

  • Entity: an ID only, stores no data
  • Component: pure data (Position, Velocity, Health…)
  • System: pure logic (MovementSystem iterates all Position+Velocity components)

Core difference: OOP centers on objects — data and logic are encapsulated in classes, which tends to grow complex inheritance trees. ECS separates data from logic: entities are containers for components, systems process batches of the same component type, contiguous data storage improves cache efficiency, and the architecture naturally supports dynamic composition and parallel computation.
UE5 Mass system example: as an ECS implementation, Mass stores entity data in “fragments” and unifies logic in “processors.” The Matrix Awakens demo’s crowd simulation of thousands of characters packs position, velocity, and other data into contiguous storage, letting the movement processor batch-update all character coordinates — performance that far exceeds the traditional Actor approach.

Stack vs. Heap

  • Heap: Dynamically allocated memory, variable size, lifetime controlled by the programmer, slower access. Suitable for large objects or data whose size is determined at runtime. (No fixed access order.)
  • Stack: Automatically allocated memory, fixed size, lifetime controlled by the function call, fast access. Suitable for local variables and function parameters. (Fixed access order: last in, first out.)

What Is Function Calling and How Have You Used It in Projects?

How it works: The LLM doesn’t execute functions directly — it outputs a structured function-call intent (function name + arguments), which the host program parses and executes.

What Is RAG and How Did You Implement It?

RAG (Retrieval-Augmented Generation) = retrieve relevant documents first, then have the LLM answer based on those retrieved results.

What Is ControlNet and What Problem Does It Solve?

Reference answer:

ControlNet adds spatial control capabilities to a pretrained Diffusion Model.

The problem it solves: Raw Text-to-Image generation cannot precisely control the composition, pose, edges, or other spatial structure of generated images.

How it works:

  • A parallel “Zero Convolution” branch is added to each block of Stable Diffusion’s U-Net
  • Additional conditioning images are fed as input (edge detection / Canny, depth maps, pose / OpenPose, normal maps, etc.)
  • During training, only the ControlNet branch is trained; the original model weights are frozen

Common ControlNet types:

  • Canny Edge: controls outlines
  • Depth: controls depth structure
  • OpenPose: controls human pose
  • Segment: controls region segmentation
  • Scribble: controls sketch-based guidance

LoRA (Low-Rank Adaptation) is a parameter-efficient fine-tuning method.
LoRA freezes the original model weights and trains only a small number of low-rank matrices to approximate the parameter updates needed for task adaptation. The trainable parameter count is just 0.1%–1% of full fine-tuning, drastically reducing VRAM usage and training cost. During inference, the weights can be merged with the base model, adding no extra latency.
In game development, LoRA lets you quickly fine-tune an image-to-image model to generate stylistically consistent character equipment and environment assets, or fine-tune a dialogue model so NPCs produce setting-appropriate natural dialogue — a great fit for small teams that need to move fast.

What Is the Difference Between MVC, MVP, and MVVM?

Pattern Component Responsibilities Component Relationships Pros / Cons
MVC Model (data) / View (UI) / Controller (logic) Controller directly operates both Model and View Simple and intuitive, good for small projects; Controller can become bloated
MVP Model (data) / View (UI) / Presenter (logic) Presenter directly operates Model, updates View indirectly Presenter is highly testable; View depends on Presenter, increasing coupling
MVVM Model (data) / View (UI) / ViewModel (logic) ViewModel directly operates Model, updates View via data binding Two-way binding simplifies UI updates; steeper learning curve, potential performance overhead

MVP’s Presenter and MVVM’s ViewModel are very similar in responsibility — both act as intermediaries handling business logic and data interaction. The key difference is that MVVM’s data-binding mechanism lets ViewModel update the View directly, eliminating the large amount of UI-update code you’d write in a Presenter. This makes the code more concise and testable. MVVM suits projects with complex, frequent UI interactions; MVP fits simpler UIs or scenarios where strict test isolation is needed.

What Are the Complete Stages of the GPU Rendering Pipeline?

Reference answer:

The GPU Rendering Pipeline is the full process by which a GPU executes graphics rendering:

Application Stage (CPU side):

1
2
3
4
1. Application Stage
→ Frustum Culling
→ Draw Call Batching
→ Outputs Draw Calls + vertex data to GPU

Geometry Stage (GPU vertex shaders):

1
2
3
4
5
6
7
8
9
2. Vertex Shader
→ Model Space → World Space → View Space → Homogeneous Clip Space
→ Vertex transform: LocalMatrix × WorldMatrix × ViewMatrix × ProjectionMatrix

3. Tessellation (optional)
→ Hull Shader → Tessellator → Domain Shader

4. Geometry Shader (optional)
→ Processes per-primitive, can emit or discard primitives

Rasterization Stage:

1
2
3
4
5
6
7
8
9
10
5. Primitive Assembly & Clipping
→ Clipping (homogeneous space clipping)
→ Perspective Divide → NDC → Viewport Transform

6. Back-face Culling
→ Discards back-facing primitives based on vertex winding order (CW/CCW)

7. Rasterization
→ Discretization: points / lines / triangles → Fragments
→ Viewport Transform: NDC → Screen Space

Fragment / Pixel Stage:

1
2
3
4
5
6
7
8
8. Fragment Shader (Pixel Shader)
→ Per-pixel shading: lighting calculations, texture sampling, color output

9. Per-Fragment Operations
→ Depth Test (Z-Test)
→ Stencil Test
→ Alpha Blending
→ Output to Framebuffer