【发布时间】:2016-06-27 19:11:24
【问题描述】:
我正在尝试在 OpenGL 中以程序方式生成一个充满星星的背景。
我采用的方法是创建一个带有立方体贴图纹理的天空盒。立方体贴图纹理的每一面基本上都由一个 2048x2048 黑色图像组成,其中随机选择的纹素设置为白色。结果如下:
我不确定它在图像中有多明显,但是当围绕一个非常明显的盒子形状移动时,可以看到靠近盒子边缘的星星看起来越来越小。我怎样才能防止这种情况?我是否需要放弃天空盒方法并改用天空球之类的东西?
编辑:这是我将立方体贴图映射到天空的方式。
// Create and bind texture.
glGenTextures(1, &texture_);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture_);
for (unsigned int i = 0; i < 6; ++i) {
std::vector<std::uint8_t> image = generateTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT,
0, GL_RGB, GL_UNSIGNED_BYTE, image.data());
}
// Set texture parameters.
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
这里是generateTexture函数的定义:
std::vector<std::uint8_t> Stars::generateTexture(GLsizei width, GLsizei height) {
std::vector<std::uint8_t> image(static_cast<std::size_t>(3 * width * height));
add_stars(image, NUM_STARS);
return image;
}
void Stars::add_stars(std::vector<std::uint8_t>& image, unsigned int nStars) {
std::default_random_engine eng;
std::uniform_int_distribution<std::size_t> dist(0, image.size() / 3 - 1);
while (nStars--) {
std::size_t index = 3 * dist(eng);
image[index++] = 255;
image[index++] = 255;
image[index++] = 255;
}
}
EDIT2:这里是用于渲染天空的绘制函数。
void Stars::draw(const Camera& camera) const {
// Skybox will be rendered last. In order to ensure that the stars are rendered at the back of
// the scene, the depth buffer is filled with values of 1.0 for the skybox -- this is done in
// the vertex shader. We need to make sure that the skybox passes the depth te3t with values
// less that or equal to the depth buffer.
glDepthFunc(GL_LEQUAL);
program_.enable();
// Calculate view-projection matrix and set the corresponding uniform. The view matrix must be
// stripped of translation components so that the skybox follows the camera.
glm::mat4 view = glm::mat4(glm::mat3(camera.viewMatrix()));
glm::mat4 projection = camera.projectionMatrix();
glm::mat4 VP = projection * view;
glUniformMatrix4fv(program_.uniformLocation("VP"), 1, GL_FALSE, glm::value_ptr(VP));
// Bind buffer objects and texture to current context and draw.
glBindVertexArray(vao_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture_);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(INDICES.size()), GL_UNSIGNED_INT,
reinterpret_cast<GLvoid *>(0));
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
program_.disable();
glDepthFunc(GL_LESS);
}
【问题讨论】:
-
你为什么贴一个黑色的矩形?如此浪费内存/存储空间。
-
@ThomasMatthews ?图片中应该有星星。
-
不清楚您是如何将立方体贴图映射到天空的。请提供minimal reproducible example。
-
在立方体面上生成星星可能看起来是均匀分布的,但是一旦添加了透视变换,立方体的形状就会很明显,如您所见。你需要做一些更复杂的事情并将它们映射到你的立方体上。
-
很难让立方体上的纹理看起来均匀。一般来说,你可以做三件事之一。 1) 使立方体更矩形(在 Y-up 世界中的 XZ 平面中),这样天空更近,角落不那么明显(假设场景中有物体)。 2) 使用球坐标在随机方向上投射光线,并通过恒星的反距离来缩放恒星的大小。 3) 我建议使用球形贴图而不是立方体贴图。
标签: c++ opengl procedural-generation