2
\$\begingroup\$

Geometry is rendering fine and works with attribute colors so I've definitely got something wrong with my texture loading / usage code. I've been following along with the tutorials at learnopengl.com as best I can. The code below is in Kotlin, so despite the funky syntax all the objects are standard Java objects. (While it should hopefully be easy enough to follow I've added some additional comments to the less obvious stuff.)

Initialisation:

glClearColor(1f, 0f, 0f, 1f)

// these will be overridden further on. (var is mutable, val is not)
var vao = -1
var vbo = -1
var ebo = -1
var texture = -1
var shaderProgram = -1

{ // Set up the geometry. A simple quad.
  val vertexBuffer = BufferUtils.createFloatBuffer(4 * 8) // 4 vertices of 8 floats.
  //                            position            color         uv
  vertexBuffer.put(floatArrayOf(-0.5f, -0.5f, 0f,   1f, 0f, 0f,   0f, 0f))
  vertexBuffer.put(floatArrayOf( 0.5f, -0.5f, 0f,   0f, 1f, 0f,   1f, 0f))
  vertexBuffer.put(floatArrayOf( 0.5f,  0.5f, 0f,   0f, 0f, 1f,   1f, 1f))
  vertexBuffer.put(floatArrayOf(-0.5f,  0.5f, 0f,   1f, 1f, 1f,   0f, 1f))
  vertexBuffer.flip()

  val indexBuffer = BufferUtils.createIntBuffer(3 * 2)
  indexBuffer.put(intArrayOf(0, 1, 2))
  indexBuffer.put(intArrayOf(2, 3, 0))
  indexBuffer.flip()

  vao = glGenVertexArrays()
  vbo = glGenBuffers()
  ebo = glGenBuffers()

  glBindVertexArray(vao)

  glBindBuffer(GL_ARRAY_BUFFER, vbo)
  glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW)

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW)

  glVertexAttribPointer(0, 3, GL_FLOAT, false, 8 * 4, 0)
  glEnableVertexAttribArray(0)

  glVertexAttribPointer(1, 3, GL_FLOAT, false, 8 * 4, 3 * 4)
  glEnableVertexAttribArray(1)

  glVertexAttribPointer(2, 2, GL_FLOAT, false, 8 * 4, 6 * 4)
  glEnableVertexAttribArray(2)

  glBindVertexArray(0)
}

{ // load the texture
  val image = ImageIO.read(File("test_image.png"))
  val pixels = IntArray(image.width * image.height) //image.width corresponds to image.getWidth() in Java, same for height.
  image.getRGB(0, 0, image.width, image.height, pixels, 0, image.width)

  val buffer = BufferUtils.createByteBuffer(image.width * image.height * 4)

  var y = 0
  var x = 0
  while (y < image.height) {
    while (x < image.width) {
      val pixel = pixels[y * image.width + x]
      buffer.put(((pixel shr 16) and 0xFF).toByte()) // "shr" and "and" are the usual ">>" and "&" bitwise operators. 
      buffer.put(((pixel shr 8) and 0xFF).toByte())
      buffer.put((pixel and 0xFF).toByte())
      buffer.put(((pixel shr 24) and 0xFF).toByte())
      x++
    }
    x = 0
    y++
  }
  buffer.flip()

  texture = glGenTextures()
  glBindTexture(GL_TEXTURE_2D, texture)
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer)
  glBindTexture(GL_TEXTURE_2D, 0)
}

{ // set up the shader
  val vertexSource = """
  #version 330 core

  layout (location = 0) in vec3 position;
  layout (location = 1) in vec3 color;
  layout (location = 2) in vec2 uv;

  out vec3 vColor;
  out vec2 vUv;

  void main() {
    vColor = color;
    vUv = uv;
    gl_Position = vec4(position, 1.0);
  }
  """
  val vertexShader = glCreateShader(GL_VERTEX_SHADER)
  glShaderSource(vertexShader, vertexSource)
  glCompileShader(vertexShader)

  val fragmentSource = """
  #version 330 core
  precision highp float;

  in vec3 vColor;
  in vec2 vUv;

  out vec4 color;

  uniform sampler2D texSampler;

  void main(){
    color = texture(texSampler, vUv);
    // color = vec4(vColor, 1.0);
  }
  """

  val shader = glCreateShader(GL_FRAGMENT_SHADER)
  glShaderSource(fragmentShader, fragmentSource)
  glCompileShader(fragmentShader)

  shaderProgram = glCreateProgram()
  glAttachShader(shaderProgram, vertexShader)
  glAttachShader(shaderProgram, fragmentShader)
  glLinkProgram(shaderProgram)

  glDeleteShader(vertexShader)
  glDeleteShader(fragmentShader)
}

Then when rendering:

glClear(GL_COLOR_BUFFER_BIT)

glUseProgram(shader)
glBindTexture(GL_TEXTURE_2D, texture)

glBindVertexArray(vao)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glBindVertexArray(0)

If the commented line in the fragment shader is swapped in it renders the colored quad as expected, but it just renders black when trying to use the texture. Stepping through the code in the debugger shows that the pixel colors being added to the texture buffer are colored as expected.

I've also got additional error checking in the shader loading and in the main loop, but as far as I can see OpenGL isn't showing any errors.

\$\endgroup\$
  • \$\begingroup\$ Hi, if interester, I am doing a kotlin port of that tutorial here \$\endgroup\$ – elect Sep 2 '17 at 9:27
1
\$\begingroup\$

Figured it out. It seems the default min filter is not set to GL_LINEAR as I had thought. If I do the following everything works as expected.

texture = glGenTextures()
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer)
glBindTexture(GL_TEXTURE_2D, 0)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.