2015-06-16 18 views
5

Tôi đang làm việc trên một mô phỏng cho những đám mây (mây thực) nơi những đám mây được mô phỏng bằng các điểm 3D, sau đó chiếu thành một bản đồ 2D, khoảng 640x480 đơn vị lớn. Số điểm là khoảng 50k, nhỏ như tôi có thể đi mà không có sự phá vỡ mô phỏng, nhưng tôi không thể tìm cách để thực hiện điều này với bất kỳ tốc độ nào (thường mất 3-5 giây thời gian chạy)Có thể xây dựng bản đồ nhiệt từ dữ liệu điểm 60 lần mỗi giây không?

Tôi cho rằng câu hỏi của tôi là khả thi cho một máy tính trung bình có thể thực hiện điều này chưa? Tôi thường đánh giá thấp máy tính nhanh như thế nào hiện nay, nhưng tôi có thể đánh giá quá cao chúng trong trường hợp này. Tôi chưa tối ưu hóa mô phỏng, nhưng nếu nó không thể thực hiện được, thì tốt nhất là bạn nên biết và lưu lại sự cố.

Nếu có thể, có bất kỳ kỹ thuật nào có thể hữu ích cho việc chuyển đổi dữ liệu điểm thành bản đồ nhiệt đủ nhanh để cập nhật 60 lần một giây không? Nó thực sự chỉ là nhìn vào dữ liệu điểm và ghi vào một mảng 2D kết quả sau khi chuyển đổi, do đó, nó chủ yếu là ràng buộc để tra cứu bộ nhớ tôi nghĩ.

+0

Tôi nghĩ rằng bạn cần phải làm một số ước lượng thô về số lượng tính toán lại quired để thực hiện phép chiếu, mỗi điểm ảnh nhiệt và mỗi điểm 3D. Tôi không nghĩ rằng có một tiêu chuẩn cho điều đó để làm cho nó rõ ràng. Không phải khu vực của tôi mặc dù vậy tôi có thể sai. – unwind

+0

