Offscreen rendering in OpenGL producing artefacts in framebuffer

I have a program that uses an offscreen OpenGL context to render a mesh of 28943 triangles into a texture. It renders the Z value, producing a height map. Then it downloads the texture using glReadnPixels(), and saves it to a file.

vertices.txt contains the vertices in a format like

-5570.08, 2616.11, -83.408,
-5581.21, 2624.23, -96.4702,
-5570.08, 2616.11, -83.408,
-5555.29, 2627.9, -87.1785,
...

each line is the X,Y,Z coordinates of a vertex, and every 3 lines are the vertices that form one triangle. They form a mesh that looks like this, without outlier points or NAN values:
Mesh rendering


When I change the line outZ = mapPosition.z; in the vertex shader (in source code below) to outZ = 1000.0, it correctly renders the following depth map:

Correct output

All non-background pixels having the value 1000.0.


But, with outZ = mapPosition.z, the following output gets generated:

Incorrect output

The gray sections contain the correct Z values, but the white sections contain invalid values.


With outZ = mapPosition.x;, it becomes like this. So even the x/y positions of the fragments (pixels) get corrupted:

Incorrect output 2


It seems to happen the same way on with NVidia and Intel GPUs.
This is the full source code. GLContext creates the offscreen context (with OpenGL 4.6 Core profile), with the proper width/height, and also calls glViewport(), and this has been tested to work correctly before.

Is there an error in the way that the OpenGL API is used?

#include "common/GLContext.h"

#include <string>
#include <fstream>
#include <iostream>
#include <map>
#include <array>
#include <typeinfo>

#include <Eigen/Dense>

static const char vertexShader[] = R"%%%(
#version 460 core

uniform mat3 alignmentRotation;
uniform vec3 alignmentTranslation;

uniform mat4 projection;

layout(location=0) in vec3 inPosition;

layout(location=0) out float outZ;

void main() {
    vec3 localPosition = inPosition;

    vec3 worldPosition = (alignmentRotation * localPosition) + alignmentTranslation;

    vec3 mapPosition = worldPosition;
    mapPosition.x += 10000;
    mapPosition.y += 3000;

    gl_Position = projection * vec4(mapPosition, 1.0);
    outZ = mapPosition.z;
    //outZ = 1000.0;
    //outZ = mapPosition.x;
}
)%%%";

static const char fragmentShader[] = R"%%%(
#version 460 core

layout(location=0) in float inZ;

layout(location=0) out float outZ;

void main() {   
  outZ = inZ;
}
)%%%";

static void GLAPIENTRY GLDebugMessageHandler(GLenum source, GLenum type, GLenum id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
  std::cout << message << std::endl;
}


class GLProgram {
public:
  GLProgram(GLuint id) : id_(id) { }
  ~GLProgram() {
    glDeleteProgram(id_);
  }

  GLint UniformLocation(const std::string& name) {
    GLint location = GL_CHK(glGetUniformLocation(id_, name.c_str()));
    return location;
  }

  operator GLuint () const { return id_; }

private:
  std::map<std::string, GLint> uniformLocations_;
  GLuint id_ = 0;
};


struct GLShaderSource {
  GLuint type;
  std::string data;
};

using GLShaderSources = std::vector<GLShaderSource>;

static GLProgram BuildGLProgram(const GLShaderSources& shaderSources) {
  GLuint program = GL_CHK(glCreateProgram());

  for(const GLShaderSource& shaderSource : shaderSources) {
    GLuint shader = GL_CHK(glCreateShader(shaderSource.type));
    GL_CHK(glAttachShader(program, shader));
    GL_CHK(glDeleteShader(shader));

    std::string source = shaderSource.data;

    const GLchar* sourceData = source.c_str();
    GLint sourceLength = (GLint)source.length();
    GL_CHK(glShaderSource(shader, 1, &sourceData, &sourceLength));

    GL_CHK(glCompileShader(shader));

    GLint compileStatus;
    GL_CHK(glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus));
    if(compileStatus != GL_TRUE) {
      GLint infoLogSize;
      GL_CHK(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogSize));

      std::string infoLog;
      infoLog.resize(infoLogSize - 1);
      GL_CHK(glGetShaderInfoLog(shader, infoLogSize, NULL, infoLog.data()));

      GL_CHK(glDeleteProgram(program));
      std::cout << "failed to build GL program: " << infoLog << std::endl;
      std::abort();
    }
  }

  GL_CHK(glLinkProgram(program));

  GLint linkStatus;
  GL_CHK(glGetProgramiv(program, GL_LINK_STATUS, &linkStatus));
  if(linkStatus != GL_TRUE) {
    GLint infoLogSize;
    GL_CHK(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogSize));

    std::string infoLog;
    infoLog.resize(infoLogSize - 1);
    GL_CHK(glGetProgramInfoLog(program, infoLogSize, NULL, infoLog.data()));

    GL_CHK(glDeleteProgram(program));
    std::cout << "failed to link GL program: " << infoLog << std::endl;
    std::abort();
  }

  return GLProgram(program);
}




