繁体   English   中英

在LWJGL 3中使用HDR映射

[英]using HDR maps in LWJGL 3

我目前正在使用LWJGL 3并构建一个简单的skybox。 我希望Skybox接收HDR文件,即等角图。 我可以使用PNGDecoder让Skybox与PNG一起运行,但不确定如何与HDR文件配合使用。 据我了解,STB(在c ++中)允许将HDR文件上传到程序中,并且LWJGL 3具有STB支持。

我将如何制作支持STB和HDR文件的loadTexture函数?

编辑:我将要发布的进度,以便任何人都可以看到我正在从事的工作。

  1. 我的加载程序类包含我所有的loadTexture方法,并且我使用的是存储纹理ID的int方法,当前该方法如下所示:

     public int loadCubeMap(String textureFile) throws IOException { int texID = glGenTextures(); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ByteBuffer imageBuffer; IntBuffer w = BufferUtils.createIntBuffer(1); IntBuffer h = BufferUtils.createIntBuffer(1); IntBuffer comp = BufferUtils.createIntBuffer(1); ByteBuffer image; imageBuffer = IOUtil.ioResourceToByteBuffer(textureFile, 8 * 1024); if (!stbi_info_from_memory(imageBuffer, w, h, comp)) throw new IOException("Failed to read image information: " + stbi_failure_reason()); image = stbi_load_from_memory(imageBuffer, w, h, comp, 3); if (image == null) throw new IOException("Failed to load image: " + stbi_failure_reason()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w.get(0), h.get(0), 0, GL_RGB, GL_UNSIGNED_BYTE, image); stbi_image_free(image); return texID; } 

这是我从这个演示lwjgl3,演示了在这里使用了HDR纹理,并使用STBImage Java绑定的环境地图的一个例子。 该方法还在我的utils包中使用了一个名为IOUtil的类,该类来自示例,可在示例中使用。 (我还尝试了LearnOpengl教程中的HDR文件,该文件在示例中工作正常,但不适用于我自己的代码);

我有一个Skybox着色器和一个Skybox渲染器,它们似乎都可以正常工作。 天空盒渲染器的编写方式如下:

公共类SkyboxRenderer {

private static final float SIZE = 500f;

private static final float[] VERTICES = {        
    -SIZE,  SIZE, -SIZE,
    -SIZE, -SIZE, -SIZE,
    SIZE, -SIZE, -SIZE,
     SIZE, -SIZE, -SIZE,
     SIZE,  SIZE, -SIZE,
    -SIZE,  SIZE, -SIZE,

    -SIZE, -SIZE,  SIZE,
    -SIZE, -SIZE, -SIZE,
    -SIZE,  SIZE, -SIZE,
    -SIZE,  SIZE, -SIZE,
    -SIZE,  SIZE,  SIZE,
    -SIZE, -SIZE,  SIZE,

     SIZE, -SIZE, -SIZE,
     SIZE, -SIZE,  SIZE,
     SIZE,  SIZE,  SIZE,
     SIZE,  SIZE,  SIZE,
     SIZE,  SIZE, -SIZE,
     SIZE, -SIZE, -SIZE,

    -SIZE, -SIZE,  SIZE,
    -SIZE,  SIZE,  SIZE,
     SIZE,  SIZE,  SIZE,
     SIZE,  SIZE,  SIZE,
     SIZE, -SIZE,  SIZE,
    -SIZE, -SIZE,  SIZE,

    -SIZE,  SIZE, -SIZE,
     SIZE,  SIZE, -SIZE,
     SIZE,  SIZE,  SIZE,
     SIZE,  SIZE,  SIZE,
    -SIZE,  SIZE,  SIZE,
    -SIZE,  SIZE, -SIZE,

    -SIZE, -SIZE, -SIZE,
    -SIZE, -SIZE,  SIZE,
     SIZE, -SIZE, -SIZE,
     SIZE, -SIZE, -SIZE,
    -SIZE, -SIZE,  SIZE,
     SIZE, -SIZE,  SIZE
};

private RawModel cube;
private int skyboxTexture;
private SkyboxShader shader;

public SkyboxRenderer(Loader loader, Matrix4f projectionMatrix) throws IOException {
    cube = loader.loadToVAO(VERTICES, 3);
    skyboxTexture = loader.loadCubeMap("res/newport_loft.hdr");
    shader = new SkyboxShader();
    shader.start();
    shader.loadProjectionMatrix(projectionMatrix);
    shader.connectTextureUnits();
    shader.stop();
    }

public void render(Camera camera) {
    shader.start();
    shader.loadViewMatrix(camera);
    GL30.glBindVertexArray(cube.getVaoID());
    GL20.glEnableVertexAttribArray(0);

    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, skyboxTexture);
    GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, cube.getVertexCount());
    GL20.glDisableVertexAttribArray(0);
    GL30.glBindVertexArray(0);
    shader.stop();
    }
}

