2016-12-31 47 views
0

我有一個使用自定義着色器顯示圓圈的OpengGL ES應用程序。見下圖。 (在新窗口中打開它可能會有所幫助)大部分iPad OpenGL ES應用程序不是視網膜

如果仔細觀察,可以看到顯示器從寬度的約50%和高度的約75%看起來似乎爲非視網膜。這似乎是only on iPad 3(客戶端設備)的情況。 Simulator和其他iPad Air 2行爲正常。

我使用了與XCode捆綁在一起的基本OpenGL ES遊戲項目。

problematic[1]

更新: 像素化的領域是那些以紅色突出顯示:

enter image description here

另請參閱特寫鏡頭:

enter image description here

我必須承認我做的不知道從哪裏開始調試, ,因爲它似乎只在給定設備上的錯誤。

這是我用來設置上下文的代碼。

func setup() 
{ 
    initTextures() 

    self.context = EAGLContext(api: .openGLES2) 

    if !(self.context != nil) { 
     print("Failed to create ES context") 
    } 

    let view = self.view as! GLKView 


    // Fix for "good" aspect ratio 
    var frameSize = view.frame.size 
    frameSize.height = frameSize.width/1.43023255813953 
    view.frame.size = frameSize 

    // Should force the aspect ratio 
    print("-------------") 
    print("width \(view.frame.width) and height \(view.frame.height)") 
    print("aspect ratio w/h \(view.frame.width/view.frame.height)") 
    print("-------------") 

    view.context = self.context! 
    view.drawableColorFormat = .RGBA8888 
    view.drawableMultisample = .multisample4X 

    // Application specific code 

    self.setupGL() 
} 

更新

我畫的圓圈用自定義fragment shader

precision highp float; 

uniform vec4 iResolution; // z - texWidth, w - texHeight 

uniform sampler2D textureUnit; 
uniform sampler2D smallPointsTextureUnit; 

uniform vec2 gridSize; 

#define SMOOTH(r,R) (1.0-smoothstep(R-0.09,R+0.09, r)) 

#define black vec3(0.0) 
#define white vec3(1.0) 

float circle(vec2 st, in float _radius, float pct){ 
    float l = length(st - vec2(0.5)); 
    return 1.-smoothstep(_radius-(_radius*0.005) * pct, 
         _radius+(_radius*0.005), 
         l); 
} 

float stroke(vec2 uv, vec2 center, float radius, float width) 
{ 
    float dist = length(uv-center); 
    float t = 1.0 + smoothstep(radius, radius+width, dist) 
    - smoothstep(radius-width, radius, dist); 
    return t; 
} 

void main() 
{ 
    vec2 resolution = vec2(iResolution.x, iResolution.y); 

    vec2 uv = gl_FragCoord.xy; 

    vec2 st = gl_FragCoord.xy/resolution; 

    float colWidth = iResolution.x/gridSize.x; 
    float rowHeight = (iResolution.y + 1.0)/gridSize.y; 

    float smallerSize = min(rowHeight, colWidth); 
    float largerSize = max(rowHeight, colWidth); 

    vec2 divider = resolution/smallerSize; 

    st.x *= divider.x; 
    st.y *= divider.y; 

    float pct = largerSize/smallerSize; 

    float texXPos = (floor(st.x * smallerSize/largerSize) + 0.5)/iResolution.z; 
    float texYPos = (floor(gridSize.y -st.y) + 0.5)/iResolution.w; 

    vec4 tex = texture2D(textureUnit, vec2(
       texXPos, 
       texYPos)); 

    vec4 texSmallPoints = texture2D(smallPointsTextureUnit, vec2((floor(st.x * 2.0 * smallerSize/largerSize) + 0.5)/128.0, 
                   (floor(gridSize.y * 2.0 -st.y * 2.0) + 0.5)/128.0)); 
    //texSmallPoints.r = 0.5; 
    vec3 fillColor = vec3(tex.x, tex.y, tex.z); 


    st.x = mod(st.x, pct); 

    st.x = step(fract(st.x * 1.0/pct), 1.0/pct) * fract(st.x); 
    st.x *= texSmallPoints.r * 2.0; // subdivide for small circles 
    st.x = fract(st.x); 

    // Divide by 4 
    st.y *= texSmallPoints.r * 2.0; 
    st.y = fract(st.y); 

    //float r = 0.425; 
    float r = 0.4; 
    float fillPct = circle(st, r, 1.0); 

    vec2 center = vec2(0.5); 
    float strokePct = stroke(st, center, r, 0.032 * texSmallPoints.r * 1.8); 

    vec3 finalColor = vec3(1.0); 
    vec3 strokeColor = fillColor; 

    // todo -refactor if slow 
    // todo - invert 

    if (tex.a > 0.99) { 
     strokeColor = black; 
    } 

    if (tex.a < 0.01) { 
     strokeColor = white; 
    } 

    finalColor = mix(white, fillColor, fillPct); 
    finalColor = mix(finalColor, strokeColor, 1. - strokePct); 

    gl_FragColor = vec4(finalColor, 1.0); 
} 

