[英]using HDR maps in LWJGL 3
我目前正在使用LWJGL 3并构建一个简单的skybox。 我希望Skybox接收HDR文件,即等角图。 我可以使用PNGDecoder让Skybox与PNG一起运行,但不确定如何与HDR文件配合使用。 据我了解,STB(在c ++中)允许将HDR文件上传到程序中,并且LWJGL 3具有STB支持。
我将如何制作支持STB和HDR文件的loadTexture函数?
编辑:我将要发布的进度,以便任何人都可以看到我正在从事的工作。
我的加载程序类包含我所有的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.