通过使用rdyncall软件包和SDL/OpenGL调用,在R中实现高效的2D SDL或OpenGL图形,以快速显示栅格图像。

42
在R中,似乎目前没有任何可用的选项(例如image)允许快速实时显示2D栅格图形。我对实时交互式曼德勃罗浏览器很感兴趣,希望能够以每秒大约5-10帧的速度显示1920x1080的原始十六进制颜色矩阵作为栅格图像(现在计算曼德勃罗图像本身在适度缩放下可以达到每秒20-30帧)。或者更好的是,我希望能够将强度像素映射传递给图形卡,并使用OpenGL加速进行颜色映射。使用image()选项useRaster=TRUEplot.raster甚至grid.raster()都无法满足要求,因为显示栅格图像需要大约1/4秒的时间(比实际计算帧的时间还长),所以我正在寻找更高效的选项,最好使用SDL或OpenGL加速。
我注意到可以使用rdyncall外部函数接口包从R中调用SDL、SDL_image和GL/OpenGL函数,这样应该能获得更好的性能。
尽管这个包在CRAN上已经归档,但是在这里有一个更新版本可用(我们正在努力将其重新放回CRAN)。
library(remotes)
remotes::install_github("hongyuanjia/rdyncall")
library(rdyncall)

首先,必须从https://libsdl.org/release/https://www.libsdl.org/projects/SDL_image/release/https://www.libsdl.org/projects/SDL_mixer/release/下载并安装(在Windows上)SDLSDL_imageSDL_mixer DLLs(版本1.2)。将64位DLL文件放置在`R-4.2.1/bin/x64`目录下或使用其他方法安装。
source("https://raw.githubusercontent.com/Jean-Romain/lidRviewer/master/sdl.R")

在Ubuntu上,它们可以通过以下方式进行安装。
sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2

一些演示如何进行SDL和OpenGL调用的示例可在https://dyncall.org/demos/soulsalicious/index.html(1980年代电脑游戏风格的星空场景,包含音乐)中找到。
我是否正确理解,使用这个软件包可以使用SDL和OpenGL加速来显示2D图像栅格?如果是这样,有人有任何关于如何做到这一点的想法吗(我问这个问题是因为我没有使用SDLOpenGL的经验)?
要打开一个1920 x 1080的SDL窗口,我认为我需要使用(从一些OpenGL示例和https://dyncall.org/demos/soulsalicious/soulsalicious.tar.gz中的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 

尝试使用quadmesh包将光栅图转换为高效的rgl格式。 - mdsumner
1
你可以将z设置为0。我并不是在建议这解决了你的问题!我也不知道答案,也很想找到一个。使用栅格或GDAL来提供特定于当前窗口的细节级别是最好的方法,但难以将这些部分串联起来。 - mdsumner
这是我尝试的第一件事,但仍然不是我能够付出足够思考去追寻的东西 :| - mdsumner
哈,谢谢你澄清了这个问题! - Tom Wenseleers
1
很抱歉,我一直希望能在这里得到一个答案,但是到目前为止还没有收到。 - Tom Wenseleers
显示剩余6条评论
4个回答

1

这不是基于SDL或OpenGL的解决方案(虽然这些解决方案应该更快),而是使用原生光栅格式,实现在https://github.com/coolbutuseless/nara中。显示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版本的吃豆人游戏, https://github.com/coolbutuseless/pacman和另一个世界的游戏, https://github.com/coolbutuseless/anotherworld

还有一个演示,我使用nara进行实时Mandelbrot分形缩放,参见函数zoom()https://github.com/tomwenseleers/mandelExplorer中。

请看视频这里

enter image description here


1
{nara}很不错,但我会尝试一个OpenGL解决方案。过去,我一直在为此目的移植GLFW。但我还没有达到那个水平。https://github.com/ramiromagno/glfw。 - Ramiro Magno

1
根据RGL包介绍,它是一个使用OpenGL作为渲染后端的可视化设备系统。rgl设备在其核心是一个用C++编写的实时3D引擎。它提供交互式视点导航功能(鼠标+滚轮支持)和R编程接口。
由于RGL是一个实时3D引擎,我期望使用RGL进行2D显示会更快。
请注意,这是一个旧项目,所以我不确定它是否符合您的要求。
您可以查看此论文并在此图库中查看一些结果图像。

我尝试了RGL库,但它只适用于3D OpenGL,而不是2D,而我在这里需要的是2D。所以我担心这不会起作用(我之前尝试过那个选项)。 - Tom Wenseleers
我认为rdyncall包可能是解决问题的方法,但我担心我需要一些帮助来使用它,因为我不是OpenGL专家... - Tom Wenseleers
你是否尝试在二维平面/网格上绘制三维数据,并将相机(位置和方向)固定在Z轴朝向XY平面? - A. STEFANI
1
是的,这就是我尝试过的,但我的数据不是三维的,所以这并不高效 - 在这里应该使用非常高效的OpenGL方法来处理纯二维图形... - Tom Wenseleers
这里有非常高效的OpenGL方法用于纯2D图形,应该在这里使用。不,实际上没有这种区分。绘图始终是2D的,因为帧缓冲区是2D的。3D变换的内容在着色器中,因此完全是可选的。渲染管道中有一些针对3D数据的部分 - 例如剪裁和可以争论的z测试,但它们的存在并不会使2D渲染效率降低。 - derhass
1
@derhass,至少在RGL包中使用的OpenGL的小子集不足以满足我想要做的事情,但是请随意证明我错了...另一方面,使用SDL和OpenGL直接使用rdyncall应该可以工作(查看上面链接的随机场演示),但我还没有弄清楚如何使其适用于我的特定问题... - Tom Wenseleers

0
五年过去了,我终于找到了这个问题的答案。
在R中,显示光栅图像的比image更快的选项是使用naranativeRaster格式加上grid.raster。然而,更快的方法是使用SDL+OpenGl解决方案,可以通过rdyncall外部函数接口调用-这种解决方案比使用nativeRaster结合grid.raster还要快大约10倍。理论上,这应该允许在640 x 480分辨率下以200+ fps的速度全屏或窗口显示。我正在使用OpenGL纹理映射方法-我还没有尝试过使用SDL_BlitSurface方法-这将产生不同的时间。而且,使用SDL或OpenGL进行强度到颜色映射也可能是可行的,尽管我无法立即弄清楚如何做到这一点(因为我现在是在之前进行这个操作,这仍然是一个很大的瓶颈)。如果有人知道如何在纯OpenGL中实现这一点(也许使用上面问题中提到的glPixelMapfv),请告诉我。
首先,我们安装所需的软件包并计算一个漂亮的曼德博集分形图像:
# 0. load required packages ####
library(remotes)
remotes::install_github("hongyuanjia/rdyncall")
library(rdyncall)
# install SDL libraries (SDL, SDL_image & SDL_mixer, version 1.2) 
# from https://libsdl.org/release/, 
# https://www.libsdl.org/projects/SDL_image/release/ and 
# https://www.libsdl.org/projects/SDL_mixer/release/)
# 64 bit DLLs are to be put under R-4.2.3/bin/x64
# you can use
# source("https://raw.githubusercontent.com/Jean-Romain/lidRviewer/master/sdl.R") 
# on Ubuntu install using sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2

remotes::install_github("coolbutuseless/nara")
library(nara)
remotes::install_github("tomwenseleers/mandelExplorer") # for nice example images
library(mandelExplorer)
library(microbenchmark)

# 1. create nice 640x480 image - here Mandelbrot fractal ####
xlims=c(-0.74877,-0.74872)
ylims=c(0.065053,0.065103)
x_res=640L
y_res=480L
nb_iter=as.double(nrofiterations(xlims))
m <- matrix(mandelRcpp2(as.double(xlims[[1]]), as.double(xlims[[2]]), # openmp+SIMD version
                        as.double(ylims[[1]]), as.double(ylims[[2]]), 
                        x_res, 
                        y_res, 
                        nb_iter), 
            nrow=as.integer(x_res))
m[m==0] <- nb_iter
m <- equalizeman(m, nb_iter, rng = c(0, 0.95), levels = 1E4)^(1/8) # equalize colours & apply gamma correction
dim(m) # x_res x y_res, grayscale matrix normalized between 0 and 1
range(m) # 0 1

A. 使用默认图像和dbcairo图形窗口显示光栅图像的时间:
# A. display raster using image - not terribly fast (not fast enough for real-time rendering at good framerate) ####
x11(type = 'dbcairo', antialias = 'none', width = 6*x_res/y_res, height = 6) # Setup a fast graphics device that can render quickly
par(mar=c(0, 0, 0, 0))
microbenchmark(image(m, col=palettes[[2]], asp=y_res/x_res, axes=FALSE, useRaster=TRUE), unit='s') 
# 0.08s, this includes colour mapping+raster display

B. 使用nara包和grid.raster的nativeRaster功能显示光栅图像的第二种解决方案的时间:比image快2.3倍。
# B. display raster user nara package, using nara::nativeRaster & grid.raster - 2.3x faster than image ####

microbenchmark({ col = palettes[[2]]
              idx = findInterval(m, seq(0, 1, length.out = length(col)))
              colors = col[idx] # matrix of hex colour values
              natrast = nara::raster_to_nr(matrix(t(colors), ncol = x_res,  # nativeRaster 
                                           nrow = y_res, byrow = TRUE))
              grid::grid.raster(natrast, interpolate = FALSE) }, unit='s') 
# 0.035s, 2.3x faster than image(), including the colour mapping + raster display

# timings just for colour mapping part & converting to nativeRaster
microbenchmark({ col = palettes[[2]]
idx = findInterval(m, seq(0, 1, length.out = length(col)))
colors = col[idx] # matrix of hex colour values
natrast = nara::raster_to_nr(matrix(t(colors), ncol = x_res,  # nativeRaster 
                                    nrow = y_res, byrow = TRUE)) }, unit='s')
# 0.027s for colour mapping part & converting to nativeRaster

# timings just for display of nativeRaster
microbenchmark({ grid::grid.raster(natrast, interpolate = FALSE); 
                 dev.flush() }, unit='s')
# 0.004s just for displaying nativeRaster

C. 使用第三种解决方案通过SDL和OpenGL使用rdyncall软件包显示光栅图像的时间:显示nativeRaster比grid.graphics快10倍。
# C. display nativeRaster or rgb array using SDL & OpenGL and rdyncall: to display nativeRaster 10x faster than grid.graphics ####

dynport(SDL)
dynport(GL)
dynport(GLU)

# initialize SDL and create a window
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
  stop("Failed to initialize SDL")
}

