Blitz GameDevСтатьи

Статья. Отражение луча от произвольной поверхности

Автор:

Статья. Отражение луча от произвольной поверхности

Как узнать, куда полетит шарик после столкновения с кубиком? Сразу вспоминаем фразу: «Угол отражения равен углу падения». Правильно!!! Но что делать, если мы не знаем угол падения? Всё просто…

Автор: Grover

Нам необходимо знать направление полета шарика. Для этого нам нужны три числа: на сколько мячик сместится по оси X, по оси Y и по оси Z. То есть, шарик вылетел из точки (0,0,0) после перемещения его координата (4,2,4) – это и есть вектор направления полета шарика. Обозначим его V(vx,vy,vz)

Если траектория шарика может меняться со временем (например, сдуло ветром), то вектор перемещения шарика можно вычислить путем вычитания предыдущих координат шарика из нынешних.

vx = x_new - x_old = 8 – 6 = 2
vy = y_new – y_old = 4 – 1 = 3
Так же вычисляется и vz.

Еще необходимо знать, как повернута плоскость кубика, с которой шарик столкнулся. Для этого существует вектор нормали. Это перпендикуляр к плоскости. Назовем его вектор N(nx,ny,nz).
В Blitz 3D вектор нормали можно узнать, используя команды CollisionNX(),CollisionNY(),CollisionNZ(). Используются они в цикле от 1 до CountCollisions(entity).

For k=1 To CountCollisions(sharik)

nx#=CollisionNX(sharik,k)
ny#=CollisionNY(sharik,k)
nz#=CollisionNZ(sharik,k)

Next

nx, ny, nz – вектор нормали плоскости, с которой столкнулся шарик.

Итак, мы знаем направление полета шарика vx, vy, vz и направление плоскости, с которой шарик столкнулся. Можно начинать считать:

For k=1 To CountCollisions(sharik)

; Находим векрот нормали плоскости
nx#=CollisionNX(sharik,k)
ny#=CollisionNY(sharik,k)
nz#=CollisionNZ(sharik,k)

; Находим вектор полета шарика
vx#=EntityX(sharik)-old_x#
vy#=EntityY(sharik)-old_y#
vz#=EntityZ(sharik)-old_z#

; Вычисление нового вектора полета шарика (1)
dot#=vx*nx+vy*ny+vz*nz
ex#=nx*dot
ey#=ny*dot
ez#=nz*dot
new_x=vx-ex*2
new_y=vy-ey*2
new_z=vz-ez*2
Next

New_x, new_y, new_z – новый вектор направления полета шарика.
Вычисления после нахождения векторов – это поворот вектора полета шарика вокруг вектора нормали плоскости на 180 градусов. Процесс вычисления поворота одного вектора вокруг другого на любой угол очень трудоемкий. Но так как у нас угол всегда постоянен, то формула сокращается до той, что представлена в программе выше (1).

Альфа ( угол падения) равен Бета (угол отражения).

Для направления шарика на новый вектор полета применим команду AlignToVector:

AlignToVector sharik,new_x,new_y,new_z,3

ВСЁ!!!
Ниже приведен листинг программы, в которой шарик летает внутри куба.


Graphics3D 640,480,0,2

Const t_pl1=1,t_cu=2

cu=CreateCube()
ScaleEntity cu,60,60,60
FlipMesh cu
EntityColor cu,100,100,100

piv=CreatePivot()
cam=CreateCamera(piv)
lit=CreateLight()
RotateEntity lit,45,45,0
pl1=CreateSphere()
ScaleEntity pl1,3,3,3
EntityRadius pl1,3
EntityColor pl1,0,0,255
MoveEntity cam,0,0,-150

speed#=2
TurnEntity pl1,Rnd(360),Rnd(360),Rnd(360)

EntityType pl1,t_pl1
EntityType cu,t_cu
Collisions t_pl1,t_cu,2,1

PointEntity cam,pl1
MoveMouse(200,200)
While Not KeyHit(1)

x#=MouseX()
y#=MouseY()

If y440 Then TurnEntity piv,-1,0,0
If x600 Then TurnEntity piv,0,1,0

old_x#=EntityX(pl1)
old_y#=EntityY(pl1)
old_z#=EntityZ(pl1)

MoveEntity pl1,0,0,speed

If EntityCollided(pl1,t_cu) Then
For k=1 To CountCollisions(pl1)

n_xx#=CollisionNX(pl1,k)
n_yy#=CollisionNY(pl1,k)
n_zz#=CollisionNZ(pl1,k)

xx#=EntityX(pl1)-old_x#
yy#=EntityY(pl1)-old_y#
zz#=EntityZ(pl1)-old_z#

dot#=xx*n_xx+yy*n_yy+zz*n_zz
ex#=n_xx*dot
ey#=n_yy*dot
ez#=n_zz*dot

xx=xx-ex*2
yy=yy-ey*2
zz=zz-ez*2

AlignToVector pl1,xx,yy,zz,3
MoveEntity pl1,0,0,speed
Exit
Next
EndIf

UpdateWorld
RenderWorld
Flip

Wend
End

11 октября 2006