Liên quan đến [this] (http://stackoverflow.com/q/30857894/1888983)? Việc chia các hạt 50k thành hình ảnh 640x480 sẽ cực kỳ nhanh (trừ khi chúng lấp đầy toàn bộ hình ảnh). Gần đây tôi đã viết [this] (http://stackoverflow.com/a/30837947/1888983). – jozxyqk

+0

Bạn nên thực hiện một số điểm chuẩn để xem liệu các dự đoán 3D đến 2D có thực sự chậm hay không trước khi tối ưu hóa các bản cập nhật bản đồ nhiệt (tức là tỷ lệ phần trăm của 3-5 giây hiển thị hiện đang được chi tiêu trong các dự báo?) –

Trả lời

6

Điều này chắc chắn khả thi, có lẽ ngay cả khi việc tính toán được thực hiện bởi CPU. Lý tưởng nhất là bạn nên sử dụng GPU. Các API cần có hoặc là OpenCL hoặc vì bạn đang hiển thị kết quả mà bạn có thể muốn sử dụng Compute Shaders.

Cả hai kỹ thuật đều cho phép bạn viết một chương trình nhỏ (đổ bóng) hoạt động trên một phần tử (điểm) duy nhất. Tất cả đều chạy song song trên GPU, cho phép chúng chạy rất nhanh.

3

Yes nếu dữ liệu của bạn đã được tính toán trước trong bộ nhớ

Chỉ cần cố gắng nó ra với kết cấu SDL (hoặc kết cấu OpenGL trực tiếp, đó là những gì sử dụng SDL):

#include <math.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

#include <SDL2/SDL.h> 

#define COLOR_MAX 255 

double common_get_secs(void) { 
    struct timespec ts; 
    timespec_get(&ts, TIME_UTC); 
    return ts.tv_sec + (1e-9 * ts.tv_nsec); 
} 
const double COMMON_FPS_GRANULARITY_S = 0.5; 
double common_fps_last_time_s; 
unsigned int common_fps_nframes; 
void common_fps_init() { 
    common_fps_nframes = 0; 
    common_fps_last_time_s = common_get_secs(); 
} 
void common_fps_update_and_print() { 
    double dt, current_time_s; 
    current_time_s = common_get_secs(); 
    common_fps_nframes++; 
    dt = current_time_s - common_fps_last_time_s; 
    if (dt > COMMON_FPS_GRANULARITY_S) { 
     printf("FPS = %f\n", common_fps_nframes/dt); 
     common_fps_last_time_s = current_time_s; 
     common_fps_nframes = 0; 
    } 
} 

int main(void) { 
    SDL_Event event; 
    SDL_Renderer *renderer = NULL; 
    SDL_Texture *texture = NULL; 
    SDL_Window *window = NULL; 
    Uint8 *base; 
    int pitch; 
    void *pixels = NULL; 
    const unsigned int 
     WINDOW_WIDTH = 500, 
     WINDOW_HEIGHT = WINDOW_WIDTH; 
    const double 
     SPEED = WINDOW_WIDTH/10.0, 
     CENTER_X = WINDOW_WIDTH/2.0, 
     CENTER_Y = WINDOW_HEIGHT/2.0, 
     PERIOD = WINDOW_WIDTH/10.0, 
     PI2 = 2.0 * acos(-1.0); 
    double dt, initial_time; 
    float z; 
    unsigned int x, xc, y, yc; 

    SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO); 
    SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer); 
    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, 
     SDL_TEXTUREACCESS_STREAMING, WINDOW_WIDTH, WINDOW_HEIGHT); 
    initial_time = common_get_secs(); 
    common_fps_init(); 
    while (1) { 
     dt = common_get_secs() - initial_time; 
     SDL_LockTexture(texture, NULL, &pixels, &pitch); 
     for (x = 0; x < WINDOW_WIDTH; x++) { 
      for (y = 0; y < WINDOW_HEIGHT; y++) { 
       xc = CENTER_X - x; 
       yc = CENTER_Y - y; 
       /*z = COLOR_MAX * 0.5 * (1.0 + (sin(PI2 * (sqrt(xc*xc + yc*yc) - SPEED * dt)/PERIOD)));*/ 
       z = (int)(x + y + SPEED * dt) % COLOR_MAX; 
       base = ((Uint8 *)pixels) + (4 * (x * WINDOW_WIDTH + y)); 
       base[0] = 0; 
       base[1] = 0; 
       base[2] = z; 
       base[3] = COLOR_MAX; 
      } 
     } 
     SDL_UnlockTexture(texture); 
     SDL_RenderCopy(renderer, texture, NULL, NULL); 
     SDL_RenderPresent(renderer); 
     common_fps_update_and_print(); 
     if (SDL_PollEvent(&event) && event.type == SDL_QUIT) 
      break; 
    } 
    SDL_DestroyRenderer(renderer); 
    SDL_DestroyWindow(window); 
    SDL_Quit(); 
    return EXIT_SUCCESS; 
} 

Compile với :

gcc -Wall -std=c11 heatmap.c -lSDL2 -lm 

Trên Ubuntu 16.04, việc tính toán đơn giản hơn:

0.123.
z = (x + y + SPEED * dt) % COLOR_MAX 

đạt 300 FPS trên Lenovo Thinkpad T430 với Nvidia NVS 5400M (giữa năm 2012).

Vì vậy, tất nhiên, là kết quả tính toán trước vào bộ nhớ sẽ nhanh hơn.

Nếu việc tính toán là tuy nhiên một chút phức tạp hơn:

z = COLOR_MAX * 0.5 * (1.0 + (sin(PI2 * (sqrt(xc*xc + yc*yc) - SPEED * dt)/PERIOD))) 

FPS chỉ 30, do đó hạn chế nhanh chóng trở thành tính.

Nếu bạn không thể chạy tính toán đủ nhanh, bạn có thể sẽ cần phải lưu trữ vào đĩa để không tràn bộ nhớ, và sau đó nó là tất cả về điểm chuẩn đĩa của bạn + phương pháp nén (codec video).

Fragment shaders

Nếu bạn có thể chạy tính toán của bạn trên shader mảnh, bạn có thể làm những điều phức tạp hơn nhiều tuy nhiên trong thời gian thực.

Với mã sau, phép tính phức tạp hơn chạy tại 3k FPS!

Nhưng sẽ khó thực hiện hơn, vì vậy hãy đảm bảo bạn cần.

#include <math.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

#include <SDL2/SDL.h> 
#define GLEW_STATIC 
#include <GL/glew.h> 

static const GLuint WIDTH = 500; 
static const GLuint HEIGHT = 500; 
static const GLchar* vertex_shader_source = 
    "#version 120\n" 
    "attribute vec2 coord2d;\n" 
    "void main(void) {\n" 
    " gl_Position = vec4(coord2d, 0.0, 1.0);\n" 
    "}\n"; 
static const GLchar* fragment_shader_source = 
    "#version 120\n" 
    "uniform float pi2;\n" 
    "uniform float time;\n" 
    "uniform float width;\n" 
    "uniform float height;\n" 
    "uniform float periods_x;\n" 
    "uniform float periods_y;\n" 
    "void main(void) {\n" 
    " float center_x = width/2.0;" 
    " float center_y = height/2.0;" 
    " float x = (gl_FragCoord.x - center_x) * periods_x/width;" 
    " float y = (gl_FragCoord.y - center_y) * periods_y/height;" 
    " gl_FragColor[0] = 0.5 * (1.0 + (sin((pi2 * (sqrt(x*x + y*y) - time)))));\n" 
    " gl_FragColor[1] = 0.0;\n" 
    " gl_FragColor[2] = 0.0;\n" 
    "}\n"; 
static const GLfloat vertices[] = { 
    -1.0, 1.0, 
    1.0, 1.0, 
    1.0, -1.0, 
    -1.0, -1.0, 
}; 
static const GLuint indexes[] = { 
    0, 2, 1, 
    0, 3, 2, 
}; 

double common_get_secs(void) { 
    struct timespec ts; 
    timespec_get(&ts, TIME_UTC); 
    return ts.tv_sec + (1e-9 * ts.tv_nsec); 
} 
const double COMMON_FPS_GRANULARITY_S = 0.5; 
double common_fps_last_time_s; 
unsigned int common_fps_nframes; 
void common_fps_init() { 
    common_fps_nframes = 0; 
    common_fps_last_time_s = common_get_secs(); 
} 
void common_fps_update_and_print() { 
    double dt, current_time_s; 
    current_time_s = common_get_secs(); 
    common_fps_nframes++; 
    dt = current_time_s - common_fps_last_time_s; 
    if (dt > COMMON_FPS_GRANULARITY_S) { 
     printf("FPS = %f\n", common_fps_nframes/dt); 
     common_fps_last_time_s = current_time_s; 
     common_fps_nframes = 0; 
    } 
} 

/* Copy paste. Upstream on OpenGL. */ 
GLint common_get_shader_program(
     const char *vertex_shader_source, 
     const char *fragment_shader_source) { 
    GLchar *log = NULL; 
    GLint fragment_shader, log_length, program, success, vertex_shader; 

    /* Vertex shader */ 
    vertex_shader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); 
    glCompileShader(vertex_shader); 
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); 
    glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &log_length); 
    log = malloc(log_length); 
    if (log_length > 0) { 
     glGetShaderInfoLog(vertex_shader, log_length, NULL, log); 
     printf("vertex shader log:\n\n%s\n", log); 
    } 
    if (!success) { 
     printf("vertex shader compile error\n"); 
     exit(EXIT_FAILURE); 
    } 

    /* Fragment shader */ 
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); 
    glCompileShader(fragment_shader); 
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); 
    glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &log_length); 
    if (log_length > 0) { 
     log = realloc(log, log_length); 
     glGetShaderInfoLog(fragment_shader, log_length, NULL, log); 
     printf("fragment shader log:\n\n%s\n", log); 
    } 
    if (!success) { 
     printf("fragment shader compile error\n"); 
     exit(EXIT_FAILURE); 
    } 

    /* Link shaders */ 
    program = glCreateProgram(); 
    glAttachShader(program, vertex_shader); 
    glAttachShader(program, fragment_shader); 
    glLinkProgram(program); 
    glGetProgramiv(program, GL_LINK_STATUS, &success); 
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); 
    if (log_length > 0) { 
     log = realloc(log, log_length); 
     glGetProgramInfoLog(program, log_length, NULL, log); 
     printf("shader link log:\n\n%s\n", log); 
    } 
    if (!success) { 
     printf("shader link error"); 
     exit(EXIT_FAILURE); 
    } 

    free(log); 
    glDeleteShader(vertex_shader); 
    glDeleteShader(fragment_shader); 

    return program; 
} 

