njin
Engine 2D gọn nhẹ để tự tay làm game theo ý mình. Vibe coding cũng ổn luôn
Loading...
Searching...
No Matches
Instancing

Vẽ hàng nghìn hình giống nhau bằng một lệnh vẽ, mỗi hình một ít dữ liệu riêng. Tiếp...

Classes

struct  njin::batch_grid2d
 Lưới chia mặt đất thành ô, để nhóm instance theo ô chứa tâm của chúng. Tiếp...
struct  njin::batch_view2d
 Phần mặt phẳng một camera thấy, do game dựng từ camera của mình mỗi frame. Tiếp...

Typedefs

using njin::instance_range = std::pair<u32, u32>
 Một đoạn instance [first, second) trong bộ đệm: vẽ bằng draw_instanced3d(ctx, mesh, buffer, first, second - first).

Các hàm

bool njin::instancing_available (const context &ctx)
 Máy này có vẽ instanced được không: cần OpenGL 3.3 trở lên (hoặc ES 3.0).
instance_buffer_handle njin::instance_buffer_create (context &ctx, u32 floats_per_instance)
 Tạo một bộ đệm instance trên GPU: mỗi instance là floats_per_instance số thực, do game tự quyết định ý nghĩa.
void njin::instance_buffer_destroy (context &ctx, instance_buffer_handle handle)
 Hủy bộ đệm instance.
void njin::instance_buffer_upload (context &ctx, instance_buffer_handle handle, const f32 *data, u32 count)
 Ghi count instance vào bộ đệm, thay toàn bộ nội dung cũ.
void njin::draw_instanced (context &ctx, instance_buffer_handle handle, shader_handle shader, u32 first, u32 count)
 Vẽ count hình vuông, bắt đầu từ instance first, bằng một lệnh vẽ.
void njin::draw_instanced (context &ctx, instance_buffer_handle handle, shader_handle shader, u32 first, u32 count, texture_handle texture)
 Như bản trên, và gắn texture vào uniform sampler2D texture0 của shader.
void njin::draw_instanced (context &ctx, instance_buffer_handle handle, shader_handle shader, u32 first, u32 count, render_texture_handle texture)
 Như bản trên, với một render texture, ví dụ sprite sheet vừa vẽ ra (bake) một lần bằng render_texture_begin().
bool njin::batch_cell_visible (const batch_grid2d &grid, const batch_view2d &view, i32 cell)
 Ô cell có lọt vào vùng nhìn không: hình chữ nhật của ô, nới thêm overhang, có chạm hình chữ nhật lo .
bool njin::batch_cell_detailed (const batch_grid2d &grid, const batch_view2d &view, i32 cell, f32 radius)
 Ô cell có ở gần không: khoảng cách từ view.focus đến hình chữ nhật của ô nhỏ hơn radius.
std::vector< instance_range > njin::batch_instance_ranges (std::span< const u32 > offsets, std::span< const u8 > wanted, std::span< const instance_range > excluded={})
 Các đoạn instance cần vẽ, từ những ô được chọn.

Mô tả chi tiết

Vẽ hàng nghìn hình giống nhau bằng một lệnh vẽ, mỗi hình một ít dữ liệu riêng.

Thông tin về hàm

◆ instancing_available()

bool njin::instancing_available ( const context & ctx)

Máy này có vẽ instanced được không: cần OpenGL 3.3 trở lên (hoặc ES 3.0).

Khi false, mọi hàm instance_* trả về handle không hợp lệ hoặc không làm gì; game nên có sẵn một cách vẽ khác (ví dụ texture_draw_ex() từng cái).

Các tham số
ctxContext của engine.
Giá trị trả về
true nếu draw_instanced() vẽ được.

◆ instance_buffer_create()

instance_buffer_handle njin::instance_buffer_create ( context & ctx,
u32 floats_per_instance )

Tạo một bộ đệm instance trên GPU: mỗi instance là floats_per_instance số thực, do game tự quyết định ý nghĩa.

Shader đọc chúng thành các thuộc tính vec4 theo instance, tên instance0, instance1, instance2, instance3 (4 số một thuộc tính, theo thứ tự). Bộ đệm tự lớn lên khi instance_buffer_upload() cần thêm chỗ.

Các tham số
ctxContext của engine.
floats_per_instance4, 8, 12 hoặc 16.
Giá trị trả về
Handle, hoặc handle có id 0 nếu số không hợp lệ hay máy không hỗ trợ (xem instancing_available()).

◆ instance_buffer_destroy()

void njin::instance_buffer_destroy ( context & ctx,
instance_buffer_handle handle )

Hủy bộ đệm instance.

Handle không hợp lệ bị bỏ qua.

Các tham số
ctxContext của engine.
handleBộ đệm cần hủy.

◆ instance_buffer_upload()

void njin::instance_buffer_upload ( context & ctx,
instance_buffer_handle handle,
const f32 * data,
u32 count )

Ghi count instance vào bộ đệm, thay toàn bộ nội dung cũ.

data có count * floats_per_instance số, instance này nối tiếp instance kia. Gọi mỗi frame với dữ liệu mới là cách dùng bình thường.

Các tham số
ctxContext của engine.
handleBộ đệm cần ghi.
dataDữ liệu các instance.
countSố instance.

◆ draw_instanced() [1/3]

void njin::draw_instanced ( context & ctx,
instance_buffer_handle handle,
shader_handle shader,
u32 first,
u32 count )

Vẽ count hình vuông, bắt đầu từ instance first, bằng một lệnh vẽ.

