#include <graphics.h>
#include <math.h>
#include <stdio.h>
#define PI 3.1415926f
#define LONGITUDE 80 // 经度细分
#define LATITUDE 80
#define R 1 // 球半径
// 全局控制
float g_scale = 1.0f;
float g_rotateY = 0.0f;
typedef struct { float x, y, z; } Point;
// 你的山体函数
float mountainFunc(float x, float y, float z) {
return x * y * y - z;
}
// 变形:沿法线方向移动
void deformPoint(Point& p, float strength) {
float offset = mountainFunc(p.x, p.y, p.z);
p.x += p.x * offset * strength;
p.y += p.y * offset * strength;
p.z += p.z * offset * strength;
}
// 透视投影
void project(Point p, int& sx, int& sy) {
// 绕 Y 轴旋转
float cosY = cos(g_rotateY);
float sinY = sin(g_rotateY);
float xr = p.x * cosY + p.z * sinY;
float zr = -p.x * sinY + p.z * cosY;
float yr = p.y;
int cx = 400, cy = 300;
float eyeDist = 500.0f;
float persp = eyeDist / (eyeDist + zr + 0.01f);
float scale = g_scale * 130.0f;
sx = cx + xr * persp * scale;
sy = cy - yr * persp * scale;
}
// 鼠标处理
void handleMouse() {
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
if (msg.uMsg == WM_MOUSEWHEEL) {
if (msg.wheel > 0)
g_scale = min(g_scale * 1.1f, 2.2f);
else
g_scale = max(g_scale * 0.9f, 0.4f);
}
else if (msg.uMsg == WM_MOUSEMOVE && (msg.mkCtrl & MK_LBUTTON)) {
g_rotateY += msg.x * 0.008f;
}
}
}
int main() {
initgraph(800, 600);
setbkcolor(BLACK);
cleardevice();
Point vertices[LONGITUDE + 1][LATITUDE + 1];
int centerI = 15, centerJ = 15;
int regionRadius = 5; // 区域半径(索引格数)
// 生成变形后的网格
for (int i = 0; i <= LONGITUDE; i++) {
float lon = i * 2 * PI / LONGITUDE;
float cosLon = cos(lon);
float sinLon = sin(lon);
for (int j = 0; j <= LATITUDE; j++) {
float lat = -PI / 2 + j * PI / LATITUDE;
float cosLat = cos(lat);
float sinLat = sin(lat);
float x = R * cosLat * cosLon;
float y = R * sinLat;
float z = R * cosLat * sinLon;
Point p = { x, y, z };
// 计算到中心点的距离(索引空间)
int di = i - centerI;
int dj = j - centerJ;
float dist = sqrt(di * di + dj * dj);
// 圆形区域变形,中心强边缘弱
if (dist <= regionRadius) {
float strength = 0.18f * (1 - dist / regionRadius);
deformPoint(p, strength);
}
vertices[i][j] = p;
}
}
BeginBatchDraw();
while (true) {
handleMouse();
cleardevice();
setlinecolor(RGB(80, 160, 255));
setlinestyle(PS_SOLID, 1);
// 绘制网格
for (int i = 0; i <= LONGITUDE; i++) {
for (int j = 0; j <= LATITUDE; j++) {
int sx, sy;
project(vertices[i][j], sx, sy);
if (j < LATITUDE) {
int sx2, sy2;
project(vertices[i][j + 1], sx2, sy2);
line(sx, sy, sx2, sy2);
}
if (i < LONGITUDE) {
int sx2, sy2;
project(vertices[i + 1][j], sx2, sy2);
line(sx, sy, sx2, sy2);
}
}
}
// 显示说明
settextcolor(RGB(255, 200, 100));
settextstyle(20, 0, _T("宋体"));
outtextxy(20, 20, _T("区域变形 | 公式: x*y²+z"));
outtextxy(20, 50, _T("中心在 (15,15) 附近 | 圆形衰减 | 滚轮缩放 | Ctrl+左键旋转"));
FlushBatchDraw();
Sleep(16);
}
EndBatchDraw();
getchar();
closegraph();
return 0;
}
为什么鼠标拖动的时候反应很慢很慢
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
2条回答 默认 最新
檀越@新空间 2026-03-20 21:33关注晚上好🌙🌙🌙
本答案参考通义千问你提到的问题是“鼠标拖动的时候反应很慢很慢”,在你的代码中,主要问题集中在以下几个方面:
一、问题原因分析
-
频繁的图形绘制(
cleardevice())和刷新- 你在每次循环中都调用了
cleardevice(),这会导致屏幕不断重绘,而由于图形库的性能限制,这会显著降低帧率。 - 如果没有使用双缓冲或批量绘制(如
BeginBatchDraw()和FlushBatchDraw()),这会导致明显的卡顿。
- 你在每次循环中都调用了
-
Sleep(16)的延迟- 你使用了
Sleep(16)来控制帧率,但这种方式并不精确,而且如果实际渲染时间小于 16ms,它仍然会强制等待,导致 CPU 占用低但画面不流畅。
- 你使用了
-
鼠标事件处理与渲染同步
- 鼠标事件处理(如旋转)是在主循环中进行的,如果主循环被阻塞或执行时间过长,也会造成响应延迟。
-
图形库本身性能限制
- 你使用的
graphics.h是一个较老的图形库,性能不如现代图形 API(如 OpenGL 或 DirectX),在高频率更新时容易出现卡顿。
- 你使用的
二、解决方案
1. 使用双缓冲技术优化绘制
- 使用
BeginBatchDraw()和FlushBatchDraw()进行批量绘制,避免逐帧刷新。 - 确保
BeginBatchDraw()和FlushBatchDraw()正确包裹整个绘制逻辑。
2. 优化鼠标事件处理
- 将鼠标事件处理与渲染分离,确保不会因为图形绘制耗时影响响应速度。
3. 移除不必要的
cleardevice()- 只有在需要重绘整个场景时才调用
cleardevice(),否则可以只绘制变化的部分。
4. 使用更高效的帧率控制方式
- 使用
timeGetTime()或clock()控制帧率,而不是Sleep()。
三、修改后的代码示例
以下是针对你提供的代码进行优化后的版本,重点在于减少重复绘制、提升响应速度,并保持功能不变:
#include <graphics.h> #include <math.h> #include <stdio.h> #include <windows.h> // 用于时间控制 #define PI 3.1415926f #define LONGITUDE 80 // 经度细分 #define LATITUDE 80 #define R 1 // 球半径 // 全局控制 float g_scale = 1.0f; float g_rotateY = 0.0f; typedef struct { float x, y, z; } Point; // 你的山体函数 float mountainFunc(float x, float y, float z) { return x * y * y - z; } // 变形:沿法线方向移动 void deformPoint(Point& p, float strength) { float offset = mountainFunc(p.x, p.y, p.z); p.x += p.x * offset * strength; p.y += p.y * offset * strength; p.z += p.z * offset * strength; } // 透视投影 void project(Point p, int& sx, int& sy) { // 绕 Y 轴旋转 float cosY = cos(g_rotateY); float sinY = sin(g_rotateY); float xr = p.x * cosY + p.z * sinY; float zr = -p.x * sinY + p.z * cosY; float yr = p.y; int cx = 400, cy = 300; float eyeDist = 500.0f; float persp = eyeDist / (eyeDist + zr + 0.01f); float scale = g_scale * 130.0f; sx = cx + xr * persp * scale; sy = cy - yr * persp * scale; } // 鼠标处理 void handleMouse() { if (MouseHit()) { MOUSEMSG msg = GetMouseMsg(); if (msg.uMsg == WM_MOUSEWHEEL) { if (msg.wheel > 0) g_scale = min(g_scale * 1.1f, 2.2f); else g_scale = max(g_scale * 0.9f, 0.4f); } else if (msg.uMsg == WM_MOUSEMOVE && (msg.mkCtrl & MK_LBUTTON)) { g_rotateY += msg.x * 0.008f; } } } int main() { initgraph(800, 600); setbkcolor(BLACK); cleardevice(); Point vertices[LONGITUDE + 1][LATITUDE + 1]; int centerI = 15, centerJ = 15; int regionRadius = 5; // 区域半径(索引格数) // 生成变形后的网格 for (int i = 0; i <= LONGITUDE; i++) { float lon = i * 2 * PI / LONGITUDE; float cosLon = cos(lon); float sinLon = sin(lon); for (int j = 0; j <= LATITUDE; j++) { float lat = -PI / 2 + j * PI / LATITUDE; float cosLat = cos(lat); float sinLat = sin(lat); float x = R * cosLat * cosLon; float y = R * sinLat; float z = R * cosLat * sinLon; Point p = { x, y, z }; // 计算到中心点的距离(索引空间) int di = i - centerI; int dj = j - centerJ; float dist = sqrt(di * di + dj * dj); // 圆形区域变形,中心强边缘弱 if (dist <= regionRadius) { float strength = 0.18f * (1 - dist / regionRadius); deformPoint(p, strength); } vertices[i][j] = p; } } BeginBatchDraw(); DWORD lastTime = GetTickCount(); // 获取当前时间 while (true) { handleMouse(); // 控制帧率 DWORD currentTime = GetTickCount(); if (currentTime - lastTime >= 16) { lastTime = currentTime; // 只在需要时清除设备 cleardevice(); setlinecolor(RGB(80, 160, 255)); setlinestyle(PS_SOLID, 1); // 绘制网格 for (int i = 0; i <= LONGITUDE; i++) { for (int j = 0; j <= LATITUDE; j++) { int sx, sy; project(vertices[i][j], sx, sy); if (j < LATITUDE) { int sx2, sy2; project(vertices[i][j + 1], sx2, sy2); line(sx, sy, sx2, sy2); } if (i < LONGITUDE) { int sx2, sy2; project(vertices[i + 1][j], sx2, sy2); line(sx, sy, sx2, sy2); } } } // 显示说明 settextcolor(RGB(255, 200, 100)); settextstyle(20, 0, _T("宋体")); outtextxy(20, 20, _T("区域变形 | 公式: x*y²+z")); outtextxy(20, 50, _T("中心在 (15,15) 附近 | 圆形衰减 | 滚轮缩放 | Ctrl+左键旋转")); FlushBatchDraw(); } } EndBatchDraw(); getchar(); closegraph(); return 0; }
四、关键改进点总结
- 使用
BeginBatchDraw()和FlushBatchDraw()提升绘制效率 - 移除了不必要的
cleardevice(),只在必要时调用 - 使用
GetTickCount()控制帧率,替代Sleep(16) - 将鼠标事件处理与渲染分离,提升响应速度
五、建议进一步优化方向
如果你希望获得更高的性能和更流畅的交互体验,可以考虑以下方向:
- 使用 OpenGL 或 DirectX:这些现代图形 API 性能更强,适合复杂图形应用。
- 采用多线程:将图形渲染和逻辑处理分离开,提高程序响应性。
- 优化顶点计算:预计算顶点位置并缓存,避免每次循环重新计算。
如果你还有其他问题,比如如何实现更复杂的变形算法或增加光照效果,也欢迎继续提问!
解决 无用评论 打赏 举报-