而且GLKViewController

// 
// HomeOpenGLController.swift 
// Kobi 
// 
// Created by Tibor Udvari on 14/06/16. 
// Copyright © 2016 Tibor Udvari. All rights reserved. 
// 

import GLKit 
import OpenGLES 
import HEXColor 

open class KobiOpenGLControllerBase: GLKViewController 
{ 
    // --- Small points texture --- 
    var gpuSmallColorsTexture = [GLubyte](repeating: 0, count: 0) 

    var currentSmallPointTextureData: [GLubyte]? = nil 

    // - allocated size 
    let smallPointsTextureWidth = 128 
    let smallPointsTextureHeight = 128 

    // --- Color texture --- 

    var gpuColorsTexture = [GLubyte](repeating: 0, count: 0) 

    var currentColorsTextureData: [GLubyte]? = nil // size of grid 

    // - allocated size 
    let texWidth: Int = 256 
    let texHeight: Int = 256 

    // Grid - circles 
    let cols = 31 
    let rows = 22 

    open let maxIdx: Int 
    open let circleCount: Int 

    // Grid - pixels 
    var width: CGFloat = 0.0 
    var height: CGFloat = 0.0 

    var circleWidth: CGFloat = 0.0 
    var circleHeight: CGFloat = 0.0 

    // OpenGL 
    var program: GLuint = 0 
    var circleProgram: GLuint = 0 

    var context: EAGLContext? = nil 

    required public init?(coder aDecoder: NSCoder) { 
     maxIdx = cols * rows 
     circleCount = cols * rows 
     super.init(coder: aDecoder) 
    } 

    // 0 is positive instead of 0 
    func sign(_ x: Int) -> Int { 
     let r = x < 0 ? -1 : 1 
     return r 
    } 

    // MARK: - Setup 

    override open func viewDidLoad() { 
     setupGridData() 
    } 

    override open func viewDidAppear(_ animated: Bool) { 
     super.viewDidAppear(animated) 
     setup() // because width and height is not initiated yet 
    } 

    func setupGridData(){ 

     //currentSmallPointTextureData = createCurrentSmallPointsTextureData() 
    } 


    func setup() 
    { 
     initTextures() 

     self.context = EAGLContext(api: .openGLES2) 

     if !(self.context != nil) { 
      print("Failed to create ES context") 
     } 

     let view = self.view as! GLKView 


     // Fix for "good" aspect ratio 
     var frameSize = view.frame.size 
     frameSize.height = frameSize.width/1.43023255813953 
     view.frame.size = frameSize 

     // Should force the aspect ratio 
     print("-------------") 
     print("width \(view.frame.width) and height \(view.frame.height)") 
     print("aspect ratio w/h \(view.frame.width/view.frame.height)") 
     print("-------------") 

     view.context = self.context! 
     view.drawableColorFormat = .RGBA8888 
     view.drawableMultisample = .multisample4X 
     //view.drawableMultisample = .MultisampleNone 
     //view.multipleTouchEnabled = true 

     width = self.view.frame.size.width * self.view.contentScaleFactor 
     height = self.view.frame.size.height * self.view.contentScaleFactor 

     circleWidth = width/CGFloat(cols) 
     circleHeight = height/CGFloat(rows) 

     self.setupGL() 

    } 

    func initTextures() 
    { 
     gpuColorsTexture = [GLubyte](repeating: 0, count: Int(texWidth)*Int(texHeight)*4) 
     gpuSmallColorsTexture = [GLubyte](repeating: 128, count: Int(smallPointsTextureWidth)*Int(smallPointsTextureHeight)) 
    } 

