Страница: 1 | 2 |
Вопрос: Перспектива (трехмерная графика)
Добавлено: 02.11.05 18:39
Автор вопроса: Victor | Web-сайт:
Я тут начал писать элементарный 3-хмерный движок. Пока он занимается только отображением точек в пространстве.
Вот вроде все написал, но столкнулся с проблемой.
перспектива корявая.
Очень сильная. Когда точки подползают к краю экрана, фигура неестественно вытягивается.
Это поправляемо простым растягиванием (сужением кругозора). Но беда в том, что когда вроде хорошо настроил, то при плавании взникает эффект подзорной трубы.
Подскажите, как правильно настроить перспективу.
Ответы
Всего ответов: 23
Номер ответа: 1
Автор ответа:
Victor
ICQ: 345743490
Вопросов: 42
Ответов: 385
Web-сайт:
Профиль | | #1
Добавлено: 02.11.05 21:09
Да. И еще. Как быть с вращением? Вокруг какой точки крутить вид при движении мышью?
Номер ответа: 2
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #2
Добавлено: 02.11.05 22:05
Ты где програмишь в директе или open GL?
Приведи пример кода, если не секрет.
Номер ответа: 3
Автор ответа:
Victor
ICQ: 345743490
Вопросов: 42
Ответов: 385
Web-сайт:
Профиль | | #3
Добавлено: 02.11.05 23:27
GDI. И ничего больше.
Кажется, разобрался сам. Взгляни.
http://vt-dbnz.narod.ru/persp.rar
(18kb)
Че-то все равно перспектива подхрамывает, хотя уже не так плохо.
Номер ответа: 4
Автор ответа:
Victor
ICQ: 345743490
Вопросов: 42
Ответов: 385
Web-сайт:
Профиль | | #4
Добавлено: 02.11.05 23:32
Вот самое интересное.
Type TriVector
x As Double
y As Double
z As Double
End Type
Type ColorPoint
Pos As TriVector
Color As RGBQUAD
End Type
Type typLookVectorReserved
vMoveAhead As TriVector
End Type
Type typLookVector
Org As TriVector
ZVector As TriVector
YVector As TriVector
XVector As TriVector
Length As Double
Reserved As typLookVectorReserved
MoveAhead As Double
PixelsPerMeter As Double
End Type
Public Type PointZ
x As Double
y As Double
z As Double
End Type
Public LookVector As typLookVector
Public Function PerspectiveTransform(Vct As TriVector, _
Result As PointZ) As Boolean
Dim VctX As TriVector
Dim VctY As TriVector
Dim VctZ As TriVector
Dim r As TriVector
Dim rz As TriVector
Dim lrz As Double
Dim k As Double
r.x = Vct.x - LookVector.Org.x + LookVector.Reserved.vMoveAhead.x
r.y = Vct.y - LookVector.Org.y + LookVector.Reserved.vMoveAhead.y
r.z = Vct.z - LookVector.Org.z + LookVector.Reserved.vMoveAhead.z
lrz = ProjectVector(r, LookVector.ZVector, rz)
If lrz < 0.001 * LookVector.Length Then
PerspectiveTransform = False
Exit Function
Else
PerspectiveTransform = True
'resume
End If
Result.z = VectorLength(r)
k = LookVector.Length / lrz
r.x = r.x * k
r.y = r.y * k
r.z = r.z * k
Result.x = ProjectVector(r, LookVector.XVector, rz)
Result.y = ProjectVector(r, LookVector.YVector, rz)
End Function
Public Function ProjectVector(ByRef VectorToProject As TriVector, _
ByRef VectorProjectTo As TriVector, _
ByRef Result As TriVector) As Double
Dim L As Double
Dim tmpVec As TriVector
Dim t As Double
tmpVec = VectorProjectTo
Normalize tmpVec
t = tmpVec.x * VectorToProject.x + _
tmpVec.y * VectorToProject.y + _
tmpVec.z * VectorToProject.z
Result.x = tmpVec.x * t
Result.y = tmpVec.y * t
Result.z = tmpVec.z * t
ProjectVector = t
End Function
Public Sub DrawPixels(ByRef Data() As RGBQUAD, _
ByRef Points() As ColorPoint, _
Optional ByVal Cls As Boolean)
Dim w As Long, h As Long
Dim i As Long
Dim x As Long, y As Long
Dim cx As Long, cy As Long
Dim pz As PointZ
w = UBound(Data, 1) + 1
h = UBound(Data, 2) + 1
If Cls Then
ZeroMemory Data(0, 0), w * h * 4
End If
If AryDims(AryPtr(Points)) <> 1 Then
Exit Sub
End If
cx = w \ 2
cy = h \ 2
For i = 0 To UBound(Points)
If PerspectiveTransform(Points(i).Pos, pz) Then
x = cx + pz.x * LookVector.PixelsPerMeter
y = cy - pz.y * LookVector.PixelsPerMeter
If x >= 0 And y >= 0 And x < w And y < h Then
 ata(x, y) = Points(i).Color
End If
End If
Next i
End Sub
Вопрос в том, как правильно рассчитать LookVector.Length.
Номер ответа: 5
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #5
Добавлено: 03.11.05 00:03
Супер!
Но, извини конечно, нафига столько мучений и изобретений велосипеда?
Есть какие - то веские причины использовать GDI?
Я в подобных случаях работаю с open GL. Никаких проблем с перспективой и скорость значительно выше?
Так на всякий случай, на VB это тоже можно( в смысле open GL) без всяких проблем.
Номер ответа: 6
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #6
Добавлено: 03.11.05 00:06
Я пока в твой код внимательно не смотрел, но корректно спроецировать 3D сцену на экран (2D) еще та задачка.
Номер ответа: 7
Автор ответа:
Victor
ICQ: 345743490
Вопросов: 42
Ответов: 385
Web-сайт:
Профиль | | #7
Добавлено: 03.11.05 00:23
Хочешь сказать, что если бы я взял в руки OpenGL, мне бы не пришлось возится с векторами? Как-то мне с трудом верится. Почитать что ли ради интереса этот OpenGL...
Номер ответа: 8
Автор ответа:
Victor
ICQ: 345743490
Вопросов: 42
Ответов: 385
Web-сайт:
Профиль | | #8
Добавлено: 03.11.05 00:28
Мне тоже раньше так казалось. А тут вдруг как-то вроде все не так уж сложно... Всего лишь вектора, да вектора. Считаю себе проекции, и все.
Вообще, 3D-графику первый раз программирую. Уж никогда бы не подумал, что возникнут проблемы с формой перспективы, а они возникли. Мало того, они оказались самыми сложными (для меня).
Номер ответа: 9
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #9
Добавлено: 03.11.05 00:56
Да нет, смотря как возится. Но OpenGL предоставляет мощный математический аппарат для работы в 3D. Если хочешь разобраться с проекциями - посмотри как это сделано в OpenGL.
Если резюмировать - то OpenGL освобаждает от рутины, позволяя концентрироваться на реализации задачи. К примеру ID не считала зазорным использовать эту библиотеку.
Очень неплохие русские доки по ней есть на RSDN.
Номер ответа: 10
Автор ответа:
Страшный Сон
Вопросов: 46
Ответов: 848
Профиль | | #10
Добавлено: 03.11.05 11:46
У меня тоже есть небольшой пример 3D-движка... по сути, я недавно начал делать спрайтовый 2D-движок, но благодаря Z-буферу он может отображать и 3D. Там в пространстве размещены спрайты-шары, которые притягиваются друг к другу до определенного предела, а потом отталкиваются, стремясь сохранить постоянное расстояние между собой. А искажение перспективы - явление нормальное, оно есть везде, во всех играх.
Номер ответа: 11
Автор ответа:
Pashenko
ICQ: 176176951
Вопросов: 14
Ответов: 655
Профиль | | #11
Добавлено: 03.11.05 12:00
Чтобы не было искажения, необходимо учитывать положение глаз пользователя.
Например, мои глаза находятся на расстоянии ~0,5м от экрана, перпендикуляр, опущенный на экран пересекает его (экран) по горизонтали по центру, по вертикали в верхней четверти.
Иными словами, при запуске программы спрашиваешь пользователя о положении еглаз и отрисовываешь проекции на экран для этой точки. Если всё грамотно сделать, никаких искажений не будет.
Номер ответа: 12
Автор ответа:
GSerg
Вопросов: 0
Ответов: 1876
Профиль | | #12
Добавлено: 03.11.05 12:29
Вообще-то "глаза пользователя" с точки зрения игры - это плоскость монитора...
Номер ответа: 13
Автор ответа:
Pashenko
ICQ: 176176951
Вопросов: 14
Ответов: 655
Профиль | | #13
Добавлено: 03.11.05 12:41
Вот из-за этого искажения и получаются
А вообще-то, если проекция на плоскость идёт параллельными лучами, то и перспективы никакой не будет.
Перспектива появится только при проецировании сходящимися лучами (в идеальнос случае лучи сходятся в точку, но могут быть и другие варианты).Соответственно, точка пересечения проецирующих лучей должна находиться ПОЗАДИ плоскости, на которую проецируем. Если эта точка находится НА ПЛОСКОСТИ, то, что бы не проецировали, получим только эту точку и больше ничего. Если точка находится ПЕРЕД плоскостью, получим перевёрнутое изображение проецируемых объектов.
Вот так-то...
Обычная геометрия.
Номер ответа: 14
Автор ответа:
Pashenko
ICQ: 176176951
Вопросов: 14
Ответов: 655
Профиль | | #14
Добавлено: 03.11.05 12:47
Кстати, в наших с вами глазах плоскость проецирования (сетчатка) находится на задней поверхности глаза, а точка пересечения проецирующих лучей внутри глаза, то есть ПЕРЕД плоскостью. Соответственно, изображение на сетчатке получается перевёрнутым. Ещё раз изображение переворачивает мозг, на основе жизненного опыта (новорождённые, например, так и видят весь мир перевёрнутым вверх ногами).
Номер ответа: 15
Автор ответа:
Victor
ICQ: 345743490
Вопросов: 42
Ответов: 385
Web-сайт:
Профиль | | #15
Добавлено: 03.11.05 13:44
Вот результаты попыток.
Например, мои глаза находятся на расстоянии ~0,5м от экрана, перпендикуляр, опущенный на экран пересекает его (экран) по горизонтали по центру, по вертикали в верхней четверти.
Иными словами, при запуске программы спрашиваешь пользователя о положении еглаз и отрисовываешь проекции на экран для этой точки. Если всё грамотно сделать, никаких искажений не будет.
Да, я так делал. И вроде как их нет, но эффект подзорной трубы угнетает. Потом я догадался написать туда расстояние глаза-монитор/2, и все стало нормально (по крайней мере перспектива приемлимая и эффект подзорной трубы не слишком силен). Но вот почему именно d/2?
У меня глазами является точка. И вокруг нее производится поворот. Когда у меня был эффект подзорной трубы, я подумал, не сделать ли мне так, чтобы камера вращалась вокруг центральной точки этой плоскости. Но это выглядело уродски по той простой причине, что для этого нужен на экране герой, вокруг которого будет крутиться камера, а у меня его нет (и не будет).
ЗЫ. Загнал я туда линии напряженности. Выглядит неплохо. Для вида еще туман сделал. Не хватает только Z-буфера. Но это потом как-нибудь.
ЗЗЫ. Работает медленно. Там 36782 точки, и даже exe немного подтормаживает. А в среде разработки все еще хуже. И это, надо заметить, после ускорения алгоритма - ненужных вычислений там уже почти нет.
Смотрите.
http://vt-dbnz.narod.ru/field.rar
(22kb)
Там строятся линии напряженности поля 1/r. И в программе можно легко поправить на 1/r^2.