OpenGL奇怪的线性过滤

时间:2017-11-22 11:28:28

标签: opengl textures filtering

我编写了以下着色器来测试线性过滤在OpenGL中的工作原理。

enter image description here

这里我们有一个5x1纹理喷溅到立方体的一个面上(megenta区域只是背景的颜色)。

纹理是这个(它非常小)。

enter image description here

botton-left 一角对应<?php class newelement extends WPBakeryShortCode { # Construct ---------------- function __construct() { add_action( 'init', [ $this, 'elementMapping' ] ); add_shortcode( 'element_Shortcode', [ $this, 'elementShortcode' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'elementCss' ]); } # Fields ------------------- public function elementMapping() { if ( !defined( 'WPB_VC_VERSION' ) ) { return; } vc_map( [ "base" => "elementShortcode", "params" => [ [ "type" => "colorpicker", "param_name" => "elementcolor" ], ], ] ); } # Output Code --------------------------------- public function elementShortcode () { $atts = shortcode_atts([ "elementcolor" => "", ], $atts); extract($atts); ob_start(); ?> <?php $output = ob_get_contents(); ob_end_clean(); return $output; } # css --------------------------------- public function elementCss() { // this value $elementcolor = $atts["elementcolor"]; $css = " .element{ color: {$elementcolor} ;} "; wp_add_inline_style( 'main', $css); } } new newelement(); 右上角对应uv=(0, 0)。 启用线性过滤。

着色器将uv=(1, 1)坐标垂直分成5行(从上到下):

  1. 连续采样。只是正常采样。
  2. 绿色,如果你在[0,1],否则为红色。仅用于测试目的。
  3. u坐标为灰度。
  4. 在纹理元素的左侧进行采样。
  5. 在画中心的中心采样。
  6. 问题是在v3之间有一行像素闪烁。通过改变相机距离来改变闪烁,有时你甚至可以让它消失。问题似乎在处理第四行的着色器代码中。

    4

    这对我来说很奇怪,因为在该区域中// sample at the left of the pixel // the following line can fix the problem if I add any number different from 0 tc.y += 0.000000; // replace by any number other than 0 and works fine tc.x = floor(5 * tc.x) * 0.2; c = texture(tex0, tc); 坐标不在纹理的任何边缘附近。

1 个答案:

答案 0 :(得分:4)

在纹理提取过程中,您的代码依赖于未定义值

第8.9节纹理函数中的here状态(强调我的):

  

某些纹理函数(非“Lod”和非“Grad”版本)可能需要   隐含衍生物。 内隐衍生物未定义   非均匀控制流和非片段着色器纹理提取。

虽然大多数人认为这些衍生物只是mip-mapping所必需的,但这是不正确的。还需要LOD因子来确定纹理是放大还是缩小(以及非mipmapped情况下的各向异性过滤,但这里不感兴趣)。

GPU通常通过2x2像素四边形中的相邻像素之间的有限差分来近似导数。 发生的事情是,在各种选项之间的边缘处,您有非均匀的控制流,其中对于一行您进行纹理过滤,而在上面的行中,您没有这样做。有限差分将导致尝试访问上行中纹理采样操作的纹理坐标,这些操作根本无法保证计算,因为该着色器调用没有主动执行该代码路径 - 这就是为什么spec将它们视为未定义。

现在取决于您的边缘位于2x2像素四边形中的哪个位置,您可以得到正确的结果,或者您没有。对于没有得到正确结果的情况,一个可能的结果可能是GL在您的示例中使用了GL_NEAREST的缩小过滤器。

将两个过滤器设置为GL_LINEAR可能会有所帮助。但是,这仍然不是正确的代码,因为根据规范,结果仍未定义。

唯一正确的解决方案是将纹理采样移出非均匀控制流程,如

vec4 c1=texture(tex, tc); // sample directly at tc
vec4 c2=texture(tex, some_function_of(tc)); // sample somewhere else
vec4 c3=texture(tex, ...);

// select output color in some non-uniform way
if (foo) {
   c=c1;
} else if (bar) {
   c=c2;
} else {
   c=c3;
}