我目前正在使用LWJGL 3并构建一个简单的天空盒。我希望天空盒能够拍摄一个HDR文件,一个equirectangular地图。我可以使用带PNGDecoder的PNG运行天空盒,但不确定它如何与HDR文件一起使用。根据我的理解,STB(在c ++中)允许将HDR文件上传到程序中,LWJGL 3支持STB。
我如何制作支持STB和HDR文件的loadTexture函数?
编辑:我要发布我的进展,以便任何人都可以看到我一直在做的事情。我的loader类包含我所有的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-demos here获得了一个使用HDR纹理和使用STBImage java绑定的环境贴图示例。该方法还在我的utils包中使用了一个名为IOUtil的类,它来自示例并在示例中工作。 (我也尝试过LearnOpengl教程中的HDR文件,该教程适用于该示例,但不适用于我自己的代码);
我有一个天空盒着色器和一个天空盒渲染器,它们似乎都运行良好。天空盒渲染器的编写如下:
公共类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();
}
}
我正在使用来自learnOpengl的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地图用于球体,我正在渲染一个立方体。 (LOL)
所以,我似乎无法弄清楚问题。我会再给它一个旋转,看看我能改进什么。任何帮助将不胜感激。
编辑:
所以我尝试过改造它。图像变量已更改为浮动缓冲区,现在接受带有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;
答案 0 :(得分:0)
而不是stbi_load_from_memory()
您应该使用stbi_loadf_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
。