    // MARK: - GLKView and GLKViewController delegate methods 

    func sendTexturesToGPU() { 
     for i in 0..<currentColorsTextureData!.count/4 { 
      let r = Int(i)/Int(cols) 
      let c = Int(i) % cols 

      let j = r * texWidth + c 
      gpuColorsTexture[j*4] = currentColorsTextureData![i * 4]; //= GLubyte(255); // red 
      gpuColorsTexture[j*4+1] = currentColorsTextureData![i * 4 + 1]; //GLubyte(random() % 255); // green 
      gpuColorsTexture[j*4+2] = currentColorsTextureData![i * 4 + 2]; //GLubyte(0); // blue 
      gpuColorsTexture[j*4+3] = currentColorsTextureData![i * 4 + 3]; // used for the stroke color 
     } 

     for i in 0..<currentSmallPointTextureData!.count{ 
      let r = Int(i)/Int(31 * 2) 
      let c = Int(i) % (31 * 2) 

      let j = r * 128 + c 
      gpuSmallColorsTexture[j] = currentSmallPointTextureData![i]; 
     } 

     glActiveTexture(GLenum(GL_TEXTURE1)); 
     glTexImage2D(GLenum(GL_TEXTURE_2D), GLint(0), GL_LUMINANCE, GLsizei(smallPointsTextureWidth), GLsizei(smallPointsTextureHeight), GLint(0), GLenum(GL_LUMINANCE), GLenum(GL_UNSIGNED_BYTE), &gpuSmallColorsTexture) 

     glActiveTexture(GLenum(GL_TEXTURE0)); 
     glTexImage2D(GLenum(GL_TEXTURE_2D), GLint(0), GL_RGBA, GLsizei(texWidth), GLsizei(texHeight), GLint(0), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), &gpuColorsTexture); 
    } 

    func update() { 
     print("update") 
     //todo 

    } 

    // todo send a uniform array 

    override open func glkView(_ view: GLKView, drawIn rect: CGRect) { 
     glClearColor(1.0, 1.0, 0.0, 1.0) 
     glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) 

     glEnable(GLenum(GL_DEPTH_TEST)) 
     glEnable(GLenum(GL_POINT_SIZE)); 
     glEnable(GLenum(GL_BLEND)) 
     glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA)) 
     glEnable(GLenum(GL_POINT_SMOOTH)) 

     // 22 x 15 

     var baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, 0.0) 
     baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, 0.0, 0.0, 1.0, 0.0) 

     var modelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, 1.5) 
     modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, 0.0, 1.0, 1.0, 1.0) 
     modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix) 

     modelViewMatrix = GLKMatrix4Identity 
     glUseProgram(program) 

     /* 
     withUnsafePointer(to: &modelViewProjectionMatrix, { 
      $0.withMemoryRebound(to: Float.self, capacity: 16, { 
       glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, $0) 
      }) 
     })*/ 


     withUnsafePointer(to: &modelViewMatrix, { 
      $0.withMemoryRebound(to: Float.self, capacity: 16, { 
       glUniformMatrix4fv(glGetUniformLocation(program, "modelViewProjectionMatrix"), 1, 0, UnsafePointer($0)) 
      }) 
     }) 

     glVertexAttribPointer(0, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, squareVertices) 
     glUniform4f(glGetUniformLocation(program, "iResolution"), Float(width), Float(height), Float(texWidth), Float(texHeight)) 
     glUniform2f(glGetUniformLocation(program, "gridSize"), Float(cols), Float(rows)) 

     glDrawArrays(GLenum(GL_TRIANGLE_STRIP) , 0, 4) 

     glUseProgram(circleProgram) 
    } 

    // MARK: - Texture 

    func setupTextures() 
    { 
     let texInfo = try! GLKTextureLoader.texture(with: UIImage(named: "texture256")!.cgImage!, options: nil) 

     glActiveTexture(GLenum(GL_TEXTURE0)) 
     glBindTexture(GLenum(GL_TEXTURE0), (texInfo.name)) 
     //var dataTexture = (texInfo.name) 
     glUniform1i(glGetUniformLocation(program, "textureUnit"), 0) 


     glActiveTexture(GLenum(GL_TEXTURE1)) 
     let _ = createSmallPointsTexture() 
     glUniform1i(glGetUniformLocation(program, "smallPointsTextureUnit"), 1) 
    } 

    func createSmallPointsTexture() -> GLuint { 
     var texture: GLuint = 1 
     glGenTextures(GLsizei(1), &texture) 

     glBindTexture(GLenum(GL_TEXTURE_2D), texture) 

     glActiveTexture(texture) 
     glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GL_LINEAR); 
     glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GL_LINEAR_MIPMAP_LINEAR); 

     glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GL_CLAMP_TO_EDGE); 
     glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GL_CLAMP_TO_EDGE); 

     glGenerateMipmap(GLenum(GL_TEXTURE_2D)); 

     return texture 
    } 

    // MARK: - OpenGL ES 2 shader compilation 

    func setupGL() { 
     EAGLContext.setCurrent(self.context) 

     let _ = self.loadShaders() 

     glUseProgram(program) 
     glEnableVertexAttribArray(0) 

     self.setupTextures() 
    } 

    func tearDownGL() { 
     EAGLContext.setCurrent(self.context) 

     if program != 0 { 
      glDeleteProgram(program) 
      program = 0 
     } 
    } 

    func loadShaders() -> Bool { 
     var vertShader: GLuint = 0 
     var fragShader: GLuint = 0 
     var vertShaderPathname: String 
     var fragShaderPathname: String 

     // Create shader program. 
     program = glCreateProgram() 

     // Create and compile vertex shader. 
     vertShaderPathname = Bundle.main.path(forResource: "Shader", ofType: "vsh")! 
     if self.compileShader(&vertShader, type: GLenum(GL_VERTEX_SHADER), file: vertShaderPathname) == false { 
      print("Failed to compile vertex shader") 
      return false 
     } 

     // Create and compile fragment shader. 
     fragShaderPathname = Bundle.main.path(forResource: "Shader", ofType: "fsh")! 
     if !self.compileShader(&fragShader, type: GLenum(GL_FRAGMENT_SHADER), file: fragShaderPathname) { 
      print("Failed to compile fragment shader") 
      /* 
      var fragInfoLength: GLint = 0 
      glGetShaderiv(fragShader, GLenum(GL_INFO_LOG_LENGTH), &fragInfoLength) 

      //let cstring = UnsafeMutablePointer<GLchar>(allocatingCapacity: Int(fragInfoLength)) 
      var cstring = UnsafeMutablePointer<GLchar>(malloc(Int(fragInfoLength))) 

      glGetShaderInfoLog(fragShader, fragInfoLength, nil, cstring) 
      let shaderInfoLog = NSString(utf8String: cstring) 
      print(shaderInfoLog) 
      */ 
      return false 
     } 

     // Attach vertex shader to program. 
     glAttachShader(program, vertShader) 

     // Attach fragment shader to program. 
     glAttachShader(program, fragShader) 

     // Bind attribute locations. 
     // This needs to be done prior to linking. 
     glBindAttribLocation(program, 0, "position") 

     // Link program. 
     if !self.linkProgram(program) { 
      print("Failed to link program: \(program)") 

      if vertShader != 0 { 
       glDeleteShader(vertShader) 
       vertShader = 0 
      } 
      if fragShader != 0 { 
       glDeleteShader(fragShader) 
       fragShader = 0 
      } 
      if program != 0 { 
       glDeleteProgram(program) 
       program = 0 
      } 

      return false 
     } 

     // Release vertex and fragment shaders. 
     if vertShader != 0 { 
      glDetachShader(program, vertShader) 
      glDeleteShader(vertShader) 
     } 
     if fragShader != 0 { 
      glDetachShader(program, fragShader) 
      glDeleteShader(fragShader) 
     } 

     return true 
    } 


    func compileShader(_ shader: inout GLuint, type: GLenum, file: String) -> Bool { 
     var status: GLint = 0 
     var source: UnsafePointer<Int8> 
     do { 
      source = try NSString(contentsOfFile: file, encoding: String.Encoding.utf8.rawValue).utf8String! 
     } catch { 
      print("Failed to load vertex shader") 
      return false 
     } 
     //var castSource = UnsafePointer<GLchar>(source) 
     var castSource: UnsafePointer<GLchar>? = UnsafePointer<GLchar>(source) 


     shader = glCreateShader(type) 
     glShaderSource(shader, 1, &castSource, nil) 
     glCompileShader(shader) 

     var logLength: GLint = 0 
     glGetShaderiv(shader, GLenum(GL_INFO_LOG_LENGTH), &logLength) 

     if logLength > 0 { 
      //var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength))) 
      print("Log length gt 0") 
      /* 
      var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength))) 

      glGetShaderInfoLog(shader, logLength, &logLength, log) 
      NSLog("Shader compile log: \n%s", log) 
      free(log) 
      */ 
     } 

     glGetShaderiv(shader, GLenum(GL_COMPILE_STATUS), &status) 
     if status == 0 { 
      glDeleteShader(shader) 
      return false 
     } 
     return true 
    } 

    func linkProgram(_ prog: GLuint) -> Bool { 
     var status: GLint = 0 
     glLinkProgram(prog) 

     //#if defined(DEBUG) 
     //  var logLength: GLint = 0 
     //  glGetShaderiv(shader, GLenum(GL_INFO_LOG_LENGTH), &logLength) 
     //  if logLength > 0 { 
     //   var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength))) 
     //   glGetShaderInfoLog(shader, logLength, &logLength, log) 
     //   NSLog("Shader compile log: \n%s", log) 
     //   free(log) 
     //  } 
     //#endif 

     glGetProgramiv(prog, GLenum(GL_LINK_STATUS), &status) 
     if status == 0 { 
      return false 
     } 

     return true 
    } 

    func validateProgram(_ prog: GLuint) -> Bool { 
     var logLength: GLsizei = 0 
     var status: GLint = 0 

     glValidateProgram(prog) 
     glGetProgramiv(prog, GLenum(GL_INFO_LOG_LENGTH), &logLength) 
     if logLength > 0 { 
      var log: [GLchar] = [GLchar](repeating: 0, count: Int(logLength)) 
      glGetProgramInfoLog(prog, logLength, &logLength, &log) 
      print("Program validate log: \n\(log)") 
     } 

     glGetProgramiv(prog, GLenum(GL_VALIDATE_STATUS), &status) 
     var returnVal = true 
     if status == 0 { 
      returnVal = false 
     } 
     return returnVal 
    } 

    // MARK : Cleanup 

    override open func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 

     if self.isViewLoaded && (self.view.window != nil) { 
      self.view = nil 

      self.tearDownGL() 

      if EAGLContext.current() === self.context { 
       EAGLContext.setCurrent(nil) 
      } 
      self.context = nil 
     } 
    } 

    deinit { 
     self.tearDownGL() 

     if EAGLContext.current() === self.context { 
      EAGLContext.setCurrent(nil) 
     } 
    } 

} 

