使用rdyncall软件包和SDL/OpenGL调用,在R中实现高性能的2D SDL或OpenGL图形,以快速显示光栅图像

hmae6n7t  于 2023-01-08  发布在  其他
关注(0)|答案(2)|浏览(159)

对于一个实时交互式Mandelbrot查看器,我在R中制作,我正在寻找一种高性能的方式来显示1920 x1080原始十六进制颜色矩阵作为光栅图像,希望能够达到约5-10 fps(calculating the Mandelbrot images themselves now achieves ca. 20-30 fps at moderate zooms,当然滚动应该很快)(当然,在R中可以有许多访问 swift2 D图形的应用)。使用带有选项useRaster=TRUEimage()plot.raster甚至grid.raster()都不能解决这个问题,因为显示光栅图像比实际计算要慢得多(最好的情况下大约是1/4秒),所以我在寻找一个性能更好的选项,最好是使用SDL或OpenGL加速。
我注意到应该可以使用rdyncall包从R调用SDL、SDL_image和GL/OpenGL函数,这应该有更好的性能。
虽然这个软件包被归档在CRAN上,但是它仍然是完全可用的。请参阅文章here和Mercurial存储库here
要安装存档版本:

library(devtools)
install_version("rdyncall",
                version="0.7.5",
                repos="http://cran.us.r-project.org")

SDLSDL_imageSDL_mixer DLL(版本1.2)(在Windows上)必须首先从https://libsdl.org/release/https://www.libsdl.org/projects/SDL_image/release/https://www.libsdl.org/projects/SDL_mixer/release/安装)(the 64 bit DLLs are to be put under R-4.2.1/bin/x64“)。在Ubuntu上,可以使用

sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2

一些如何调用SDL和OpenGL的演示可以在https://dyncall.org/demos/soulsalicious/index.html(20世纪80年代计算机游戏风格的starfield,包括音乐)上获得。
我说的这个软件包应该可以使用SDLopengl加速来显示2D图像光栅,对吗?如果是这样,有没有人想过如何做到这一点(我问是因为我没有使用SDLOpenGL的经验)?
要打开一个1920 x 1080 SDL窗口,我想我必须使用(从https://dyncall.org/demos/soulsalicious/soulsalicious.tar.gz中的一些OpenGL示例和windowed.R脚本收集,全屏也是可能的,请参见fullscreen.R

init <- function()
{
  require(rdyncall)
  dynport(SDL)
  SDL_Init(SDL_INIT_VIDEO)
  dynport(GL)
  dynport(GLU)
  dynport(SDL_image)
  
  SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8)
  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8)
  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8)
  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1)
  x_res <- 1920
  y_res <- 1080
  win <- SDL_SetVideoMode(x_res, y_res, 32, 
                          SDL_HWSURFACE + SDL_OPENGL + SDL_DOUBLEBUF)
  SDL_WM_SetCaption("SDL surface",NULL)
  glEnable(GL_TEXTURE_2D)
  # Set the projection matrix for the image
  glMatrixMode(GL_PROJECTION)
  glLoadIdentity()
  x_min=1
  x_max=x_res
  y_min=1
  y_max=y_res
  glOrtho(x_min, x_max, y_min, y_max, -1, 1)
  # Set the modelview matrix for the image
  glMatrixMode(GL_MODELVIEW)
  glLoadIdentity()
}
init()

我收集我应该然后设置一些像素转移图使用的东西,

glPixelMapfv(GL_PIXEL_MAP_I_TO_R, nb_colors, map_colors)
glPixelMapfv(GL_PIXEL_MAP_I_TO_G, nb_colors, map_colors)
glPixelMapfv(GL_PIXEL_MAP_I_TO_B, nb_colors, map_colors)

然后使用另一个pixels <- glPixelMapfv调用为像素数据创建一个缓冲区,使用glDrawPixels将像素数据绘制到屏幕上,使用SDL_GL_SwapBuffers(win)交换前后缓冲区以显示图像,然后等待用户关闭窗口,然后使用SDL_Quit()等进行清理。问题是我没有OpenGL或SDL经验,那么有谁知道如何执行最后几个步骤吗?(我在这里使用的是SDL 1. 2版)
非OpenGL选项的一些计时对我的应用程序来说太慢:

# some example data & desired colour mapping of [0-1] ranged data matrix
library(RColorBrewer)
ncol=1080
cols=colorRampPalette(RColorBrewer::brewer.pal(11, "RdYlBu"))(ncol)
colfun=colorRamp(RColorBrewer::brewer.pal(11, "RdYlBu"))
col = rgb(colfun(seq(0,1, length.out = ncol)), max = 255)
mat=matrix(seq(1:1080)/1080,nrow=1920,ncol=1080,byrow=TRUE)
mat2rast = function(mat, col) {
  idx = findInterval(mat, seq(0, 1, length.out = length(col)))
  colors = col[idx]
  rastmat = t(matrix(colors, ncol = ncol(mat), nrow = nrow(mat), byrow = TRUE))
  class(rastmat) = "raster"
  return(rastmat)
}
system.time(mat2rast(mat, col)) # 0.24s

# plot.raster method - one of the best?
par(mar=c(0, 0, 0, 0))
system.time(plot(mat2rast(mat, col), asp=NA)) # 0.26s

# grid graphics - tie with plot.raster?
library(grid)
system.time(grid.raster(mat2rast(mat, col),interpolate=FALSE)) # 0.28s

# base R image()
par(mar=c(0, 0, 0, 0))
system.time(image(mat,axes=FALSE,useRaster=TRUE,col=cols)) # 0.74s # note Y is flipped to compared to 2 options above - but not so important as I can fill matrix the way I want

# ggplot2 - just for the record...
df=expand.grid(y=1:1080,x=1:1920)
df$z=seq(1,1080)/1080
library(ggplot2)
system.time({q <- qplot(data=df,x=x,y=y,fill=z,geom="raster") + 
                scale_x_continuous(expand = c(0,0)) + 
                scale_y_continuous(expand = c(0,0)) +
                scale_fill_gradientn(colours = cols) + 
                theme_void() + theme(legend.position="none"); print(q)}) # 11s
t1rydlwq

t1rydlwq1#

根据RGL package introduction,它是:
R的可视化设备系统,使用OpenGL作为渲染后端。其核心的rgl设备是用C++编写的实时3D引擎。它提供了交互式视点导航工具(鼠标+滚轮支持)和R编程接口。
由于RGL是一个真实的的3D引擎,我希望使用RGL的2D将给予你一个快速的显示。

  • 请注意,这是一个老项目,所以我不确定它是否符合您的要求。*

您可以查看一下this paper并看到一些结果图像in this gallery

au9on6nz

au9on6nz2#

不是基于SDL或OpenGL的解决方案(应该更快),但在https://github.com/coolbutuseless/nara中实现的nativeRaster格式显示640x480图像光栅的速度似乎比grid.raster()快10倍。
要显示栅格,只需调用

library(remotes)
remotes::install_github("coolbutuseless/nara")
library(nara)

# Setup a fast graphics device that can render quickly
x11(type = 'dbcairo', antialias = 'none', width = 8, height = 6)
grid.raster(nara::raster_to_nr(ras), interpolate = FALSE)

其中ras是规则栅格光栅。
有几个很好的演示,包括一个R版本的pacman,https://github.com/coolbutuseless/pacman和游戏Anotherworld,https://github.com/coolbutuseless/anotherworld
还有一个演示,我使用nara来做实时Mandelbrot分形缩放,参见https://github.com/tomwenseleers/mandelExplorer中的zoom()函数。
参见视频here

相关问题