Mỗi hình vuông có 6 đỉnh (2 tam giác). Vertex shader của game nhận:

  • in vec3 vertexPosition: góc của hình vuông đơn vị, từ (0, 0) đến (1, 1), y hướng xuống. Chỉ xy có nghĩa.
  • in vec4 instance0 ... instance3: dữ liệu của instance đang vẽ.
  • uniform mat4 mvp: camera hiện tại, như khi vẽ bình thường.

Shader tự đặt hình vuông vào thế giới (vị trí, kích thước, góc xoay) từ dữ liệu instance. Cách trộn màu hiện tại (blend_begin()) được giữ nguyên; thứ đã vẽ trước đó được đẩy ra trước, nên thứ tự vẽ đúng như gọi. Instance vẽ sau đè lên instance vẽ trước: sắp xếp dữ liệu (ví dụ theo y) trước khi ghi.

Phải gọi giữa lúc bắt đầu và kết thúc vẽ của frame, ngoài shader_begin()/shader_end(). Uniform khác của shader đặt bằng shader_set_*() như thường.

Các tham số
ctxContext của engine.
handleBộ đệm đã ghi bằng instance_buffer_upload().
shaderShader có vertex shader đọc các thuộc tính trên.
firstInstance đầu tiên được vẽ.
countSố instance, bị cắt bớt nếu vượt quá số đã ghi.

◆ draw_instanced() [2/3]

void njin::draw_instanced ( context & ctx,
instance_buffer_handle handle,
shader_handle shader,
u32 first,
u32 count,
texture_handle texture )

Như bản trên, và gắn texture vào uniform sampler2D texture0 của shader.

Dùng khi mỗi instance là một khung trong một sprite sheet: vertex shader chọn khung từ dữ liệu instance, fragment shader đọc nó. Với texture nằm trong atlas (atlas_load()), toạ độ là của cả trang atlas.

Các tham số
ctxContext của engine.
handleBộ đệm đã ghi bằng instance_buffer_upload().
shaderShader có vertex shader đọc các thuộc tính trên.
firstInstance đầu tiên được vẽ.
countSố instance, bị cắt bớt nếu vượt quá số đã ghi.
textureTexture gắn vào texture0. Handle không hợp lệ thì không vẽ gì.

◆ draw_instanced() [3/3]

void njin::draw_instanced ( context & ctx,
instance_buffer_handle handle,
shader_handle shader,
u32 first,
u32 count,
render_texture_handle texture )

Như bản trên, với một render texture, ví dụ sprite sheet vừa vẽ ra (bake) một lần bằng render_texture_begin().

Toạ độ texture có gốc ở góc dưới trái của hình đã vẽ (v = 1 - y / chiều cao), vì framebuffer OpenGL lưu từ dưới lên. Render texture lấy mẫu kiểu filter_nearest trừ khi đổi bằng render_texture_set_filter().

Các tham số
ctxContext của engine.
handleBộ đệm đã ghi bằng instance_buffer_upload().
shaderShader có vertex shader đọc các thuộc tính trên.
firstInstance đầu tiên được vẽ.
countSố instance, bị cắt bớt nếu vượt quá số đã ghi.
textureRender texture gắn vào texture0. Handle không hợp lệ thì không vẽ gì.

◆ batch_cell_visible()

bool njin::batch_cell_visible ( const batch_grid2d & grid,
const batch_view2d & view,
i32 cell )

Ô cell có lọt vào vùng nhìn không: hình chữ nhật của ô, nới thêm overhang, có chạm hình chữ nhật lo .

. hi không.

Các tham số
gridLưới.
viewVùng nhìn của camera.
cellChỉ số ô.
Giá trị trả về
false cả khi ô, lưới hay vùng nhìn không hợp lệ.

◆ batch_cell_detailed()

bool njin::batch_cell_detailed ( const batch_grid2d & grid,
const batch_view2d & view,
i32 cell,
f32 radius )

Ô cell có ở gần không: khoảng cách từ view.focus đến hình chữ nhật của ô nhỏ hơn radius.

Dùng để chọn mức chi tiết (hình mịn ở gần, hình ít mặt ở xa). Hàm không xét vùng nhìn; kết hợp với batch_cell_visible() nếu cần.

Các tham số
gridLưới.
viewVùng nhìn, chỉ dùng focus.
cellChỉ số ô.
radiusBán kính vùng gần, lớn hơn 0.
Giá trị trả về
false cả khi ô, lưới, focus hay radius không hợp lệ.

◆ batch_instance_ranges()

std::vector< instance_range > njin::batch_instance_ranges ( std::span< const u32 > offsets,
std::span< const u8 > wanted,
std::span< const instance_range > excluded = {} )

Các đoạn instance cần vẽ, từ những ô được chọn.

Bộ đệm phải xếp instance theo ô: mọi instance của ô 0, rồi ô 1, ... offsets[c] là instance đầu của ô c, offsets[c + 1] là chỗ ô đó hết, nên offsets có wanted.size() + 1 phần tử, không giảm; ô rỗng được phép. Các ô được chọn liền nhau gộp thành một đoạn, rồi các đoạn trong excluded bị cắt bỏ.

Hàm không đổi gì ngoài kết quả, nên gọi được cho nhiều camera và trên thread khác, miễn là không ai sửa dữ liệu vào cùng lúc.

Các tham số
offsetsChỗ bắt đầu của từng ô trong bộ đệm, cộng chỗ kết thúc.
wantedMỗi ô một số: khác 0 là vẽ ô đó.
excludedCác đoạn không vẽ (ví dụ một vật đang được vẽ riêng), theo thứ tự bất kỳ, có thể chồng nhau. Đoạn rỗng hay ngược bị bỏ qua.
Giá trị trả về
Các đoạn tăng dần, không chồng nhau, không vượt offsets.back(). Rỗng nếu offsets sai kích thước hay có chỗ giảm.