跳转至

OpenGL 着色器示例

原文链接:https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/opengl-shader-example

17872 为本文评分:

1.5

OpenGL 着色器示例

匿名 2015年12月17日,星期四

自 IDL 6.4 版本起,就开始支持 OpenGL 着色器编程。IDLgrShader 功能可用于编程实现多种显示处理函数,这些函数运行在图形处理器而非 CPU 上,从而释放 CPU 以处理其他任务。一个巨大的优势是,图形处理器能够并行运行大量线程,这对于处理像素可以独立对待的图像数据来说非常理想。我将在此展示一个示例,演示如何执行一种计算,其中每个输出像素都依赖于输入图像中一个 5x5 的像素邻域,这与更简单的、每个像素的处理不受相邻像素影响的示例不同。这利用了所谓的"采样器"——着色器语言中的一种内置类型,允许在图像中进行快速插值(最近邻、线性)。

此示例未包含一些注意事项。首先是,如果图像大于最大纹理尺寸(可以查询得到),那么图像会在内部进行分块处理。为了使类似本例的示例正常工作,此时需要使用 TILE_BORDER_SIZE 关键字。另一个针对大图像的注意事项是,需要编写代码来处理分辨率级别和分块请求。

请注意,此示例需要物理显卡才能运行着色器代码,虚拟环境通常无法访问显卡。在 IDL 代码中,您可以查询运行时可用的着色器语言(GLSL)版本,并编写代码以适应不同的可能性。

此示例以一种能够非常有效地填补缺失数据(设为零)的方式使用卷积核。空洞填充是在显示时即时完成的,因此像素数据仍然反映数据缺失处的零值。有方法可以读取着色器代码的输出,但此示例未包含该部分。

左侧图像是具有零值表示缺失数据的原始输入像素。右侧图像是经过 5x5 滤波器处理的同一图像数据的显示效果。

以下列出了生成这些图像的完整源代码。

pro shader_tricks

compile_opt idl2, logical_predicate

im = read_image(filepath('elev_t.jpg', subdir=['examples','data']), /order)

im = total(float(im),1)

if min(im) eq 0 then im++

help, im

; 模拟随机缺失数据,一半像素缺失 im[floor(randomu(1, n_elements(im)/2)*n_elements(im))] = 0

dim = size(im, /dimension)

w = where(im ne 0, n)

ord = sort(im[w])

p0 = im[w[ord[n/50]]]

p1 = im[w[ord[-n/50]]]

print, p0, p1

tlb = widget_base(title='着色器示例', /row)

w1 = widget_draw(tlb, xsize=dim[0], ysize=dim[1], retain=2)

w2 = widget_draw(tlb, xsize=dim[0], ysize=dim[1], $

graphics_level=2, retain=0, renderer=0)

widget_control, tlb, /realize

widget_control, w1, get_value=winid

wset, winid

tv, bytscl(im, min=p0, max=p1)

widget_control, w2, get_value=win

vertexProgram = $ [ 'void main (void) {', $ '  gl_TexCoord[0] = gl_MultiTexCoord0;', $ '  gl_Position = ftransform();', $ '  gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;', $ '}' ]

fragProgram = $ ['uniform sampler2D _IDL_ImageTexture;' $ ,'uniform float min;' $ ,'uniform float max;' $ ,'uniform float kernel[25];' $ ,'uniform vec2 _IDL_ImageStep;' $ ,'void main(void)' $ ,'{' $ ,'vec2 adj = vec2(2*_IDL_ImageStep.x,2*_IDL_ImageStep.y);' $ ,'vec2 tc = gl_TexCoord[0].st - adj;' $ ,'float sum = 0.0;' $ ,'float nsum = 0.0;' $ ,'for (int i=0; i<4; i++) {' $ , 'adj.y = i * _IDL_ImageStep.y;' $ ,' for (int j=0; j<4; j++) {' $ ,'   adj.x = j * _IDL_ImageStep.x;' $ ,'   float p = texture2D(_IDL_ImageTexture, tc + adj).r;' $ ,'   float k = kernel[j+i*5];' $ ,'   sum += p*k;' $ ,'   nsum += (p != 0)*k;' $ ,'  }' $ ,'}' $ ,'nsum += (nsum == 0);' $ ,'sum = (sum/nsum - min) / (max - min);' $ ,'gl_FragColor = vec4(sum,sum,sum,1.0);' $ ,'}' $ ]

g = gaussian_function([0.5,0.5],width=5,maximum=1)

shader = IDLgrShader()

shader->SetProperty, $ fragment_program_string=strjoin(fragProgram, string(10b)), $ vertex_program_string=strjoin(vertexProgram, string(10b))

shader->SetUniformVariable, 'min', float(p0)

shader->SetUniformVariable, 'max', float(p1)

shader->SetUniformVariable, 'kernel', float(g)

view = IDLgrView(viewplane_rect=[0,0,dim])

model = IDLgrModel()

img = IDLgrImage(float(im), internal_data_type=3, shader=shader)

view->Add, model

model->Add, img

win->Draw, view

xmanager, 'shader_tricks', tlb, /no_block

end

采用可扩展系统的精准农业 光的波动性