You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenGL与C实现的神经细胞自动机无法正确渲染图形问题求助

问题分析与修复方案

我仔细看了你的代码,问题主要出在卷积计算的索引对应错误、直接修改原网格导致状态污染,还有display函数的更新逻辑混乱这几个地方,直接导致滑翔机的行为完全偏离康威生命游戏的规则。下面逐个拆解问题并给出修复方案:

1. 卷积滤波器的索引对应错误

你的CVFilter函数里,网格邻居和filter的索引完全对应错了。比如你写的grid[y+1][x+1]*filter[2][2],y+1是当前细胞的上方邻居,对应filter的第0行(3x3 filter的[0][0]是左上、[0][1]是上中、[0][2]是右上),但你误用了filter[2][2](右下),行方向完全搞反了,这会让卷积计算结果完全错误。

2. 直接修改原网格导致状态污染

你在计算新细胞状态时,直接把结果写回原grid数组,这样计算后面的细胞时,会用到已经更新过的邻居状态,而不是当前帧的初始状态。这相当于打乱了生命游戏的“同步更新”规则,必须用临时数组存储新状态,所有细胞计算完成后再替换原网格。

3. Display函数的更新逻辑错误

你的display函数只有frame == 1时才调用CVFilter,之后就不再更新网格状态了;而且sleep(1000)的逻辑明显是笔误(会让程序卡住1000秒),加上glutPostRedisplay()会不断触发display,frame会持续递增,最终只有第一帧做了状态更新,之后完全停滞。


修复后的完整代码

#include <stdio.h>
#include <windows.h>
#include <GL/glut.h>
#define sleep(x) Sleep(1000 * (x))
#define sizeX 10
#define sizeY 10
#define wallSize 40
int frame = 0;
double grid[sizeY][sizeX];
double filter[3][3] = {{1, 1, 1}, {1, 9, 1}, {1, 1, 1}};
int width = 1000;
int height = 500;

double activation(double x){
    // 对应康威规则:
    // x=3 → 死细胞周围3个活邻居 → 复活
    // x=11 → 活细胞周围2个活邻居(9+2)→ 存活
    // x=12 → 活细胞周围3个活邻居(9+3)→ 存活
    if(x == 3 || x == 11 || x == 12){
        return 1;
    } else {
        return 0;
    }
}

void CVFilter(){
    int x,y;
    double cv;
    // 创建临时数组存储新状态,避免污染原网格
    double newGrid[sizeY][sizeX];

    // 复制原网格的边界(边界细胞不参与规则计算,保持初始状态)
    for(x = 0; x < sizeX; x++){
        newGrid[0][x] = grid[0][x];
        newGrid[sizeY-1][x] = grid[sizeY-1][x];
    }
    for(y = 0; y < sizeY; y++){
        newGrid[y][0] = grid[y][0];
        newGrid[y][sizeX-1] = grid[y][sizeX-1];
    }

    // 计算中间细胞的新状态
    for(y=1; y < sizeY-1; y++){
        for(x=1; x < sizeX-1; x++){
            // 修正filter索引对应关系:上方邻居→filter第0行,当前行→第1行,下方→第2行
            cv = grid[y+1][x-1]*filter[0][0] + grid[y+1][x]*filter[0][1] + grid[y+1][x+1]*filter[0][2] +
                 grid[y][x-1]*filter[1][0]   + grid[y][x]*filter[1][1]   + grid[y][x+1]*filter[1][2] +
                 grid[y-1][x-1]*filter[2][0] + grid[y-1][x]*filter[2][1] + grid[y-1][x+1]*filter[2][2];
            newGrid[y][x] = activation(cv);
        }
    }

    // 将临时数组的新状态同步回原网格
    for(y=0; y < sizeY; y++){
        for(x=0; x < sizeX; x++){
            grid[y][x] = newGrid[y][x];
        }
    }
}

void drawGrid(){
    int x,y;
    double rgb;
    glPointSize(wallSize);
    glBegin(GL_POINTS);
    for(y=0; y < sizeY; y++){
        for(x=0; x < sizeX; x++){
            rgb = grid[y][x];
            glColor3f(rgb, rgb, rgb);
            glVertex2i((x*wallSize), (y*wallSize));
        }
    }
    glEnd();
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 第一帧显示初始状态,之后每帧更新一次状态
    if(frame > 0){
        CVFilter();
    }

    drawGrid();

    glutSwapBuffers();
    glutPostRedisplay();
    sleep(1); // 控制帧率,每秒1帧,方便观察滑翔机移动
    frame++;
}

void init(){
    glClearColor(0.3, 0.3, 0.3, 0);
    gluOrtho2D(0, width, height, 0);
}

void main(int argc, char** argv){
    // 初始化标准滑翔机形状
    grid[3][5] = 1;
    grid[4][5] = 1;
    grid[5][5] = 1;
    grid[5][4] = 1;
    grid[4][3] = 1;

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(width, height);
    glutCreateWindow("OpenGL Game of Life");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
}

额外说明

  • 我保留了你原本的激活函数逻辑(因为它确实对应康威规则的卷积值判断),只是修正了卷积计算的错误
  • 现在每帧都会同步更新所有细胞状态,避免了状态污染问题
  • 调整了sleep逻辑,让每帧间隔1秒,方便清晰观察滑翔机的移动轨迹

修改后,滑翔机应该会按照康威生命游戏的规则,稳定地向右下方移动了。

内容的提问来源于stack exchange,提问作者Saw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 12:37:31