int main() try {
  // vertices data
  static GLfloat vertices[][3] = {
    #include "vertices.txt"
  };
  const std::size_t numVertices = sizeof(vertices) / sizeof(GLfloat[3]);

  // transformation
  Eigen::Matrix4f alignment;
  alignment <<
    1, 0, 0, 3292.34,
    0, 1, 0, -20.297,
    0, 0, 1, 2173.21,
    0, 0, 0,       1;

  // parameters
  const std::size_t mapSize = 512;
  const float pixelSize = 20.0;
  const std::size_t mapWidth = mapSize, mapHeight = mapSize;
  const float minZ = -1e5;
  const float maxZ = +1e5;
  const std::size_t maxNumInputTriangles = 100000;
  const std::size_t maxNumInputVertices = 100000;
  const Eigen::Vector2f minimalXY(-10000, -3000);

  // create offscreen GL context
  GLContextConfiguration glConfig;
  glConfig.width = mapSize;
  glConfig.height = mapSize;
  glConfig.debug = true;
  GLContext glContext(glConfig);
  std::cout << glContext.Information().rendererName << std::endl;
  glContext.MakeCurrent();

  // debug
  GL_CHK(glEnable(GL_DEBUG_OUTPUT));
  GL_CHK(glDebugMessageCallback(GLDebugMessageHandler, NULL));

  // generate opengl objects
  GLuint vertexArray = 0;
  GLuint vertexBuffer = 0;
  GLuint framebuffer = 0;
  GLuint texture = 0;

  GL_CHK(glGenVertexArrays(1, &vertexArray));
  GL_CHK(glGenBuffers(1, &vertexBuffer));
  GL_CHK(glGenFramebuffers(1, &framebuffer));
  GL_CHK(glGenTextures(1, &texture));

  // input buffer
  {
    GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer));
    GL_CHK(glBufferStorage(GL_ARRAY_BUFFER, numVertices * sizeof(GLfloat[3]), NULL, GL_DYNAMIC_STORAGE_BIT));
    GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, 0));
  }

  // vertex array
  {
    GL_CHK(glBindVertexArray(vertexArray));
    GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer));

    std::size_t stride = 3 * sizeof(GLfloat);
    GL_CHK(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0));
    GL_CHK(glEnableVertexAttribArray(0));
    GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, 0));
    GL_CHK(glBindVertexArray(0));
  }

  // texture
  GL_CHK(glBindTexture(GL_TEXTURE_2D, texture));
  GL_CHK(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F /*GL_RGBA32F*/, mapWidth, mapHeight));
  GL_CHK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
  GL_CHK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
  GL_CHK(glBindTexture(GL_TEXTURE_2D, 0));

  // create program
  GLShaderSources shaderSources = {
    { GL_VERTEX_SHADER, vertexShader },
    { GL_FRAGMENT_SHADER, fragmentShader }
  };
  GLProgram mappingShaderProgram = BuildGLProgram(shaderSources);

  // set program uniforms
  {
    GL_CHK(glUseProgram(mappingShaderProgram));

    Eigen::Matrix3f rotation = alignment.block<3, 3>(0, 0);
    Eigen::Vector3f translation = alignment.block<3, 1>(0, 3);
    GL_CHK(glUniformMatrix3fv(mappingShaderProgram.UniformLocation("alignmentRotation"), 1, GL_FALSE, (const GLfloat*)rotation.data()));
    GL_CHK(glUniform3fv(mappingShaderProgram.UniformLocation("alignmentTranslation"), 1, (const GLfloat*)translation.data()));

    // projection matrix
    float maxX = mapWidth * pixelSize;
    float maxY = mapHeight * pixelSize;
    Eigen::Matrix4f projectionMatrix; projectionMatrix <<
      2.0 / maxX, 0.0, 0.0, -1.0,
      0.0, 2.0 / maxY, 0.0, -1.0,
      0.0, 0.0, 2.0 / (maxZ - minZ), -(maxZ + minZ) / (maxZ - minZ),
      0.0, 0.0, 0.0, 1.0;
    GL_CHK(glUniformMatrix4fv(mappingShaderProgram.UniformLocation("projection"), 1, GL_FALSE, (const GLfloat*)projectionMatrix.data()));

    GL_CHK(glUseProgram(0));
  }


  GL_CHK(glFinish());

  // clear texture
  {
    std::array<GLfloat, 4> background{ 0.0f, 0.0f, 0.0f, 1.0f };
    GL_CHK(glClearTexImage(
      texture,
      0,
      GL_RGBA,
      GL_FLOAT,
      background.data()
    ));
  }


  // bind texture to framebuffer
  GL_CHK(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
  GL_CHK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0));
  std::vector<GLenum> drawBuffers{ GL_COLOR_ATTACHMENT0 };
  GL_CHK(glDrawBuffers(drawBuffers.size(), drawBuffers.data()));
  GL_CHK(glBindFramebuffer(GL_FRAMEBUFFER, 0));


  // blending
  GL_CHK(glDisablei(GL_BLEND, 0));
  GL_CHK(glDisable(GL_BLEND));

  // depth clamping
  GL_CHK(glDisable(GL_DEPTH_CLAMP));
  GL_CHK(glDisable(GL_DEPTH_TEST));


  // upload data and draw
  GL_CHK(glBindVertexArray(vertexArray));

  GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer));
  GL_CHK(glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(GLfloat[3]), vertices));
  GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, 0));

  glFinish();

  std::size_t numTriangles = numVertices / 3;
  GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer));
  GL_CHK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer));
  GL_CHK(glUseProgram(mappingShaderProgram));
  GL_CHK(glDrawArrays(GL_TRIANGLES, 0, 3 * numTriangles));
  GL_CHK(glUseProgram(0));
  GL_CHK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
  GL_CHK(glBindBuffer(GL_ARRAY_BUFFER, 0));

  GL_CHK(glBindVertexArray(0));

  GL_CHK(glFlush());
  GL_CHK(glFinish());

  // read texture pixels
  std::vector<GLfloat> rgbaBuffer(mapWidth * mapHeight * 4);
  GL_CHK(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
  GL_CHK(glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE));
  GL_CHK(glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE));
  GL_CHK(glPixelStorei(GL_PACK_ALIGNMENT, 1));
  GL_CHK(glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE));
  GL_CHK(glReadnPixels(
    0, 0,
    mapWidth, mapHeight,
    GL_RED,
    GL_FLOAT,
    mapWidth * mapHeight * sizeof(GLfloat),
    rgbaBuffer.data()
  ));
  GL_CHK(glBindFramebuffer(GL_FRAMEBUFFER, 0));

  // export to uint16 image
  {
    Eigen::Matrix<std::uint16_t, Eigen::Dynamic, Eigen::Dynamic> map(mapSize, mapSize);
    for(GLsizei row = 0; row < mapHeight; ++row) {
      const auto* ptr = rgbaBuffer.data() + (row * mapWidth);
      for(GLsizei col = 0; col < mapWidth; ++col, ptr += 1) {
        float value = ptr[0];
        if(value > 65535) value = 65535;
        else if(value < 0.0) value = 0.0;
        map(row, col) = static_cast<std::uint16_t>(value);
      }
    }

    std::ofstream mapFile("map.bin");
    mapFile.write(reinterpret_cast<const char*>(map.data()), mapHeight * mapWidth * sizeof(std::uint16_t));
  }

} catch(const std::exception& ex) {
  std::cout << "exception " << typeid(ex).name() << ": " << ex.what() << std::endl;
  return EXIT_FAILURE;
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật