介紹
rayrender 是一個R語言編寫的開源包,用于創(chuàng)建光線跟蹤場景螟深。這個包為用 C++ 構(gòu)建的光線追蹤器提供了一個整潔的 R API小槐,以渲染由一組基元構(gòu)建的場景污秆。 rayrender 使用可管道化的迭代界面構(gòu)建場景皂股,并支持漫反射墅茉、金屬、電介質(zhì)(玻璃)呜呐、發(fā)光材料就斤,以及程序和用戶指定的圖像紋理和 HDR 環(huán)境照明。 rayrender 包括通過 RcppThread 的多核支持(帶有進度條)蘑辑、通過 PCG RNG 的隨機數(shù)生成以及通過 TinyObrjLoader 的 .obj 文件支持战转。
官網(wǎng)鏈接
Build and Raytrace 3D Scenes ? rayrender
數(shù)據(jù)源
NASA社會數(shù)據(jù)應(yīng)用中心的世界格網(wǎng)人口數(shù)據(jù)V4版本,2010年30km級別數(shù)據(jù)
可視化過程
安裝R語言環(huán)境
安裝rayrender,rayshader,rgdal,magick等包
運行腳本
利用Python腳本拼接單獨生成的PNG格式的圖片為GIF格式的圖片
可視化腳本
library(rayshader)
library(rayrender)
popdata = raster::raster("gpw_v4_basic_demographic_characteristics_rev11_atotpopbt_2010_dens_15_min.tif")
population_mat = rayshader:::flipud(raster_to_matrix(popdata))
above1 = population_mat > 1
above5 = population_mat > 5
above10 = population_mat > 10
above50 = population_mat > 50
above100 = population_mat > 100
above500 = population_mat > 500
above1000 = population_mat > 1000
above1[is.na(above1)] = 0
above5[is.na(above5)] = 0
above10[is.na(above10)] = 0
above50[is.na(above50)] = 0
above100[is.na(above100)] = 0
above500[is.na(above500)] = 0
above1000[is.na(above1000)] = 0
turbocols = viridis::turbo(7)
wc = 0.4
chart_items =
xy_rect(x=-1,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color="grey30")) %>%
add_object(text3d(label = "0", x=-1,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=-0.6,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[1]))) %>%
add_object(text3d(label = "1>", x=-0.6,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=-0.2,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[2]))) %>%
add_object(text3d(label = "5>", x=-0.2,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=0.2,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[3]))) %>%
add_object(text3d(label = "10>", x=0.2,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=0.6,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[4]))) %>%
add_object(text3d(label = "50>", x=0.6,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=1.0,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[5]))) %>%
add_object(text3d(label = "100>", x=1.0,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=1.4,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[6]))) %>%
add_object(text3d(label = "500>", x=1.4,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(xy_rect(x=1.8,y=-1.4,z=1,xwidth=wc,ywidth=0.2,
material=diffuse(color=turbocols[7]))) %>%
add_object(text3d(label = "1000>", x=1.8,y=-1.4,z=1.01, text_height = 0.1,
material=diffuse(color="black"))) %>%
add_object(text3d(label = "People per 30km^2", x=-0.55,y=-1.2,z=1.01, text_height = 0.15,
material=diffuse(color="white"))) %>%
group_objects(group_translate = c(-0.4,0,0),group_scale=c(0.85,0.85,0.85))
radm = 1.2
for(i in 1:720) {
chart_items %>%
add_object(group_objects(
sphere(radius=0.99*radm,material=diffuse(color="grey20")) %>%
add_object(sphere(radius=1.0*radm,material= diffuse(color=turbocols[1],alpha_texture = above1))) %>%
add_object(sphere(radius=1.02*radm,material=diffuse(color=turbocols[2],alpha_texture = above5))) %>%
add_object(sphere(radius=1.03*radm,material=diffuse(color=turbocols[3],alpha_texture = above10))) %>%
add_object(sphere(radius=1.04*radm,material=diffuse(color=turbocols[4],alpha_texture = above50))) %>%
add_object(sphere(radius=1.05*radm,material=diffuse(color=turbocols[5],alpha_texture = above100))) %>%
add_object(sphere(radius=1.06*radm,material=diffuse(color=turbocols[6],alpha_texture = above500))) %>%
add_object(sphere(radius=1.07*radm,material=diffuse(color=turbocols[7],alpha_texture = above1000))),
group_angle = c(0,-i/2,0))) %>%
add_object(sphere(y=10,z=5,radius=3,material=light(intensity = 20))) %>%
add_object(sphere(y=0,z=20,radius=3,material=light(intensity = 20))) %>%
render_scene(width=1000,height=1000,samples=128,rotate_env = 180,clamp_value = 10,
aperture=0,
filename=sprintf("worldpopfocus%i.png",i), lookat=c(0,-0.2,0))
}
單幀生成的結(jié)果圖
worldpopfocus1.png
利用Python腳本拼接多張PNG圖像
import imageio
def create_gif(image_list, gif_name):
frames = []
for image_name in image_list:
frames.append(imageio.imread(image_name))
imageio.mimsave(gif_name, frames, 'GIF', duration=0.1)
return
def main():
image_list = ["rayrender\worldpopfocus" +
str(x)+".png" for x in range(1, 200)]
gif_name = 'rayrender\created_gif.gif'
create_gif(image_list, gif_name)
if __name__ == "__main__":
main()
動態(tài)可視化結(jié)果
部分地區(qū)人口密度動態(tài)圖.gif
總結(jié)
rayrender提供了非常方便簡潔的調(diào)用方式,即可實現(xiàn)很強的光線渲染效果以躯。在GIS領(lǐng)域,如何實現(xiàn)好的光線渲染效果是一個比較熱門的研究方向啄踊,而rayrender的渲染結(jié)果就非常出色忧设,可以用于數(shù)字地形渲染、動態(tài)制圖等方向颠通。