Real-Time GLB Character and First-Person Sword VFX with CUDA + OpenGL on Jetson Orin Nano

Hello NVIDIA Developer Community,

I would like to share another real-time 3D rendering experiment that I have been developing on the NVIDIA Jetson Orin Nano Super.

This project combines a GLB character, an independently rendered first-person sword, CUDA-generated dynamic combat effects and OpenGL real-time rendering.

The main goal of this experiment is to investigate how increasingly complex GPU-generated attack geometry, particles, energy ribbons and screen-space effects behave on Jetson, especially when several effect layers are active at the same time.

Video Demonstration

The following video shows the current implementation:

The demonstration includes:

  • A real-time GLB character
  • An independently controlled first-person sword
  • Multi-stage sword attack sequences
  • GPU-generated particles
  • Dynamic energy ribbons
  • Circular and spiral attack geometry
  • Screen-facing impact effects
  • Large emissive combat effects
  • Character hit/reaction states
  • Combat-status HUD
  • Multiple overlapping transparent VFX layers

The video is intended as a technical rendering demonstration rather than a formal performance benchmark.

Rendering Architecture

The current rendering path can be simplified as:

GLB Character Rendering
→ Weapon Transform Update
→ CUDA Combat Geometry Generation
→ CUDA/OpenGL Shared Buffers
→ OpenGL Effect Rendering
→ Transparent VFX Composition
→ Post-Processing / Bloom

The GLB character and sword are maintained as independent scene objects.

This allows the weapon transform and attack trajectory to be updated independently from the character model.

CUDA is mainly responsible for generating or updating dynamic effect data, while OpenGL performs the final rasterization.

CUDA-Generated Dynamic Geometry

Several of the attack effects shown in the video are generated procedurally.

CUDA updates data such as:

  • Ribbon vertices
  • Attack-path positions
  • Particle positions
  • Particle lifetime
  • Spiral geometry
  • Radial effect geometry
  • Fragment direction
  • Vertex opacity
  • Emissive intensity
  • Effect scale
  • Rotation parameters

The intention is to avoid calculating large amounts of dynamic effect geometry on the CPU.

The resulting geometry can then be transferred directly into OpenGL rendering resources through CUDA–OpenGL interoperability.

CUDA–OpenGL Interoperability

One of the main areas I am currently investigating is synchronization between CUDA-generated geometry and OpenGL rendering.

The current workflow is approximately:

OpenGL VBO
→ CUDA resource mapping
→ CUDA kernel updates vertices
→ CUDA resource unmapping
→ OpenGL rendering

For effects that change every frame, repeated mapping, kernel execution and rendering may introduce synchronization overhead.

I am currently comparing approaches such as:

  • Single-buffer rendering
  • Double buffering
  • Triple buffering
  • Explicit OpenGL fences
  • Separate CUDA streams
  • Preallocated effect buffers
  • Reduced synchronization between effect stages

I previously prepared a minimal CUDA–OpenGL sample to isolate this path, and I am now applying the same profiling methodology to the larger 3D scene.

Multi-Stage Combat Effects

The video contains several attack phases with very different GPU workloads.

Some phases contain only:

  • A character
  • A sword
  • A small number of particles

Other phases simultaneously contain:

  • Large transparent ribbons
  • Radial geometry
  • Multiple particle systems
  • High-intensity emissive effects
  • Full-screen energy structures
  • Several overlapping transparent layers

This makes the project useful for observing how GPU load changes as effect complexity increases.

Transparency and Overdraw

One of the biggest performance concerns is transparent overdraw.

During the larger attacks, many translucent or additive surfaces overlap in the same screen area.

This can significantly increase fragment processing even if the actual geometry count is not extremely high.

I am currently investigating:

  • Reducing unnecessary transparent pixels
  • Culling expired effect geometry
  • Limiting full-screen effect coverage
  • Reducing particle count dynamically
  • Rendering selected effects at reduced resolution
  • Optimizing blend operations
  • Adjusting effect quality according to GPU load

Emissive Effects and Bloom

The visual style uses high-intensity emissive effects.