# set OpenGL attributes
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_ALPHA_SIZE, 8)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)

# set up screen: graphics window or run full screen
screen <- SDL_SetVideoMode(x_res, y_res, 0, SDL_OPENGL+SDL_DOUBLEBUF) # for windowed mode
# screen <- SDL_SetVideoMode(x_res, y_res, 0, SDL_OPENGL+SDL_DOUBLEBUF+SDL_FULLSCREEN) # for fullscreen mode

if(is.null(screen)) {
  stop("Failed to set video mode")
}

# initialize projection matrix
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, x_res, y_res, 0, -1, 1)

# initialize modelview matrix
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

# generate a texture
texId <- as.integer(0)
glGenTextures(1, texId)
glBindTexture(GL_TEXTURE_2D, texId)

# set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)

# convert colour vector to matrix
colorsMatrix <- matrix(colors,  
                       nrow = y_res,
                       ncol = x_res, 
                       byrow = TRUE)

# create image matrix (created as nativeRaster to make sure it is a contiguous block of memory)  
imageMatrix <- nara::raster_to_nr(colorsMatrix)

# timings just for nativeRaster display

microbenchmark({ 

# upload the image data to the texture
glTexImage2D(GL_TEXTURE_2D, 0, 4, 
             x_res, y_res, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageMatrix)

# clear the window
glClear(GL_COLOR_BUFFER_BIT)

# enable textures
glEnable(GL_TEXTURE_2D)

# draw a quad with the texture
glBegin(GL_QUADS)
glTexCoord2f(0, 1); glVertex2f(0, 0)
glTexCoord2f(1, 1); glVertex2f(x_res, 0)
glTexCoord2f(1, 0); glVertex2f(x_res, y_res)
glTexCoord2f(0, 0); glVertex2f(0, y_res)
glEnd()

# disable textures
glDisable(GL_TEXTURE_2D)

# swap buffers to display the result
SDL_GL_SwapBuffers() }, 
unit='s') 
# 0.0004s - 10x faster than displaying nativeRaster using grid.raster

# close window
SDL_Quit()

输出图片在这里展示这里


1
啊,对于版主带来的所有麻烦,真是抱歉! - undefined
@BenBolker 是的,一群令人讨厌且有毒的版主和用户,让这个网站变得难以忍受...看起来这个网站正在自掘坟墓。真是可惜... - undefined
我没有仔细看,但我认为他们是过于热衷并有点不考虑"无GenAI"规则,而不是"有害的"。(不过,我可以承认他们有点烦人。) - undefined
@BenBolker嗯,还有那个完全禁止AI的政策也让我很恼火,所有这些版主似乎都把时间花在寻找可能部分由GPT编写的帖子上...而不是更有成效地花时间删除那些质量低劣的帖子(就像这里的另一个回答一样,最多只能算是个评论,而且还不起作用)。在这里,很明显我彻底检查了代码,因为我提供了基准测试,而GPT则没有...更有讽刺的是,这发生在回答我自己高评分问题的回答上... - undefined

-1
五年过去了,我终于找到了这个问题的答案。
在R中,显示光栅图像的比image更快的选项是使用naranativeRaster格式加上grid.raster。然而,更快的方法是使用SDL+OpenGl解决方案,可以通过rdyncall外部函数接口调用-这种解决方案比使用nativeRaster结合grid.raster还要快大约10倍。理论上,这应该允许以640 x 480分辨率全屏或窗口模式下达到200+帧每秒的速度。我正在使用OpenGL纹理映射方法-我还没有尝试过使用SDL_BlitSurface方法-这将产生不同的时间。使用SDL或OpenGL进行强度到颜色映射也可能是可行的,尽管我无法立即找出如何做到这一点(因为我现在是事先完成这个步骤,这仍然是一个很大的瓶颈)。如果有人知道如何在纯OpenGL中实现这一点(也许使用上面问题中提到的glPixelMapfv),请告诉我。
首先,我们安装所需的软件包并计算一个漂亮的曼德博集分形图像:
# 0. load required packages ####
library(remotes)
remotes::install_github("hongyuanjia/rdyncall")
library(rdyncall)
# install SDL libraries (SDL, SDL_image & SDL_mixer, version 1.2) 
# from https://libsdl.org/release/, 
# https://www.libsdl.org/projects/SDL_image/release/ and 
# https://www.libsdl.org/projects/SDL_mixer/release/)
# 64 bit DLLs are to be put under R-4.2.3/bin/x64
# you can use
# source("https://raw.githubusercontent.com/Jean-Romain/lidRviewer/master/sdl.R") 
# on Ubuntu install using sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2

remotes::install_github("coolbutuseless/nara")
library(nara)
remotes::install_github("tomwenseleers/mandelExplorer") # for nice example images
library(mandelExplorer)
library(microbenchmark)

# 1. create nice 640x480 image - here Mandelbrot fractal ####
xlims=c(-0.74877,-0.74872)
ylims=c(0.065053,0.065103)
x_res=640L
y_res=480L
nb_iter=as.double(nrofiterations(xlims))
m <- matrix(mandelRcpp2(as.double(xlims[[1]]), as.double(xlims[[2]]), # openmp+SIMD version
                        as.double(ylims[[1]]), as.double(ylims[[2]]), 
                        x_res, 
                        y_res, 
                        nb_iter), 
            nrow=as.integer(x_res))
m[m==0] <- nb_iter
m <- equalizeman(m, nb_iter, rng = c(0, 0.95), levels = 1E4)^(1/8) # equalize colours & apply gamma correction
dim(m) # x_res x y_res, grayscale matrix normalized between 0 and 1
range(m) # 0 1

A. 使用默认图像和dbcairo图形窗口显示栅格图像的时间:
# A. display raster using image - not terribly fast (not fast enough for real-time rendering at good framerate) ####
x11(type = 'dbcairo', antialias = 'none', width = 6*x_res/y_res, height = 6) # Setup a fast graphics device that can render quickly
par(mar=c(0, 0, 0, 0))
microbenchmark(image(m, col=palettes[[2]], asp=y_res/x_res, axes=FALSE, useRaster=TRUE), unit='s') 
# 0.08s, this includes colour mapping+raster display