int main(void) { 
    /* SDL variables. */ 
    SDL_Event event; 
    SDL_Window *window; 
    SDL_GLContext gl_context; 
    const unsigned int WINDOW_WIDTH = 500, WINDOW_HEIGHT = WINDOW_WIDTH; 
    double dt, initial_time; 

    /* OpenGL variables. */ 
    GLint 
     attribute_coord2d, 
     ibo_size, 
     width_location, 
     height_location, 
     time_location, 
     periods_x_location, 
     periods_y_location, 
     pi2_location, 
     program 
    ; 
    GLuint ibo, vbo; 
    const char *attribute_name = "coord2d"; 
    const float 
     periods_x = 10.0, 
     periods_y = 10.0, 
     pi2 = 2.0 * acos(-1.0) 
    ; 

    /* SDL init. */ 
    SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO); 
    window = SDL_CreateWindow(__FILE__, 0, 0, 
      WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL); 
    gl_context = SDL_GL_CreateContext(window); 
    glewInit(); 

    /* OpenGL init. */ 
    { 
     program = common_get_shader_program(vertex_shader_source, fragment_shader_source); 
     attribute_coord2d = glGetAttribLocation(program, attribute_name); 
     if (attribute_coord2d == -1) { 
      fprintf(stderr, "error: attribute_coord2d: %s\n", attribute_name); 
      return EXIT_FAILURE; 
     } 
     height_location = glGetUniformLocation(program, "height"); 
     periods_x_location = glGetUniformLocation(program, "periods_x"); 
     periods_y_location = glGetUniformLocation(program, "periods_y"); 
     pi2_location = glGetUniformLocation(program, "pi2"); 
     time_location = glGetUniformLocation(program, "time"); 
     width_location = glGetUniformLocation(program, "width"); 

     glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
     glUseProgram(program); 
     glViewport(0, 0, WIDTH, HEIGHT); 

     glGenBuffers(1, &vbo); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 

     glGenBuffers(1, &ibo); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW); 
     glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &ibo_size); 

     glUniform1f(pi2_location, pi2); 
     glUniform1f(width_location, WIDTH); 
     glUniform1f(height_location, HEIGHT); 
     glUniform1f(periods_x_location, periods_x); 
     glUniform1f(periods_y_location, periods_y); 
    } 

    initial_time = common_get_secs(); 
    common_fps_init(); 
    while (1) { 
     dt = common_get_secs() - initial_time; 

     /* OpenGL draw. */ 
     glClear(GL_COLOR_BUFFER_BIT); 
     glEnableVertexAttribArray(attribute_coord2d); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo); 
     glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, 0); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 
     glUniform1f(time_location, dt); 
     glDrawElements(GL_TRIANGLES, ibo_size/sizeof(indexes[0]), GL_UNSIGNED_INT, 0); 
     glDisableVertexAttribArray(attribute_coord2d); 

     common_fps_update_and_print(); 
     SDL_GL_SwapWindow(window); 
     if (SDL_PollEvent(&event) && event.type == SDL_QUIT) 
      break; 
    } 

    /* OpenGL cleanup. */ 
    glDeleteBuffers(1, &ibo); 
    glDeleteBuffers(1, &vbo); 
    glDeleteProgram(program); 

    /* SDL cleanup. */ 
    SDL_GL_DeleteContext(gl_context); 
    SDL_DestroyWindow(window); 
    SDL_Quit(); 

    return EXIT_SUCCESS; 
} 

Sau đó:

gcc -Wall -std=c11 a.c -lSDL2 -lm -lGL -lGLEW 

GitHub upstreams:

Các vấn đề liên quan