var squareVertices: [GLfloat] = [ 
    -1.0, -1.0, 
    1.0, -1.0, 
    -1.0, 1.0, 
    1.0, 1.0, 
]; 
+0

如果您不顯示繪製圓的代碼,誰可以回答您的問題?你在你的片段着色器代碼或頂點着色器中畫了一個圓圈嗎?這對Retina無關緊要,或者不在幀緩衝區中繪製對象,因爲視圖幀大小並不總是等於FBO大小。 – Sung

+0

我對所有與此相關的代碼進行了更新。我覺得這肯定是某種設置問題,因爲截止點非常陡峭,只能在一臺設備上顯示,而在其他設備上工作得很好。 –

回答

0

感謝您的更新。我不確定究竟哪個部分導致了它,但我確定它必須發生在你的片段着色器代碼中。

我猜vec2 st的價值變化是不穩定的那裏,而它正在計算。

我想讓你測試一下,看看它是否是你的片段着色器。

只繪製了一個沒有統一值的圓,除了iResolution。 只使用iResolution和gl_FragCoord,畫一個圓。

我認爲它會正常顯示。然後過你的FS。

+0

你好。它似乎仍然工作正常。爲了清晰起見,我進一步使用屏幕截圖更新了問題。 –

+0

@TiborUdvari當你在FS中畫一個圓時,在每個設備上顯示出來都很好,對吧?我認爲這不是視網膜問題。你不會在那裏做出平滑的曲線(你更新的紅色區域),所以請使用統一變量來檢查你的Fragment Shader – Sung

相關問題