B.使用nara包和grid.raster的nativeRaster功能显示光栅图像的第二种解决方案时间:比image快2.3倍

# B. display raster user nara package, using nara::nativeRaster & grid.raster - 2.3x faster than image ####

microbenchmark({ col = palettes[[2]]
              idx = findInterval(m, seq(0, 1, length.out = length(col)))
              colors = col[idx] # matrix of hex colour values
              natrast = nara::raster_to_nr(matrix(t(colors), ncol = x_res,  # nativeRaster 
                                           nrow = y_res, byrow = TRUE))
              grid::grid.raster(natrast, interpolate = FALSE) }, unit='s') 
# 0.035s, 2.3x faster than image(), including the colour mapping + raster display

# timings just for colour mapping part & converting to nativeRaster
microbenchmark({ col = palettes[[2]]
idx = findInterval(m, seq(0, 1, length.out = length(col)))
colors = col[idx] # matrix of hex colour values
natrast = nara::raster_to_nr(matrix(t(colors), ncol = x_res,  # nativeRaster 
                                    nrow = y_res, byrow = TRUE)) }, unit='s')
# 0.027s for colour mapping part & converting to nativeRaster

# timings just for display of nativeRaster
microbenchmark({ grid::grid.raster(natrast, interpolate = FALSE); 
                 dev.flush() }, unit='s')
# 0.004s just for displaying nativeRaster

使用第三种解决方案通过SDL和OpenGL使用rdyncall软件包显示栅格图像的时间:

以比grid.graphics快10倍的速度显示nativeRaster
# C. display nativeRaster or rgb array using SDL & OpenGL and rdyncall: to display nativeRaster 10x faster than grid.graphics ####

dynport(SDL)
dynport(GL)
dynport(GLU)

# initialize SDL and create a window
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
  stop("Failed to initialize SDL")
}

# set OpenGL attributes
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_ALPHA_SIZE, 8)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)

# set up screen: graphics window or run full screen
screen <- SDL_SetVideoMode(x_res, y_res, 0, SDL_OPENGL+SDL_DOUBLEBUF) # for windowed mode
# screen <- SDL_SetVideoMode(x_res, y_res, 0, SDL_OPENGL+SDL_DOUBLEBUF+SDL_FULLSCREEN) # for fullscreen mode

if(is.null(screen)) {
  stop("Failed to set video mode")
}

# initialize projection matrix
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, x_res, y_res, 0, -1, 1)

# initialize modelview matrix
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

# generate a texture
texId <- as.integer(0)
glGenTextures(1, texId)
glBindTexture(GL_TEXTURE_2D, texId)

# set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)

# convert colour vector to matrix
colorsMatrix <- matrix(colors,  
                       nrow = y_res,
                       ncol = x_res, 
                       byrow = TRUE)

# create image matrix (created as nativeRaster to make sure it is a contiguous block of memory)  
imageMatrix <- nara::raster_to_nr(colorsMatrix)

# timings just for nativeRaster display

microbenchmark({ 

# upload the image data to the texture
glTexImage2D(GL_TEXTURE_2D, 0, 4, 
             x_res, y_res, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageMatrix)

# clear the window
glClear(GL_COLOR_BUFFER_BIT)

# enable textures
glEnable(GL_TEXTURE_2D)

# draw a quad with the texture
glBegin(GL_QUADS)
glTexCoord2f(0, 1); glVertex2f(0, 0)
glTexCoord2f(1, 1); glVertex2f(x_res, 0)
glTexCoord2f(1, 0); glVertex2f(x_res, y_res)
glTexCoord2f(0, 0); glVertex2f(0, y_res)
glEnd()

# disable textures
glDisable(GL_TEXTURE_2D)

# swap buffers to display the result
SDL_GL_SwapBuffers() }, 
unit='s') 
# 0.0004s - 10x faster than grid.raster

# close window
SDL_Quit()

输出图像在这里显示此处

(充分披露:原始的OpenGL+SDL+rdyncall代码基于ChatGPT4输出;基准测试和答案的其余部分是手动添加的;但为了防止此答案被管理员删除,代码已经手动修改)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接