C++ 用skybox程序生成恒星
我正试图在OpenGL中按程序生成一个充满星星的背景 我正在采取的方法是创建一个具有立方体贴图纹理的skybox。立方体贴图纹理的每一侧基本上由2048x2048黑色图像组成,随机选择的纹理元素设置为白色。结果如下: 我不确定从图像上看它有多明显,但当移动时,随着靠近盒子边缘的恒星看起来越来越小,可以看到一个非常独特的盒子形状。我怎样才能防止这种情况?我是否需要放弃skybox方法,转而使用类似skysphere的东西 编辑:下面是我如何将立方体贴图映射到天空的C++ 用skybox程序生成恒星,c++,opengl,procedural-generation,C++,Opengl,Procedural Generation,我正试图在OpenGL中按程序生成一个充满星星的背景 我正在采取的方法是创建一个具有立方体贴图纹理的skybox。立方体贴图纹理的每一侧基本上由2048x2048黑色图像组成,随机选择的纹理元素设置为白色。结果如下: 我不确定从图像上看它有多明显,但当移动时,随着靠近盒子边缘的恒星看起来越来越小,可以看到一个非常独特的盒子形状。我怎样才能防止这种情况?我是否需要放弃skybox方法,转而使用类似skysphere的东西 编辑:下面是我如何将立方体贴图映射到天空的 // Create and bi
// 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);
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);
}
void Stars::draw(常量摄影机和摄影机)常量{
//Skybox将最后渲染。为了确保星星渲染在
//在场景中,skybox的深度缓冲区填充了1.0的值——这是在中完成的
//顶点着色器。我们需要确保skybox通过深度te3t,并带有值
//小于或等于深度缓冲区。
glDepthFunc(GL_LEQUAL);
程序启用();
//计算视图投影矩阵并设置相应的一致性。视图矩阵必须为
//去除平移组件,使skybox跟随摄影机。
glm::mat4视图=glm::mat4(glm::mat3(camera.viewMatrix());
glm::mat4 projection=camera.projectionMatrix();
glm::mat4 VP=投影*视图;
glUniformMatrix4fv(程序统一位置(“VP”),1,GL_FALSE,glm::value_ptr(VP));
//将缓冲区对象和纹理绑定到当前上下文并绘制。
glBindVertexArray(vao_);
glBindBuffer(GL_元素_数组_缓冲区,ebo_);
glBindTexture(GL_纹理_立方体_贴图,纹理_);
GLD元素(GLU三角形、静态类型转换(index.size())、GLU无符号整数、,
重新解释(0);
glBindVertexArray(0);
glBindBuffer(GL_元素_数组_缓冲区,0);
glBindTexture(GL_纹理_立方体_贴图,0);
程序禁用();
glDepthFunc(GL_LESS);
}
x=2.0*Random()-1.0; // <-1,+1>
y=2.0*Random()-1.0; // <-1,+1>
z=2.0*Random()-1.0; // <-1,+1>
看起来它应该在这里预览(混合球体/立方体贴图):
虽然看起来有孔,但没有(可能是某些混合错误),如果禁用球体贴图渲染,则贴图中没有可见的孔或扭曲
用于测试的球体三角剖分网格obj
取自此处:
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int i;
float x,y,z,d;
RandSeed=8123456789;
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glPointSize(2.0);
glBegin(GL_POINTS);
for (i=0;i<1000;i++)
{
// uniform random cartesian stars inside cube
x=(2.0*Random())-1.0;
y=(2.0*Random())-1.0;
z=(2.0*Random())-1.0;
// project on unit sphere
d=sqrt((x*x)+(y*y)+(z*z));
if (d<1e-3) { i--; continue; }
d=1.0/d;
x*=d; y*=d; z*=d;
// redish sphere map
glColor3f(0.6,0.3,0.0); glVertex3f(x,y,z);
// cube half size=1 undistort using similarities like: y/x = y'/x'
if ((fabs(x)>=fabs(y))&&(fabs(x)>=fabs(z))){ y/=x; z/=x; if (x>=0) x=1.0; else x=-1.0; }
else if ((fabs(y)>=fabs(x))&&(fabs(y)>=fabs(z))){ x/=y; z/=y; if (y>=0) y=1.0; else y=-1.0; }
else if ((fabs(z)>=fabs(x))&&(fabs(z)>=fabs(y))){ x/=z; y/=z; if (z>=0) z=1.0; else z=-1.0; }
// bluish cube map
glColor3f(0.0,0.3,0.6); glVertex3f(x,y,z);
}
glEnd();
glPointSize(1.0);
glDisable(GL_BLEND);
glFlush();
SwapBuffers(hdc);
在这里,混合的结果是最终的颜色应该是这样的,当从(0,0,0)
观看时,球体和立方体星星完全重叠(白色):
为什么要贴一个黑色矩形?“这么浪费内存/存储空间。”托马斯马修斯?图像中应该有星星。不清楚你是如何将立方体映射到你的天空的。请提供一个示例。在立方体面上生成星星可能看起来是均匀分布的,但一旦添加透视变换,立方体的形状将是显而易见的,正如您所看到的。你需要做一些更复杂的事情,把它们映射到你的立方体上。要让立方体上的纹理看起来均匀是非常困难的。一般来说,你可以做三件事中的一件。1) 使立方体更为矩形(在Y向上世界的XZ平面中),以便天空更近,角点不那么明显(假设场景中有对象)。2) 使用球坐标在随机方向投射光线,并按恒星的反距离缩放恒星的大小。3) 我建议使用球形贴图而不是立方体贴图。这种方法不会导致极点周围的更高密度吗?呼应@Rhymoid注释,使用球坐标的随机分布将导致恒星的不均匀分布。如果你修改你答案的那一部分,我会接受的。这表明它只需在
[-1,+1]
中生成三个均匀的随机值,并将这些点投影到单位球体上即可。这可能不是最快的方法,但它确实很简单。@Rhymoid heh刚刚实现了相同的独立性。现在,比较使它比其他方法更难理解。
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int i,n=10000;
float a,b,x,y,z;
//RandSeed=8123456789;
n=obj.pnt.num; // triangulated sphere point list
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glPointSize(2.0);
glBegin(GL_POINTS);
for (i=0;i<n;i++)
{
// equidistant points instead of random to test this
x=obj.pnt[i].p[0];
y=obj.pnt[i].p[1];
z=obj.pnt[i].p[2];
/*
// random star spherical position
a=2.0*M_PI*Random();
b=M_PI*(Random()-0.5);
// spherical 2 cartessian r=1;
x=cos(a)*cos(b);
y=sin(a)*cos(b);
z= sin(b);
*/
// redish sphere map
glColor3f(0.6,0.3,0.0); glVertex3f(x,y,z);
// cube half size=1 undistort // using similarities like: yy/xx = y/x
if ((fabs(x)>=fabs(y))&&(fabs(x)>=fabs(z))){ y/=x; z/=x; if (x>=0) x=1.0; else x=-1.0; }
else if ((fabs(y)>=fabs(x))&&(fabs(y)>=fabs(z))){ x/=y; z/=y; if (y>=0) y=1.0; else y=-1.0; }
else if ((fabs(z)>=fabs(x))&&(fabs(z)>=fabs(y))){ x/=z; y/=z; if (z>=0) z=1.0; else z=-1.0; }
// bluish cube map
glColor3f(0.0,0.3,0.6); glVertex3f(x,y,z);
}
glEnd();
glPointSize(1.0);
glDisable(GL_BLEND);
glFlush();
SwapBuffers(hdc);
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int i;
float x,y,z,d;
RandSeed=8123456789;
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glPointSize(2.0);
glBegin(GL_POINTS);
for (i=0;i<1000;i++)
{
// uniform random cartesian stars inside cube
x=(2.0*Random())-1.0;
y=(2.0*Random())-1.0;
z=(2.0*Random())-1.0;
// project on unit sphere
d=sqrt((x*x)+(y*y)+(z*z));
if (d<1e-3) { i--; continue; }
d=1.0/d;
x*=d; y*=d; z*=d;
// redish sphere map
glColor3f(0.6,0.3,0.0); glVertex3f(x,y,z);
// cube half size=1 undistort using similarities like: y/x = y'/x'
if ((fabs(x)>=fabs(y))&&(fabs(x)>=fabs(z))){ y/=x; z/=x; if (x>=0) x=1.0; else x=-1.0; }
else if ((fabs(y)>=fabs(x))&&(fabs(y)>=fabs(z))){ x/=y; z/=y; if (y>=0) y=1.0; else y=-1.0; }
else if ((fabs(z)>=fabs(x))&&(fabs(z)>=fabs(y))){ x/=z; y/=z; if (z>=0) z=1.0; else z=-1.0; }
// bluish cube map
glColor3f(0.0,0.3,0.6); glVertex3f(x,y,z);
}
glEnd();
glPointSize(1.0);
glDisable(GL_BLEND);
glFlush();
SwapBuffers(hdc);
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int i;
float x,y,z,d;
RandSeed=8123456789;
glDepthFunc(GL_ALWAYS);
// glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glPointSize(2.0);
glBegin(GL_POINTS);
for (i=0;i<25000;i++)
{
// uniform random cartesian stars inside cube
x=(2.0*Random())-1.0;
y=(2.0*Random())-1.0;
z=(2.0*Random())-1.0;
// project on unit sphere
d=sqrt((x*x)+(y*y)+(z*z));
if (d<1e-3) { i--; continue; }
d=1.0/d;
x*=d; y*=d; z*=d;
// redish sphere map
glColor3f(0.6,0.3,0.0); glVertex3f(x,y,z);
// cube half size=1 undistort using similarities like: y/x = y'/x'
if ((fabs(x)>=fabs(y))&&(fabs(x)>=fabs(z))){ y/=fabs(x); z/=fabs(x); if (x>=0) x=1.0; else x=-1.0; }
else if ((fabs(y)>=fabs(x))&&(fabs(y)>=fabs(z))){ x/=fabs(y); z/=fabs(y); if (y>=0) y=1.0; else y=-1.0; }
else if ((fabs(z)>=fabs(x))&&(fabs(z)>=fabs(y))){ x/=fabs(z); y/=fabs(z); if (z>=0) z=1.0; else z=-1.0; }
// bluish cube map
glColor3f(0.0,0.3,0.6); glVertex3f(x,y,z);
}
glEnd();
glPointSize(1.0);
glDisable(GL_BLEND);
glFlush();
SwapBuffers(hdc);