lanz |
Дата 28.2.2013, 16:46 |
|
6. Насчет вращений, лучше перемещать позицию камеры а не вращать систему координат. При реализованном вращении будет очень неестественно - (попробуй повернуть сначала по иксу на 180, потом по игреку на 180, потом опять по иксу).
Вообще это связано с тем что вращения в OpenGL это не совсем то же самое что эйлеровы углы (после каждого вращения оси перемещаются). Еще используют кватернионы, но я делал проще. Кусок старого кода на шарпе/OpenTK(Qt умеет все то же самое, смотри QMatrix4x4):
ArchX/Y - перемещение по дуге параллельной осям экрана.
class Camera { #region Constructors public Camera() { } public Camera(Vector3 pos, Vector3 look, Vector3 up) { pos_ = pos; look_at_ = look; up_ = up; } #endregion
public void Apply() { Matrix4 mv = Matrix4.LookAt(pos_, look_at_, up_);
GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref mv);
}
public void ArchY(float angle) { Vector3 lv = Vector3.Subtract(pos_, look_at_); Matrix4 rotation = Matrix4.CreateFromAxisAngle(Vector3.Cross(up_, lv), angle); transformAll(rotation); } public void ArchX(float angle) { ortogonalizeUp(); Matrix4 rotation = Matrix4.CreateFromAxisAngle(up_, angle); transformAll(rotation); }
#region Public properties public Vector3 Pos { get { return pos_; } set { pos_ = value; } } public Vector3 Up { get { return up_; } set { up_ = value; } } public Vector3 LookAt { get { return look_at_; } set { look_at_ = value; } } #endregion
#region private helpers private void transformAll(Matrix4 rotation) { up_ = Vector3.TransformVector(up_, rotation); Vector3 lv = Vector3.Subtract(pos_, look_at_); lv = Vector3.TransformVector(lv, rotation); pos_ = Vector3.Add(look_at_, lv); } private void ortogonalizeUp() { Vector3 lv = Vector3.Subtract(pos_, look_at_); up_ = Vector3.Cross (lv, Vector3.Cross(up_, lv)); up_.Normalize(); } #endregion
|
lanz |
Дата 28.2.2013, 16:14 |
|
Еще несколько мыслей: 1.
glEnable(GL_NORMALIZE);
Можно не использовать, поскольку QVector3D возвращает уже нормализованный вектор. Будет небольшой прирост производительности. 2.
glEnable( GL_LIGHTING );
GLfloat lightDiffuse [ 4 ] = { 0.8 , 0.8 , 0.8 , 1.0 }; GLfloat lightAmbient [ 4 ] = { 0.8 , 0.8 , 0.8 , 1.0 }; GLfloat lightSpecular[ 4 ] = { 0.5 , 0.8 , 0 , 1.0 }; GLfloat lightPosition[ 4 ] = { 0.0 , 0.0 , 100.0 , 0 };
glLightfv(GL_LIGHT1 , GL_POSITION , lightPosition); glLightfv(GL_LIGHT1 , GL_DIFFUSE , lightDiffuse); glLightfv(GL_LIGHT1 , GL_AMBIENT , lightAmbient); glLightfv(GL_LIGHT1 , GL_SPECULAR , lightSpecular);
glEnable( GL_LIGHT1 );
Это необязательно делать каждый кадр (все таки лишнее переключение состояний). Можно запихнуть в initializeGL. 3.
v00.normal(vectorAt(i+1, j-1), vectorAt(i+1, j+1), vectorAt(i-1, j-1));
Лучше наверное писать QVector3D::normal(...) а то немного запутывает читателя. 4.
swapBuffers();
Необязательно, т.к. QGLWidget сам свапает, после каждого вызова paintGL (если специально не отключать) 5. Ну и конечно шейдеры и VBO. Надо постепенно переходить на них (они не такие сложные как кажутся! ) , с ffp нормальный материал трудно будет сделать. |
ltise |
Дата 28.2.2013, 11:08 |
|
lanz, Вроде все заработало, осталось разобраться с материалами, но это уже не так критично
void GLWidget::iniCam() { rot_x = 152; rot_y -1.4; rot_z = 0; scale = 0.5; }
void GLWidget::initializeGL() { glEnable(GL_NORMALIZE); qglClearColor(Qt::black); glShadeModel (GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE);
}
void GLWidget::resizeGL(int w , int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode (GL_MODELVIEW); updateGL(); }
QVector3D GLWidget::vectorAt(int i, int j) const { double xx = i*2; double zz = j*2; int wi = j*logo.width() + i; double yy = wave[wi]; return QVector3D(xx, yy, zz); }
void GLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const int w = logo.width(); const int h = logo.height();
glMatrixMode ( GL_MODELVIEW ); glLoadIdentity( );
glRotatef(rot_x, 1.0f, 0.0f, 0.0f); glRotatef(rot_y, 0.0f, 1.0f, 0.0f); glRotatef(rot_z, 0.0f, 0.0f, 1.0f); glScalef(scale/w, scale/w, scale/w);
// Light settings glEnable( GL_LIGHTING );
GLfloat lightDiffuse [ 4 ] = { 0.8 , 0.8 , 0.8 , 1.0 }; GLfloat lightAmbient [ 4 ] = { 0.8 , 0.8 , 0.8 , 1.0 }; GLfloat lightSpecular[ 4 ] = { 0.5 , 0.8 , 0 , 1.0 }; GLfloat lightPosition[ 4 ] = { 0.0 , 0.0 , 100.0 , 0 };
glLightfv(GL_LIGHT1 , GL_POSITION , lightPosition); glLightfv(GL_LIGHT1 , GL_DIFFUSE , lightDiffuse); glLightfv(GL_LIGHT1 , GL_AMBIENT , lightAmbient); glLightfv(GL_LIGHT1 , GL_SPECULAR , lightSpecular);
glEnable( GL_LIGHT1 );
glTranslatef(-w, 0, 0.0f);
for(int j=1; j < h-2; ++j) { glBegin(GL_TRIANGLE_STRIP); for(int i=1; i < w-2; ++i) { QVector3D v00 = vectorAt(i , j); QVector3D v10 = vectorAt(i+1, j); QVector3D v11 = vectorAt(i+1, j+1); QVector3D v01 = vectorAt(i , j+1);
{ glVertex3f(v00.x(), v00.y(), v00.z());
QVector3D v = v00.normal(vectorAt(i+1, j-1), vectorAt(i+1, j+1), vectorAt(i-1, j-1)); glNormal3f(v.x(), v.y(), v.z()); }
{ glVertex3f(v01.x(), v01.y(), v01.z());
QVector3D v = v01.normal(vectorAt(i+1, j-1), vectorAt(i+1, j+1), vectorAt(i-1, j-1)); glNormal3f(v.x(), v.y(), v.z()); }
{ glVertex3f(v10.x(), v10.y(), v10.z());
QVector3D v = v10.normal(vectorAt(i+1, j-1), vectorAt(i+1, j+1), vectorAt(i-1, j-1)); glNormal3f(v.x(), v.y(), v.z()); }
{ glVertex3f(v11.x(), v11.y(), v11.z());
QVector3D v = v11.normal(vectorAt(i+1, j-1), vectorAt(i+1, j+1), vectorAt(i-1, j-1)); glNormal3f(v.x(), v.y(), v.z()); } } glEnd(); } swapBuffers(); }
|
lanz |
Дата 27.2.2013, 14:56 |
|
Нормаль назначается на каждую вершину, это да. При расчете освещения OpenGL интерполирует нормали с краев полигона (так же как и цвет). Поэтому если расчитывать так как я предложил - получится что то вроде левого рисунка, будут полосы вдоль граней На картинке в правом случае более правильный вариант, получится лучшее сглаживание. |
ltise |
Дата 27.2.2013, 14:10 |
|
Цитата(lanz @ 27.2.2013, 9:03) Ох с чего же начать 5. Что самое главное для освещения? Правильно, нормали
С нормалями все вроде стало понятнее, как-то я их проигнорировал..
Но я так понимаю, что нормаль должна строиться к каждому вертексу ? |
lanz |
Дата 27.2.2013, 9:03 |
|
Ох с чего же начать 1. void GLWidget::saveGLState() { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); }
void GLWidget::restoreGLState() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); }
Push и Pop должны идти в разном порядке (см. как работает стек (последний пришел-первый ушел)
2. Сохранение состояния не нужны (по крайней мере сейчас) 3. Всю настройку источников света можно вынести в initializeGL 4. Чуть покрутил коэффициенты, убрал мусор
void GLWidget::initializeGL() { makeCurrent (); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepth(1.0f); glEnable (GL_NORMALIZE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
// Enable light and set up 2 light sources (GL_LIGHT0 and GL_LIGHT1) glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); float ambientLight0[] = { 0.25f, 0.25f, 0.25f, 0.6f }; float diffuseLight0[] = { 0.2f, 0.2f, 0.2f, 0.1f }; float specularLight0[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float position0[] = { 0, 0, -40.0f, 1.0f };
// Assign created components to GL_LIGHT0 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight0); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight0); glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight0); glLightfv(GL_LIGHT0, GL_POSITION, position0);
// //light model properties // float model_ambient[] = {0.4f, 0.4f, 0.4f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, model_ambient); //small white ambient light
// // meterial properties // float no_mat[] = {0.0f, 0.0f, 0.0f, 1.0f}; float mat_ambient[] = {0.7f, 0.7f, 0.7f, 0.1f}; float mat_diffuse[] = {0.1f, 0.5f, 0.8f, 0.1f}; float mat_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; float high_shininess = 0.1f;
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
} 5. Что самое главное для освещения? Правильно, нормали Примерно так, неидеально конечно:
void GLWidget::paintGL() { makeCurrent();
glClearColor(.0, 0.0, .0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f (1.0, 1.0, 1.0, 1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 10, 100); glTranslatef(0.0f, 0.0f, -15.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width(), height());
const int w = logo.width(); const int h = logo.height(); glRotatef(rot_x, 1.0f, 0.0f, 0.0f); glRotatef(rot_y, 0.0f, 1.0f, 0.0f); glRotatef(rot_z, 0.0f, 0.0f, 1.0f); glScalef(scale/w, scale/w, scale/w); glTranslatef(-w+1, 0, 0.0f);
for(int j=0; j < h-1; ++j) {
glBegin(GL_TRIANGLE_STRIP); for(int i=0; i < w-1; ++i) { double x = i; double y = j; GLfloat v1[] = {0,0,0}; GLfloat v2[] = {0,0,0}; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); v1[0] -= xx; v1[1] -= yy; v1[2] -= zz; }
x = i+1; y = j; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); v1[0] += xx; v1[1] += yy; v1[2] += zz; v2[0] -= xx; v2[1] -= yy; v2[2] -= zz; }
x = i; y = j+1; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); v2[0] += xx; v2[1] += yy; v2[2] += zz; } GLfloat normal[] = {v1[1]*v2[2] - v2[2]*v1[1], v1[2]*v2[0] - v1[0]*v2[2], v1[0]*v2[1]- v1[1]*v2[0]}; glNormal3fv (normal); x = i+1; y = j+1; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); } } glEnd();
} //restoreGLState(); }
6. Что почитать? http://math.hws.edu/graphicsnotes/c4/s3.html (секция 4.3.4 очень рекомендуется) http://www.glprogramming.com/red/chapter05.html http://devernay.free.fr/cours/opengl/materials.html например. 7. Можно еще покрутить коэффициенты, но чтобы была реалистичная сталь, придется делать отражение (cube map например). Ну или текстуру. |
ltise |
Дата 26.2.2013, 16:58 |
|
Цитата(lanz @ 25.2.2013, 9:16) А как выглядит класс камеры, как рендеришь сцену из карты глубины?
Немного изменил пример pbuffer2:
Целиком проект тут архив:
Не врубаюсь - как настроить источник света, чтобы волна была металлической и смотрелась реалестично (материал - сталь)... Счас вообще непойми что получается.. пробовал по разному...
void GLWidget::paintGL() { saveGLState();
makeCurrent();
glClearColor(.0, 0.0, .0, 0.1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 10, 100); glTranslatef(0.0f, 0.0f, -15.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width(), height());
glBindTexture(GL_TEXTURE_2D, dynamicTexture); glEnable(GL_TEXTURE_2D); glEnable(GL_MULTISAMPLE); glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
const int w = logo.width(); const int h = logo.height();
glRotatef(rot_x, 1.0f, 0.0f, 0.0f); glRotatef(rot_y, 0.0f, 1.0f, 0.0f); glRotatef(rot_z, 0.0f, 0.0f, 1.0f); glScalef(scale/w, scale/w, scale/w);
glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST);
// //light properties // float ambient[] = {0.0f, 0.0f, 0.0f, 1.0f}; float diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; float specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; float position[] = {0.0f, 10.0f, 0, .0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glLightfv(GL_LIGHT0, GL_POSITION, position);
// //light model properties // float model_ambient[] = {0.4f, 0.4f, 0.4f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, model_ambient); //small white ambient light
// // meterial properties // float no_mat[] = {0.0f, 0.0f, 0.0f, 1.0f}; float mat_ambient[] = {0.7f, 0.7f, 0.7f, 1.0f}; float mat_diffuse[] = {0.1f, 0.5f, 0.8f, 1.0f}; float mat_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; float high_shininess = 100.0f;
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
// //draw wave // glTranslatef(-w+1, 0, 0.0f);
for(int j=0; j < h-1; ++j) {
glBegin(GL_TRIANGLE_STRIP); for(int i=0; i < w-1; ++i) { double x = i; double y = j; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); }
x = i+1; y = j; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); }
x = i; y = j+1; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); }
x = i+1; y = j+1; { GLfloat xx = x*2; GLfloat zz = y*2; int wi = y*w + x; GLfloat yy = wave[wi]; glVertex3f(xx, yy, zz); } } glEnd(); }
restoreGLState(); }
|
lanz |
Дата 25.2.2013, 9:16 |
|
А как выглядит класс камеры, как рендеришь сцену из карты глубины? |
ltise |
Дата 22.2.2013, 18:17 |
|
Привет!
подскажите плиз, может у кого гденить завалялся пример реализации движения камеры над сценой ?
неделю уже собираю примеры из разных источников - получается какая-то фигня полная в примерах Qt реализации движения камеры к сожалению нету....
Мне надо сделать-то в одном месте программы визуализацию профиля по grayscale пиксмапу в качестве карты глубин... и забыть
Заранее спасибо |
Просмотр темы полностью (откроется в новом окне) |
|