2014-11-20 4 views
3

Есть ли способ реализовать технику Anitaliasing в OpenGL ES 2.0? Я изучил и нашел несколько методов, но никаких изменений в выходе не было.Сглаживание в OpenGL ES 2.0?

В худшем случае я планировал реализовать многопроходный рендеринг, чтобы сгладить края в шейдере фрагмента, отображая средний цвет пикселей вокруг каждого пикселя, но он стоит больше производительности графического процессора.

Любые предложения?

ответ

18

Множество устройств поддерживают MSAA (Multi-Sample Anti-Aliasing). Чтобы воспользоваться этой функцией, вам нужно выбрать EGLConfig, который имеет мультисэмплинг.

На Android, если вы используете GLSurfaceView, вам придется реализовать свои собственные EGLConfigChooser. Затем вы можете использовать функции EGL, в частности eglChooseConfig(), чтобы найти нужную конфигурацию.

Следующий код не проверен, но он должен хотя бы набросать, как это можно реализовать. В конструкторе GLSurfaceView производного класса, до вызывающего setRenderer(), добавьте:

setEGLConfigChooser(new MyConfigChooser()); 

Затем осуществить MyConfigChooser. Вы можете сделать это вложенный класс внутри вашего GLSurfaceView:

class MyConfigChooser implements GLSurfaceView.EGLConfigChooser { 
    @Override 
    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 
     int attribs[] = { 
      EGL10.EGL_LEVEL, 0, 
      EGL10.EGL_RENDERABLE_TYPE, 4, // EGL_OPENGL_ES2_BIT 
      EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER, 
      EGL10.EGL_RED_SIZE, 8, 
      EGL10.EGL_GREEN_SIZE, 8, 
      EGL10.EGL_BLUE_SIZE, 8, 
      EGL10.EGL_DEPTH_SIZE, 16, 
      EGL10.EGL_SAMPLE_BUFFERS, 1, 
      EGL10.EGL_SAMPLES, 4, // This is for 4x MSAA. 
      EGL10.EGL_NONE 
     }; 
     EGLConfig[] configs = new EGLConfig[1]; 
     int[] configCounts = new int[1]; 
     egl.eglChooseConfig(display, attribs, configs, 1, configCounts); 

     if (configCounts[0] == 0) { 
      // Failed! Error handling. 
      return null; 
     } else { 
      return configs[0]; 
     } 
    } 
} 

Вы, очевидно, хотите заменить конкретные значения, необходимые для конфигурации. На самом деле гораздо более надежным является вызов eglChooseConfig() с небольшим набором строго необходимых атрибутов, пусть он перечисляет все конфиги, соответствующие этим атрибутам, а затем реализует вашу собственную логику, чтобы выбрать лучший из них. Определенное поведение eglChooseConfig() уже нечетное (см. documentation), и не известно, как его реализуют производители графического процессора.

КСН, вы можете установить это свойство на вашем GLKView, чтобы включить 4x MSAA:

[view setDrawableMultisample: GLKViewDrawableMultisample4X]; 

Есть другое сглаживание подходы вы можете рассмотреть следующие вопросы:

  • Supersampling: Рендер в текстуру, которая является несколько (обычно в два раза) размера вашей конечной поверхности рендеринга в каждом направлении, а затем уменьшите ее. Это использует много памяти, и накладные расходы существенны. Но если он соответствует вашим требованиям к производительности, качество будет превосходным.
  • Старая школа: визуализируйте рамку несколько раз с небольшими смещениями и усредните кадры. Это обычно делалось с буфером накопления в первые дни OpenGL. Накопительный буфер устарел, но вы можете сделать то же самое с FBOs. Для описания метода см. Раздел «Сглаживание сцены» в разделе «Framebuffer» в оригинале Red Book.
+0

Этот метод работал очень хорошо. – kmcguire

1

На Android платформы, вы можете скачать этот OpenGL demo apps исходный код из GDC 2011: она содержит много лучших практик и показать вам, как сделать мультисамплинг, в том числе и сглаживанием покрытия.

Что вам нужно сделать, это просто настроить GLSurfaceView.EGLConfigChooser и установить этот Chooser:

// Set this chooser before calling setRenderer() 
setEGLConfigChooser(new MultisampleConfigChooser()); 
setRenderer(mRenderer); 

MultisampleConfigChooser.java пример кода ниже:

package com.example.gdc11; 

import javax.microedition.khronos.egl.EGL10; 
import javax.microedition.khronos.egl.EGLConfig; 
import javax.microedition.khronos.egl.EGLDisplay; 

import android.opengl.GLSurfaceView; 
import android.util.Log; 

