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