我正在使用来自learningOpengl的PBR教程的顶点和片段着色器。

顶点着色器:

#version 330 core 

layout (location = 0) in vec3 aPos;

out vec3 WorldPos;

uniform mat4 projection; 
uniform mat4 view;

void main() {
    WorldPos = aPos;  
    gl_Position =  projection * view * vec4(WorldPos, 1.0); }

片段着色器:

#version 330 core
out vec4 FragColor;
in vec3 WorldPos;

uniform sampler2D equirectangularMap;

const vec2 invAtan = vec2(0.1591, 0.3183);
vec2 SampleSphericalMap(vec3 v)
{
    vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
    uv *= invAtan;
    uv += 0.5;
    return uv;
}

void main()
{       
    vec2 uv = SampleSphericalMap(normalize(WorldPos));
    vec3 color = texture(equirectangularMap, uv).rgb;

    FragColor = vec4(color, 1.0);
}

在Thinmatrix的教程的帮助下,着色器代码可以正常工作。

公共类SkyboxShader扩展了ShaderProgram {

private static final String VERTEX_FILE = "src/skybox/cubemap.vs";
private static final String FRAGMENT_FILE = "src/skybox/cubemap.fs";

private int location_projectionMatrix;
private int location_viewMatrix;

private int location_equirectangularMap;

public SkyboxShader() {
    super(VERTEX_FILE, FRAGMENT_FILE);
}

public void loadProjectionMatrix(Matrix4f matrix){
    super.loadMatrix(location_projectionMatrix, matrix);
}

public void loadViewMatrix(Camera camera){
    Matrix4f matrix = Maths.createViewMatrix(camera);
    super.loadMatrix(location_viewMatrix, matrix);
}

@Override
protected void getAllUniformLocations() {
    location_projectionMatrix = super.getUniformLocation("projection");
    location_viewMatrix = super.getUniformLocation("view");
    location_equirectangularMap = super.getUniformLocation("equirectangularMap");
}

@Override
protected void bindAttributes() {
    super.bindAttribute(0, "aPos");
}

public void connectTextureUnits() {
    super.loadInt(location_equirectangularMap, 0);
} }

我在天空盒渲染器中初始化loadCubeMap函数以及文件名,然后在主渲染器类中初始化天空盒渲染器。

在运行它时,我对HDR纹理和加载程序没有任何错误,因此我假定它已接受它。 大部分有效。

这里

我得到一个盒子和一个纹理,但是纹理绑定到错误的纹理。 它绑定了我在地形中使用的反照率地面纹理,我猜这是事物未正确绑定(只是猜测)时的默认条件。

编辑:我刚刚意识到HDR贴图用于一个球体,并且正在渲染一个立方体。 (大声笑)

所以在那儿,我似乎无法解决问题。 我会再旋转一下,看看我可以改进什么。 任何帮助将非常感激。

编辑:

因此,我尝试对其进行重做。 image变量已更改为Float Buffer,现在接受带有stbi_loadf_from_memory的图像。 仍然是一个但很困惑的人,并不认为HDR映射会如此混乱。

public int loadCubeMap(String textureFile) throws IOException {

         int texID = glGenTextures();
         //glActiveTexture(GL11.GL_TEXTURE);
         glBindTexture(GL_TEXTURE_2D, texID);

         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

         ByteBuffer imageBuffer;
         IntBuffer w = BufferUtils.createIntBuffer(1);
         IntBuffer h = BufferUtils.createIntBuffer(1);
         IntBuffer comp = BufferUtils.createIntBuffer(1);
         FloatBuffer image;

         imageBuffer = IOUtil.ioResourceToByteBuffer(textureFile, 8 * 1024);

         if (!stbi_info_from_memory(imageBuffer, w, h, comp))
             throw new IOException("Failed to read image information: " + stbi_failure_reason());

         image = stbi_loadf_from_memory(imageBuffer, w, h, comp, 3);



         if (image == null)
             throw new IOException("Failed to load image: " + stbi_failure_reason());
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, w.get(0), h.get(0), 0, GL_RGB16, GL_FLOAT, image);

         stbi_image_free(image);

         return texID;

您应该使用stbi_loadf_from_memory()而不是stbi_load_from_memory()来读取HDR文件。 STB还包含诸如stbi_is_hdr_from_memory()函数,可让您确保缓冲区包含HDR图像。

请注意, stbi_load_from_memory()返回包含纹理的FloatBuffer

另外,您应该修改对glTexImage2D()的调用:

  • GL_UNSIGNED_BYTE替换为GL_FLOAT ,因为缓冲区现在包含每个组件的float ,并且
  • 选择一个适当的浮点内部格式,例如GL_RGB16F来替换GL_RGB8

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM