Я строю простой город с помощью OpenGL и GLUT, я создал текстурированный купол неба, и теперь я хотел бы соединить его с плоской плоскостью, чтобы создать видимость горизонта. Чтобы дать относительный размер, небесный купол имеет радиус 3,0 с отключенной маской глубины, и к нему применяется только вращение камеры, и он находится над камерой. Здание имеет размер около 30,0, и я смотрю на него с y=500,0 вниз.
У меня есть плоскость земли размером 1000x1000, я текстурирую текстуру с разрешением 1024x1024, которая хорошо выглядит вблизи, когда я нахожусь на земле. Моя текстура загружается с помощью GL_REPEAT с координатой текстуры 1000, чтобы повторить ее 1000 раз.
У меня возникли некоторые проблемы с соединением купола неба с плоскостью земли. Я перечислю ряд вещей, которые я пробовал.
Проблемы:
1) Когда я поворачиваю курс, из-за квадратной формы самолета я вижу край, как на прикрепленном изображении, вместо плоского горизонта.
2) Вместо этого я попробовал круговую плоскость земли, но у меня получился кривой горизонт, который становится более извилистым, когда я взлетаю.
3) Чтобы избежать черного промежутка между бесконечным куполом неба и моей плоской плоскостью ограниченного размера, я устанавливаю ограничение на то, как далеко я могу летать, и немного сдвигаю купол неба по мере подъема, чтобы я не видел черный промежуток между бесконечным небосводом и моей плоской плоскостью, когда я высоко. Существуют ли другие способы плавного перехода плоскости в купол неба и устранения зазора, когда зазор различается по размеру в разных местах (например, круг, описывающий квадрат)? Я пытался применить цвет тумана к горизонту, но у меня получается фиолетовая дымка на белой земле.
4) Если я прикрепил землю в качестве нижней крышки полусферы Skydome, то при увеличении и уменьшении масштаба это выглядит странно, похоже, что текстурированная земля скользит и отсоединяется от моего здания.
5) Я попытался нарисовать бесконечно большую плоскость, используя концепцию точки схода, установив w=0. Визуализация бесконечно большой плоскости Горизонт выглядит плоским, но правильное текстурирование кажется сложным, поэтому я застрял с одним цветом.
6) Я отключил освещение для купола неба, если я хочу включить освещение для моей наземной плоскости, то при определенном угле наклона моя плоскость будет выглядеть черной, но мое небо все еще полностью освещено, и это выглядит неестественно.
7) Если я увеличу свою плоскость, например, 10000x10000, то горизонт будет казаться плоским, но, если я нажму клавишу со стрелкой, чтобы скорректировать мой курс, горизонт будет трястись в течение нескольких секунд, прежде чем стабилизироваться, в чем причина, и как я мог предотвратить это. Связанный с этим вопрос, похоже, что тайлинг и текстурирование 1000x1000 наземной плоскости и 10000x10000 не влияют на мою частоту кадров, почему это так? Разве больше плитки не означает больше работы?
8) Я читал о каком-то математическом подходе к вычислению прямоугольника отсечения для рисования горизонта, но мне интересно, есть ли более простые подходы http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/a-super-simple-method-for-creating-infinite-sce-r2769
В большинстве тредов, которые я читал о горизонте, говорилось: используйте скайбокс, используйте скайдоум, но я не наткнулся на конкретный учебник, в котором хорошо рассказывается о слиянии скайдома с большой наземной плоскостью. Указатель на такой учебник было бы здорово. Не стесняйтесь отвечать на любые части вопроса, указывая номер, я не хотел их разбивать, потому что все они связаны. Спасибо.
Вот некоторый соответствующий код в моей настройке:
void Display()
{
// Clear frame buffer and depth buffer
glClearColor (0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera.Update();
GLfloat accumulated_camera_rotation_matrix[16];
GetAccumulatedRotationMatrix(accumulated_camera_rotation_matrix);
SkyDome_Draw(accumulated_camera_rotation_matrix);
FlatGroundPlane_Draw();
// draw buildings
// swap buffers when GLUT_DOUBLE double buffering is enabled
glutSwapBuffers();
}
void SkyDome_Draw(GLfloat (&accumulated_camera_rotation_matrix)[16])
{
glPushMatrix();
glLoadIdentity();
glDepthMask(GL_FALSE);
glDisable(GL_LIGHTING);
glMultMatrixf(accumulated_camera_rotation_matrix);
// 3.0f is the radius of the skydome
// If we offset by 0.5f in camera.ground_plane_y_offset, we can offset by another 1.5f
// at skydome_sky_celing_y_offset of 500. 500 is our max allowable altitude
glTranslatef( 0, -camera.ground_plane_y_offset - camera.GetCameraPosition().y /c amera.skydome_sky_celing_y_offset/1.5f, 0);
skyDome->Draw();
glEnable(GL_LIGHTING);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glPopMatrix();
}
void GetAccumulatedRotationMatrix(GLfloat (&accumulated_rotation_matrix)[16])
{
glGetFloatv(GL_MODELVIEW_MATRIX, accumulated_rotation_matrix);
// zero out translation is in elements m12, m13, m14
accumulated_rotation_matrix[12] = 0;
accumulated_rotation_matrix[13] = 0;
accumulated_rotation_matrix[14] = 0;
}
GLfloat GROUND_PLANE_WIDTH = 1000.0f;
void FlatGroundPlane_Draw(void)
{
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, concreteTextureId);
glBegin(GL_QUADS);
glNormal3f(0, 1, 0);
glTexCoord2d(0, 0);
// repeat 1000 times for a plane 1000 times in width
GLfloat textCoord = GROUND_PLANE_WIDTH;
glVertex3f( -GROUND_PLANE_WIDTH, 0, -GROUND_PLANE_WIDTH);
// go beyond 1 for texture coordinate so it repeats
glTexCoord2d(0, textCoord);
glVertex3f( -GROUND_PLANE_WIDTH, 0, GROUND_PLANE_WIDTH);
glTexCoord2d(textCoord, textCoord);
glVertex3f( GROUND_PLANE_WIDTH, 0, GROUND_PLANE_WIDTH);
glTexCoord2d(textCoord, 0);
glVertex3f( GROUND_PLANE_WIDTH, 0, -GROUND_PLANE_WIDTH);
glEnd();
glDisable(GL_TEXTURE_2D);
}
Void Init()
{
concreteTextureId = modelParser->LoadTiledTextureFromFile(concreteTexturePath);
}
ModelParser::LoadTiledTextureFromFile(string texturePath)
{
RGBImage image; // wrapping 2-d array of data
image.LoadData(texturePath);
GLuint texture_id;
UploadTiledTexture(texture_id, image);
image.ReleaseData();
return texture_id;
}
void ModelParser::UploadTiledTexture(unsigned int &iTexture, const RGBImage &img)
{
glGenTextures(1, &iTexture); // create the texture
glBindTexture(GL_TEXTURE_2D, iTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// the texture would wrap over at the edges (repeat)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, img.Width(), img.Height(), GL_RGB, GL_UNSIGNED_BYTE, img.Data());
}