raylib文本绘制数量受限?超阈值后画面消失问题排查
Raylib绘制带文本圆形时画面消失的原因分析
问题现象
- 使用Raylib开发时,绘制带有
>_<文本的黄色圆形,当数量达到390个时,画面完全变黑消失 - 若仅绘制单个字符
>,则可绘制到430个圆形才出现同样问题
附问题代码:
#include <stdio.h> #include <raylib.h> #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 600 #define CIRCLES_CAPACITY 1024 // why?? #define CIRCLES_MAX 390 int main(void) { Vector2 circles[CIRCLES_CAPACITY] = {0}; for (int i = 0; i < CIRCLES_MAX - 2; i++) { // coordinates does not matter circles[i] = (Vector2){SCREEN_WIDTH * 0.5f, SCREEN_HEIGHT * 0.5f}; } size_t circles_len = CIRCLES_MAX - 2; InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "test"); //SetTargetFPS(60); while (!WindowShouldClose()) { BeginDrawing(); DrawFPS(10, 10); // add new circle when user left click if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { if (circles_len + 1 < CIRCLES_CAPACITY) { circles[circles_len++] = (Vector2){GetMouseX(), GetMouseY()}; } } // render circles for (size_t i = 0; i < circles_len; i++) { // draw a circle DrawCircleV(circles[i], 25, YELLOW); // >_< const char* smile_str = ">_<"; Vector2 smile_size = MeasureTextEx(GetFontDefault(), smile_str, 32, 0); // this line causes strange behaviour i think // draw a text on the circle DrawText(smile_str, (int)(circles[i].x - smile_size.x*0.5f - 3), (int)(circles[i].y - smile_size.y*0.5f), 32, BLACK); } // print count of circles if (IsKeyPressed(KEY_C)) { printf("Count of circles: %zu\n", circles_len); } ClearBackground(BLACK); EndDrawing(); } CloseWindow(); return 0; }
核心原因
1. 渲染顺序完全错误
你的代码中ClearBackground(BLACK);被放在了所有绘制操作之后,这违背了Raylib的基本渲染流程:
- 正确流程:
BeginDrawing()→ 清屏(ClearBackground) → 绘制所有内容 →EndDrawing() - 当前错误流程会导致:绘制的内容本应被后续清屏操作覆盖,但Raylib的批处理机制会延迟提交绘制命令,当缓冲区未填满时,绘制命令会在
EndDrawing()时才提交,刚好覆盖清屏结果,所以你能看到内容;当缓冲区满了之后,Raylib会自动提交缓冲区内容,随后执行清屏,最终画面只剩下黑色。
2. Raylib默认批处理缓冲区耗尽
Raylib使用顶点批处理优化2D绘制性能,所有DrawCircleV、DrawText这类操作都会把顶点数据打包到一个内部缓冲区中,缓冲区有固定容量(默认对应32768个顶点):
- 每个带
>_<的圆形:1个圆形(4个顶点,Raylib用四边形模拟圆) + 3个字符(每个字符对应1个四边形,4个顶点),总共16个顶点 - 单个
>的圆形:1个圆形(4顶点) + 1个字符(4顶点),总共8个顶点 - 前者的顶点消耗是后者的2倍,会更快耗尽缓冲区。当缓冲区满时,新的绘制命令无法被添加,后续内容无法渲染,加上错误的清屏顺序,就会出现画面全黑的现象。
解决办法
- 修正渲染顺序:把
ClearBackground(BLACK);移到BeginDrawing()之后、所有绘制操作之前,这是最基础的修复。 - 增大批处理缓冲区:在
InitWindow前调用SetBatchLimit(16384);(新版本Raylib支持),或者修改Raylib编译时的MAX_BATCH_ELEMENTS宏定义,提升缓冲区容量。 - 优化绘制操作:
- 预渲染表情为纹理,用
DrawTexture代替DrawText,减少每个圆形的顶点消耗 - 合并绘制逻辑,减少绘制调用次数,降低批处理压力
- 预渲染表情为纹理,用
- 分批渲染:当绘制元素数量接近缓冲区上限时,手动调用
EndDrawing()和BeginDrawing()刷新缓冲区,不过会增加一定性能开销。
内容的提问来源于stack exchange,提问作者user27336462
相关产品推荐
相关产品推荐

