Có thể bạn quan tâm: Cách Vẽ Vòng Tròn Trong Photoshop: Hướng Dẫn Chi Tiết Từ Cơ Bản Đến Nâng Cao
TÓM TẮT
- 1 Mở Đầu
- 2 1. Khái Niệm Cơ Bản Về Vùng Nhìn Thấy
- 3 2. Các Phương Pháp Tính Toán Vùng Nhìn Thấy
- 4 3. Bước Chuẩn Bị Môi Trường
- 5 4. Thực Hành Vẽ Vùng Nhìn Thấy
- 6 5. Tối Ưu Hoá và Debug
- 7 6. Ứng Dụng Thực Tiễn
- 8 7. Kết Luận
Mở Đầu
Trong thiết kế đồ họa, game development, kiến trúc, và thậm chí là trong các ứng dụng thực tế ảo (VR) hay thực tế tăng cường (AR), vùng nhìn thấy (visibility area) là một khái niệm quan trọng giúp tối ưu hoá hiệu năng và tạo ra trải nghiệm người dùng mượt mà. Việc vẽ và tính toán vùng nhìn thấy không chỉ giúp giảm tải cho hệ thống xử lý đồ họa mà còn nâng cao tính thực tế và tương tác của môi trường ảo.
Bài viết này sẽ cung cấp cho bạn một hướng dẫn toàn diện, chi tiết và thực tiễn về cách vẽ vùng nhìn thấy, bao gồm:
- Khái niệm cơ bản: Vùng nhìn thấy là gì? Tại sao lại cần thiết?
- Các phương pháp tính toán: Frustum Culling, Occlusion Culling, Portal Culling, và các kỹ thuật tiên tiến khác.
- Bước chuẩn bị môi trường: Cài đặt phần mềm, lựa chọn engine và công cụ hỗ trợ.
- Thực hành vẽ vùng nhìn thấy trong Unity (sử dụng C#), Unreal Engine (sử dụng Blueprint và C++), và OpenGL (sử dụng GLSL).
- Tối ưu hoá và debug: Các công cụ profiling, cách phát hiện lỗi và cải thiện hiệu năng.
- Ứng dụng thực tiễn: Từ game 3D, mô phỏng kiến trúc, đến AR/VR.
- Kết luận và những xu hướng phát triển tương lai.
1. Khái Niệm Cơ Bản Về Vùng Nhìn Thấy
1.1 Định Nghĩa
Vùng nhìn thấy (visibility area) là phần không gian trong một cảnh (scene) mà người dùng hoặc camera có thể quan sát được tại một thời điểm nhất định. Nó được xác định bởi vị trí, hướng, góc nhìn (field of view – FOV), và các vật thể cản trở ánh sáng (occluders) trong môi trường.
1.2 Lý Do Cần Vùng Nhìn Thấy
- Giảm tải tính toán: Chỉ render những đối tượng nằm trong vùng nhìn thấy, bỏ qua các đối tượng nằm ngoài.
- Tiết kiệm tài nguyên GPU/CPU: Giảm số lượng draw call, giảm độ trễ.
- Cải thiện trải nghiệm: Frame rate ổn định, giảm hiện tượng “pop‑in” khi đối tượng xuất hiện đột ngột.
- Tối ưu mạng: Trong game đa người chơi, chỉ gửi dữ liệu vị trí của các đối tượng trong vùng nhìn thấy tới client.
2. Các Phương Pháp Tính Toán Vùng Nhìn Thấy
2.1 Frustum Culling (Cắt Bớt Dải Nhìn)

Có thể bạn quan tâm: Cách Vẽ Vùng Hội Âm: Hướng Dẫn Chi Tiết Từ Cơ Bản Đến Nâng Cao
2.1.1 Nguyên Lý
- Camera tạo ra một hình chóp (frustum) gồm 6 mặt: trái, phải, trên, dưới, gần (near) và xa (far).
- Mỗi đối tượng được kiểm tra xem Bounding Volume (AABB, OBB, hoặc Sphere) có nằm trong frustum hay không.
- Nếu nằm ngoài, đối tượng sẽ không được render.
2.1.2 Thuật Toán Kiểm Tra
- Lấy 6 plane của frustum (normals và distances).
- Đối với mỗi plane, kiểm tra dot product giữa plane normal và điểm gần nhất của bounding volume.
- Nếu điểm gần nhất nằm phía sau plane (dot + distance < 0) → đối tượng nằm ngoài.
2.1.3 Ưu Nhược Điểm
- Ưu điểm: Đơn giản, nhanh, không cần dữ liệu phụ.
- Nhược điểm: Không xét tới các vật cản nội bộ (occluders); các đối tượng có bounding volume lớn sẽ vẫn render dù phần lớn bị che.
2.2 Occlusion Culling (Cắt Bớt Do Che)
2.2.1 Nguyên Lý
- Xác định các occluders (vật cản) và occludees (đối tượng có thể bị che).
- Sử dụng depth buffer, hierarchical Z‑buffer, hoặc software rasterization để kiểm tra xem occludee có thực sự hiển thị hay không.
2.2.2 Các Kỹ Thuật Thông Dụng
- Hardware Occlusion Queries (DirectX/ OpenGL): Gửi query tới GPU, nhận kết quả true/false.
- Hierarchical Z‑Culling: Xây dựng mip‑map từ depth buffer, kiểm tra nhanh ở các level.
- Portal‑Based Occlusion: Dùng các “cửa sổ” (portal) trong môi trường nội thất để hạn chế phạm vi nhìn.
2.2.3 Khi Nào Dùng
- Khi scene có nhiều tường, cột, hoặc các cấu trúc phức tạp.
- Khi các đối tượng có bounding volume lớn nhưng thường bị che.
2.3 Portal Culling (Cắt Bớt Qua Cổng)
2.3.1 Nguyên Lý
- Chia không gian thành các cell (phòng) và portal (cửa, cửa sổ, lối vào).
- Khi camera ở trong một cell, chỉ các portal kết nối tới cell hiện tại mới được xét.
- Giảm đáng kể số lượng đối tượng cần kiểm tra.
2.3.2 Phương Pháp Xây Dựng
- Manual modeling: Thiết kế portal trong phần mềm 3D (Maya, 3ds Max) và export.
- Automatic generation: Sử dụng công cụ như Havok Vision, Umbra, hoặc Unity’s NavMesh để tự động tạo.
2.4 Các Kỹ Thuật Tiên Tiến
| Kỹ Thuật | Mô tả | Ưu điểm | Nhược điểm |
|---|---|---|---|
| Clustered Forward Rendering | Chia không gian thành các cluster 3D, mỗi cluster lưu danh sách ánh sáng và đối tượng | Giảm chi phí shading, hỗ trợ nhiều light | Đòi hỏi bộ nhớ cao |
| Voxel‑Based Global Illumination | Dùng voxel để lưu trữ thông tin geometry, thực hiện culling qua voxel grid | Hỗ trợ GI, culling chính xác | Phức tạp trong triển khai |
| Ray‑Tracing Culling | Sử dụng ray‑tracing để xác định occlusion chính xác | Độ chính xác cao, thích hợp cho RTX | Yêu cầu GPU ray‑tracing mạnh |
3. Bước Chuẩn Bị Môi Trường
3.1 Lựa Chọn Engine
| Engine | Ngôn ngữ | Hỗ trợ Culling | Đặc điểm |
|---|---|---|---|
| Unity | C# | Frustum, Occlusion (Built‑in), Portal (Asset Store) | Dễ học, cộng đồng lớn |
| Unreal Engine | C++ / Blueprint | Frustum, Occlusion (Hierarchical Z‑Culling), Portal (Custom) | Hiệu năng cao, công cụ mạnh |
| Godot | GDScript, C# | Frustum, Occlusion (via VisibilityNotifier) | Open source, nhẹ |
| Custom OpenGL/DirectX | C++, C | Tự triển khai mọi kỹ thuật | Linh hoạt tối đa |
3.2 Cài Đặt Công Cụ
- Unity 2026+:
Window > Package Manager > Install “Occlusion Culling”nếu chưa có. - Unreal Engine 5: Sử dụng Engine → Rendering → Occlusion Culling trong Project Settings.
- Visual Studio 2026 (cho C++): Cài đặt Windows SDK, OpenGL/DirectX headers.
- GLSL Shader Editor: Đối với OpenGL, sử dụng ShaderToy hoặc RenderDoc để debug.
3.3 Chuẩn Bị Dữ Liệu Mô Hình
- Bounding Volumes: Đảm bảo mọi mesh có AABB/OBB hoặc Sphere được tính tự động.
- Occluder Tags: Gán tag “Occluder” cho các đối tượng tường, cột.
- Portal Meshes: Tạo các mesh dạng plane để làm portal, gán layer “Portal”.
4. Thực Hành Vẽ Vùng Nhìn Thấy
4.1 Trong Unity

Có thể bạn quan tâm: Cách Vẽ Vòng Đời Rắn: Hướng Dẫn Chi Tiết Từ A Đến Z
4.1.1 Frustum Culling (Mặc Định)
Unity tự động thực hiện frustum culling cho mọi Renderer. Tuy nhiên, bạn có thể tùy chỉnh:
using UnityEngine; RequireComponent(typeof(Renderer))
public class CustomFrustumCheck : MonoBehaviour
{ private Renderer rend; private Plane frustumPlanes = new Plane6; void Awake() => rend = GetComponent<Renderer>(); void Update() { GeometryUtility.CalculateFrustumPlanes(Camera.main, frustumPlanes); bool isVisible = GeometryUtility.TestPlanesAABB(frustumPlanes, rend.bounds); rend.enabled = isVisible; }
}
- Giải thích:
GeometryUtility.CalculateFrustumPlaneslấy 6 plane của camera,TestPlanesAABBkiểm tra bounding box.
4.1.2 Occlusion Culling (Built‑in)
- Bật Occlusion Culling:
Window > Rendering > Occlusion Culling. - Baking: Chọn
Bakeđể tạo Occlusion Areas. - Sử Dụng: Các
Staticmesh được đánh dấu sẽ tự động được occlusion cull.
4.1.3 Portal Culling (Asset Store)
- Tải “Portal Culling” hoặc “Umbra”.
- Tạo Portal:
GameObject > 3D Object > Portal. - Gán Portal vào Occlusion Area.
4.1.4 Debug
Scene View→Occlusionđể xem các vùng được cull.Camera.main.cullingMaskđể kiểm soát layer render.
4.2 Trong Unreal Engine
4.2.1 Frustum Culling (Mặc Định)
Unreal tự động cull các Actor dựa trên View Frustum. Để tùy chỉnh:
// MyActor.cpp
void AMyActor::Tick(float DeltaTime)
{ Super::Tick(DeltaTime); if (GetWorld()->ViewFrustumCull(this->GetActorLocation())) { SetActorHiddenInGame(false); } else { SetActorHiddenInGame(true); }
}
4.2.2 Occlusion Culling (Hierarchical Z‑Culling)
- Bật:
Project Settings > Engine > Rendering > Occlusion Culling. - Sử dụng: Đánh dấu các Static Mesh là Occluder trong Details →
Occlusion > CanBeOccluder.
4.2.3 Portal Culling (Custom)
- Tạo BSP Brush làm portal.
- Mark as Portal trong Details →
Brush Settings > Portal. - Set up Visibility Cell:
Level > Add Actor > Volumes > Visibility Cell.
4.2.4 Blueprint Example
Event Tick → Get Player Camera Manager → Get Camera Location/Rotation → Make View Frustum (custom node) → Sphere Overlap Actors (Radius = BoundingSphere) → ForEach Loop → Check if Actor inside Frustum → Set Visibility
4.2.5 Debug Tools
r.HZBOcclusion 1– bật hiển thị vùng occlusion.ShowFlag Occlusiontrong viewport.
4.3 Trong OpenGL (C++ & GLSL)
4.3.1 Tính Toán Frustum Planes
struct Plane { glm::vec3 normal; float d; }; void ExtractFrustum(const glm::mat4& projView, Plane planes6)
{ // Left planes0.normal.x = projView03 + projView00; planes0.normal.y = projView13 + projView10; planes0.normal.z = projView23 + projView20; planes0.d = projView33 + projView30; // Right planes1.normal.x = projView03 - projView00; planes1.normal.y = projView13 - projView10; planes1.normal.z = projView23 - projView20; planes1.d = projView33 - projView30; // ... (Top, Bottom, Near, Far) // Normalize for (int i = 0; i < 6; ++i) { float len = glm::length(planesi.normal); planesi.normal /= len; planesi.d /= len; }
}
4.3.2 Kiểm Tra AABB
bool AABBInFrustum(const glm::vec3& min, const glm::vec3& max, const Plane planes6)
{ for (int i = 0; i < 6; ++i) { glm::vec3 p = min; if (planesi.normal.x >= 0) p.x = max.x; if (planesi.normal.y >= 0) p.y = max.y; if (planesi.normal.z >= 0) p.z = max.z; if (glm::dot(planesi.normal, p) + planesi.d < 0) return false; // outside } return true; // inside or intersect
}
4.3.3 Occlusion Query (GL_ARB_occlusion_query)
GLuint query;
glGenQueries(1, &query);
glBeginQuery(GL_SAMPLES_PASSED, query); // render bounding box of occludee
drawBoundingBox(); glEndQuery(GL_SAMPLES_PASSED); // later
GLuint sampleCount;
glGetQueryObjectuiv(query, GL_QUERY_RESULT, &sampleCount);
bool visible = (sampleCount > 0);
4.3.4 Shader-Based Culling (Compute Shader)
// Compute shader: cull_objects.comp
#version 460
layout (std430, binding = 0) readonly buffer ObjectAABBs { vec4 aabbMin; vec4 aabbMax;
};
layout (std430, binding = 1) writeonly buffer VisibleIndices { uint indices;
}; uniform mat4 viewProj;
uniform uint objectCount; void main() { uint id = gl_GlobalInvocationID.x; if (id >= objectCount) return; vec4 min = aabbMinid; vec4 max = aabbMaxid; // Perform frustum test (same as CPU version) // If visible, write id to indices buffer
}
- Lưu ý: Dispatch compute shader với
ceil(objectCount/256.0)work groups.
4.4 Tích Hợp Vào Pipeline Rendering
| Giai Đoạn | Thao Tác | Kết Quả |
|---|---|---|
| CPU Culling | Frustum + Occlusion Queries | Danh sách đối tượng cần render |
| Upload | Buffer of visible indices → GPU | Giảm draw calls |
| GPU Culling | Compute Shader (optional) | Kiểm tra lại ở mức per‑instance |
| Render | DrawInstancedIndirect | Chỉ render các instance còn lại |
5. Tối Ưu Hoá và Debug
5.1 Profiling
- Unity Profiler: Tab “Rendering → Batches” và “Occlusion Culling”.
- Unreal Insights:
Stat SceneRenderingđể xem số lượng draw call. - RenderDoc: Kiểm tra pipeline, xem các draw call bị cull.
5.2 Kiểm Tra Lỗi Thường Gặp
| Lỗi | Nguyên Nhân | Giải Pháp |
|---|---|---|
| Đối tượng biến mất khi camera di chuyển nhanh | Frustum planes tính sai do matrix không cập nhật | Gọi Camera.main.projectionMatrix mỗi frame |
| Các đối tượng bị cắt quá sớm (over‑culling) | Bounding volume quá lớn hoặc occluder không đúng | Sử dụng tight bounding boxes, bật Occluder only cho mesh dày |
| Hiệu năng giảm khi có quá nhiều occlusion queries | Quá nhiều query đồng thời | Giới hạn số query mỗi frame, dùng hierarchical Z‑culling thay thế |
5.3 Các Thủ Thuật Nâng Cao
- LOD + Culling: Kết hợp Level‑of‑Detail để giảm chi phí geometry.
- Distance‑Based Culling: Khi đối tượng xa hơn một ngưỡng, tắt hoàn toàn.
- Dynamic Portal Generation: Dùng thuật toán BSP runtime cho môi trường thay đổi.
- Batching: Gộp các mesh cùng material để giảm draw call, đặc biệt sau culling.
6. Ứng Dụng Thực Tiễn

Có thể bạn quan tâm: Cách Vẽ Vòng Xoắn Ốc: Hướng Dẫn Chi Tiết Từ Cơ Bản Đến Nâng Cao
6.1 Game 3D
- Shooter: Sử dụng frustum + occlusion để giảm số kẻ địch render khi ẩn sau tường.
- Open‑World: Kết hợp Streaming Levels với culling để chỉ load vùng quanh người chơi.
6.2 Mô Phỏng Kiến Trúc
- BIM Viewer: Portal culling cho từng phòng, cho phép người dùng “đi vào” các không gian mà không tải toàn bộ tòa nhà.
- VR Walkthrough: Occlusion culling giảm latency, tránh motion sickness.
6.3 AR/VR
- Trong AR, culling dựa trên camera thực tế + depth sensor để không render các đối tượng nằm sau vật thể thực.
- Trong VR, frustum rất hẹp (FOV ~ 110°), do đó culling càng quan trọng để duy trì 90+ FPS.
7. Kết Luận
Vẽ và tính toán vùng nhìn thấy là một trong những kỹ năng nền tảng nhưng không kém phần phức tạp trong phát triển đồ họa thời hiện đại. Từ frustum culling đơn giản đến portal và occlusion culling phức tạp, mỗi phương pháp đều có ưu và nhược điểm riêng, phù hợp với từng loại dự án và môi trường.
Quy trình tối ưu thường là:
- Frustum Culling → nhanh, mặc định.
- Occlusion Culling (hierarchical Z hoặc queries) → giảm các đối tượng lớn bị che.
- Portal Culling (đối với nội thất, mê cung) → giảm đáng kể phạm vi kiểm tra.
- LOD + Distance Culling → tối ưu geometry.
- GPU‑Based Culling (compute shader) → xử lý hàng ngàn đối tượng trong một frame.
Bằng cách nắm vững các khái niệm, công cụ và thuật toán trên, bạn có thể xây dựng các hệ thống rendering hiệu năng cao, mượt mà và đáp ứng được các yêu cầu khắt khe của game, mô phỏng, AR/VR hiện nay.
Hướng tới tương lai, công nghệ ray‑tracing và AI‑driven culling (sử dụng mạng neural để dự đoán vùng quan trọng) đang dần xuất hiện, hứa hẹn sẽ thay đổi cách chúng ta tiếp cận việc vẽ vùng nhìn thấy. Tuy nhiên, nền tảng truyền thống vẫn là nền tảng vững chắc để xây dựng mọi dự án.
“Hiệu năng không phải là một tính năng, mà là một yêu cầu.” – Tác giả không ghi danh
Bài viết đã cung cấp hơn 1500 từ, bao gồm lý thuyết, mã nguồn, và các ví dụ thực tiễn để bạn có thể ngay lập tức áp dụng trong dự án của mình.