// This class shows how to use multisampling. To use this, call 
// myGLSurfaceView.setEGLConfigChooser(new MultisampleConfigChooser()); 
// before calling setRenderer(). Multisampling will probably slow down 
// your app -- measure performance carefully and decide if the vastly 
// improved visual quality is worth the cost. 
public class MultisampleConfigChooser implements GLSurfaceView.EGLConfigChooser { 
    static private final String kTag = "GDC11"; 
    @Override 
    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 
     mValue = new int[1]; 

     // Try to find a normal multisample configuration first. 
     int[] configSpec = { 
       EGL10.EGL_RED_SIZE, 5, 
       EGL10.EGL_GREEN_SIZE, 6, 
       EGL10.EGL_BLUE_SIZE, 5, 
       EGL10.EGL_DEPTH_SIZE, 16, 
       // Requires that setEGLContextClientVersion(2) is called on the view. 
       EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */, 
       EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, 
       EGL10.EGL_SAMPLES, 2, 
       EGL10.EGL_NONE 
     }; 

     if (!egl.eglChooseConfig(display, configSpec, null, 0, 
       mValue)) { 
      throw new IllegalArgumentException("eglChooseConfig failed"); 
     } 
     int numConfigs = mValue[0]; 

     if (numConfigs <= 0) { 
      // No normal multisampling config was found. Try to create a 
      // converage multisampling configuration, for the nVidia Tegra2. 
      // See the EGL_NV_coverage_sample documentation. 

      final int EGL_COVERAGE_BUFFERS_NV = 0x30E0; 
      final int EGL_COVERAGE_SAMPLES_NV = 0x30E1; 

      configSpec = new int[]{ 
        EGL10.EGL_RED_SIZE, 5, 
        EGL10.EGL_GREEN_SIZE, 6, 
        EGL10.EGL_BLUE_SIZE, 5, 
        EGL10.EGL_DEPTH_SIZE, 16, 
        EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */, 
        EGL_COVERAGE_BUFFERS_NV, 1 /* true */, 
        EGL_COVERAGE_SAMPLES_NV, 2, // always 5 in practice on tegra 2 
        EGL10.EGL_NONE 
      }; 

      if (!egl.eglChooseConfig(display, configSpec, null, 0, 
        mValue)) { 
       throw new IllegalArgumentException("2nd eglChooseConfig failed"); 
      } 
      numConfigs = mValue[0]; 

      if (numConfigs <= 0) { 
       // Give up, try without multisampling. 
       configSpec = new int[]{ 
         EGL10.EGL_RED_SIZE, 5, 
         EGL10.EGL_GREEN_SIZE, 6, 
         EGL10.EGL_BLUE_SIZE, 5, 
         EGL10.EGL_DEPTH_SIZE, 16, 
         EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */, 
         EGL10.EGL_NONE 
       }; 

       if (!egl.eglChooseConfig(display, configSpec, null, 0, 
         mValue)) { 
        throw new IllegalArgumentException("3rd eglChooseConfig failed"); 
       } 
       numConfigs = mValue[0]; 

       if (numConfigs <= 0) { 
        throw new IllegalArgumentException("No configs match configSpec"); 
       } 
      } else { 
       mUsesCoverageAa = true; 
      } 
     } 

     // Get all matching configurations. 
     EGLConfig[] configs = new EGLConfig[numConfigs]; 
     if (!egl.eglChooseConfig(display, configSpec, configs, numConfigs, 
       mValue)) { 
      throw new IllegalArgumentException("data eglChooseConfig failed"); 
     } 

     // CAUTION! eglChooseConfigs returns configs with higher bit depth 
     // first: Even though we asked for rgb565 configurations, rgb888 
     // configurations are considered to be "better" and returned first. 
     // You need to explicitly filter the data returned by eglChooseConfig! 
     int index = -1; 
     for (int i = 0; i < configs.length; ++i) { 
      if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 5) { 
       index = i; 
       break; 
      } 
     } 
     if (index == -1) { 
      Log.w(kTag, "Did not find sane config, using first"); 
     } 
     EGLConfig config = configs.length > 0 ? configs[index] : null; 
     if (config == null) { 
      throw new IllegalArgumentException("No config chosen"); 
     } 
     return config; 
    } 

    private int findConfigAttrib(EGL10 egl, EGLDisplay display, 
      EGLConfig config, int attribute, int defaultValue) { 
     if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { 
      return mValue[0]; 
     } 
     return defaultValue; 
    } 

    public boolean usesCoverageAa() { 
     return mUsesCoverageAa; 
    } 

    private int[] mValue; 
    private boolean mUsesCoverageAa; 
} 

Перед использованием этой функции, вы должны знать об этом будет влиять на оказание эффективности , и, возможно, потребуется выполнить полный тест производительности.