During some attack phases, many bright layers overlap simultaneously.

This introduces another challenge: preserving the detail of the character and weapon while maintaining the intended high-energy appearance.

I am currently tuning:

  • Emissive intensity
  • HDR range
  • Bloom threshold
  • Exposure
  • Tone mapping
  • Additive blending
  • Highlight preservation

The goal is to avoid losing character detail when very bright attacks fill a large part of the screen.

Performance Profiling

Based on previous feedback from the NVIDIA Developer Forum, I am also profiling the project using:

  • tegrastats
  • Nsight Systems
  • CUDA event timing
  • Per-frame CPU/GPU timing

I am particularly interested in determining whether the main bottleneck during the largest attacks comes from:

  1. CUDA geometry generation
  2. CUDA–OpenGL synchronization
  3. OpenGL vertex processing
  4. Transparent fragment overdraw
  5. Post-processing
  6. CPU/GPU synchronization

The visual complexity changes substantially during the approximately one-minute effect sequence, so profiling each attack phase independently may provide more useful information than looking only at average FPS.

Current Development Focus

My current optimization areas are:

  • CUDA–OpenGL synchronization
  • Dynamic VBO management
  • Transparent-effect overdraw
  • Particle workload scaling
  • Reduced-resolution VFX rendering
  • Bloom and exposure stability
  • GPU utilization analysis
  • Frame-time stability
  • Minimizing CPU-side effect generation
  • Maintaining stable performance during large multi-layer attacks

Questions for the Community

I would appreciate feedback on several points:

  1. For dynamic combat geometry that is regenerated every frame, is CUDA writing directly into registered OpenGL VBOs still a good approach on Jetson Orin Nano?

  2. For workloads with many overlapping transparent ribbons and particles, is fragment overdraw likely to become a larger bottleneck than CUDA vertex generation?

  3. Would rendering large transparent VFX into a half-resolution or quarter-resolution framebuffer be a reasonable optimization on Jetson?

  4. For CUDA–OpenGL interoperability, would triple-buffered VBOs generally help reduce synchronization stalls compared with reusing one buffer every frame?

  5. Is there a recommended Nsight Systems workflow for separating CUDA kernel time, CUDA–OpenGL synchronization time and OpenGL rendering stalls?

  6. When the GPU is not fully utilized but frame time is still unstable, which synchronization points would you recommend checking first?

If useful, I can also isolate one of the larger sword-effect stages into a smaller reproducible sample for profiling.

Thank you for reading.

Any feedback regarding CUDA–OpenGL interoperability, dynamic GPU geometry, transparent rendering or Jetson-specific graphics optimization would be greatly appreciated.

Hi
When you run the application, what’s the GPU loading shown in sudo tegrastats? Probably GPU is at full loading, capping performance.

Hi DaneLLL,

Thank you for the suggestion.

I tested the application again with sudo tegrastats while the heavy 3D/VFX scene was running.

Your assumption appears to be correct.

During the captured interval, GR3D utilization remained almost continuously at approximately 98–99%.

Some representative results were:

GR3D_FREQ: 98–99%
EMC_FREQ: approximately 16–19%
RAM usage: approximately 3.48–3.56 GB / 7.62 GB
GPU temperature: approximately 59–61 C
VDD_IN: approximately 13.3–15.4 W

The GR3D load stayed close to full utilization throughout the heavy effect sequence, so it appears that this workload is currently GPU-bound.

Interestingly, EMC utilization was much lower than GR3D during the same period, so my next step is to profile the rendering stages in more detail and determine which GPU workload is dominating the frame time.

The main candidates I am currently investigating are:

  • CUDA-generated dynamic geometry
  • CUDA–OpenGL synchronization
  • Large transparent particle/ribbon overdraw
  • OpenGL fragment workload
  • Bloom/post-processing
  • Multiple overlapping VFX layers

I will next collect an Nsight Systems profile during the heaviest attack section.

I can also provide the minimal reproducible CUDA–OpenGL sample that I prepared if it would be useful for further analysis on the developer kit.

I have attached the tegrastats result for reference.

Thank you again for the guidance.