Ir ao conteúdo
  • Cadastre-se

C++ como funciona o Raycasting?


Cambalinho

Posts recomendados

como funciona o Raycasting?
parece que usam 1 mapa 2D para desenhar o 3D.. mas ainda não entendi algumas coisas:
1 - tenho de dividir o mapa por grids de 30X30(ou isso)?
2 - para verificar onde estão as paredes, tenho de verificar se ponta da linha colide com a parede... aumento a linha pelo tamanho do grid, certo?
3 - a verificação, usando a linha, é de 180 graus?(-90 a 90)
4 - quando a linha colide com a parede:
- com saber onde tocou para entender que linha, vertical, da imagem devo desenhar?
- o zoom é o comprimento da linha, mas como fazer esses cálculos para poder esticar a linha? estes cálculos são dependentes da resolução do jogo?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Recomendo a ótima série de livros-tutoriais (gratuitos!) Ray Tracing in One Weekend. Em inglês. Literalmente num final de semana você mata a curiosidade de como projetar raios, interceptar objetos, modelar iluminação etc. e tudo isso utilizando apenas a CPU (mas traduzir o conteúdo pra shaders e rodar numa GPU tampouco vai ser um problema).

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...
  • 2 semanas depois...

estou a tentar implementar o raycasting, mas ainda tenho maus resultados :(

Public Sub RayCasting()
    Dim r As Integer
    Dim mx As Integer
    Dim my As Integer
    Dim mp As Integer
    Dim dof As Integer
    Dim mapx As Integer
    Dim mapy As Integer
    
    Dim rx As Double
    Dim ry As Double
    Dim ra As Double
    Dim x0 As Double
    Dim y0 As Double
    
    ra = PlayerAngle
    For r = 0 To 0.9
        'Check Horizontal Lines:
        dof = 0
        Dim aTan As Double
        aTan = -1 / Tan(ra)
        If (ra > PI) Then 'Loking up
            ry = BitShiftLeft(BitShiftRight(Floor(PlayerPosY), 6), 6) - 0.0001
            rx = (PlayerPosX - ry) * aTan + PlayerPosX
            y0 = -MapResolution
            x0 = -y0 * aTan
        End If
        
        If (ra < PI) Then 'Loking down
            ry = BitShiftLeft(BitShiftRight(Floor(PlayerPosY), 6), 6) + MapResolution
            rx = (PlayerPosX - ry) * aTan + PlayerPosX
            y0 = MapResolution
            x0 = y0 * aTan
        End If
        
        If (ra = 0 Or ra = PI) Then 'Loking straight left or right:
            rx = PlayerPosX
            ry = PlayerPosY
            dof = 8
        End If
        While (dof < 8)
            mx = BitShiftRight(rx, 6)
            my = BitShiftRight(ry, 6)
            mp = my * mapx + mx
            Debug.Print CStr(mapx)
            If ((mp < (mapx * mapy)) And MapLevel(mapy, mapx) = 1) Then 'hit wall
              dof = 8
            Else
                rx = rx + x0
                ry = ry + y0
                dof = dof + 1
            End If
            Me.Line (PlayerPosX, PlayerPosY)-(rx, ry), vbRed
        Wend
    Next
End Sub

este código é VB6... mas fora isso.... eu ainda não entendi como se calcula isto... alguém me pode explicar melhor?

Link para o comentário
Compartilhar em outros sites

já consegui meter o codigo a funcionar:
 

Option Explicit

Private Type POINTAPI
    x As Long
    y As Long
End Type


Private Declare Function LineTo Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function MoveToEx Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByRef lpPoint As POINTAPI) As Long


Dim ScreenWidth As Integer
Dim ScreenHeight As Integer
Dim ScreenHalfHeight As Integer

Dim RenderDelay As Integer

Dim RayCastingPrecision As Integer

Dim PlayerFOV As Integer
Dim PlayerPosX As Integer
Dim PlayerPosY As Integer
Dim PlayerAngle As Double
Dim PlayerSpeedMovement As Double
Dim PlayerSpeedRotation As Double

Dim LevelMap(10) As Variant
Dim blnGameLoop As Boolean


Const PI As Double = 3.14159265359
Private Function DegreesToRadians(Degrees As Double) As Double
    DegreesToRadians = Degrees * (PI / 180)
End Function

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
        Dim PlayerCos As Double
        Dim PlayerSin As Double
        Dim NewX As Integer
        Dim NewY As Integer
    If (KeyCode = vbKeyEscape) Then
        blnGameLoop = False
        End
    ElseIf (KeyCode = vbKeyUp) Then
        
        PlayerCos = Cos(DegreesToRadians(PlayerAngle)) * PlayerSpeedMovement
        PlayerSin = Sin(DegreesToRadians(PlayerAngle)) * PlayerSpeedMovement
        
        NewX = PlayerPosX + PlayerCos
        NewY = PlayerPosY + PlayerSin

        'Verficia colisão do player
        If (LevelMap(Fix(NewY))(Fix(NewX)) = 0) Then
        
            PlayerPosX = NewX
            PlayerPosY = NewY
        End If
    ElseIf (KeyCode = vbKeyDown) Then
        
        PlayerCos = Cos(DegreesToRadians(PlayerAngle)) * PlayerSpeedMovement
        PlayerSin = Sin(DegreesToRadians(PlayerAngle)) * PlayerSpeedMovement
        
        NewX = PlayerPosX - PlayerCos
        NewY = PlayerPosY - PlayerSin
        'Verficia colisão do player
        If (LevelMap(Fix(NewY))(Fix(NewX)) = 0) Then
        
            PlayerPosX = NewX
            PlayerPosY = NewY
        End If
    ElseIf (KeyCode = vbKeyLeft) Then
        PlayerAngle = PlayerAngle - PlayerSpeedRotation
    ElseIf (KeyCode = vbKeyRight) Then
        PlayerAngle = PlayerAngle + PlayerSpeedRotation
    End If
End Sub

Private Sub drawLine(x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, color As ColorConstants)
    Me.Line (x1, y1)-(x2, y2), color
End Sub

Private Sub RayCasting()
    Dim RayAngle As Double
    Dim RayCos As Double
    Dim RaySin As Double
    RayAngle = PlayerAngle - PlayerFOV / 2
    RayCos = Cos(DegreesToRadians(RayAngle)) / RayCastingPrecision
    RaySin = Sin(DegreesToRadians(RayAngle)) / RayCastingPrecision
    Dim RayCount As Integer
    
    For RayCount = 0 To ScreenWidth
        Dim RayX As Double
        Dim RayY As Double
        RayX = PlayerPosX
        RayY = PlayerPosY
        
        'Detectar se atinge a parede:
        Dim blnWallHit As Variant
        blnWallHit = 0
        While (blnWallHit < 1)
        
            RayX = RayX + RayCos
            RayY = RayY + RaySin
            blnWallHit = LevelMap(Fix(RayY))(Fix(RayX))
        Wend
        
        'calcular a distancia a tamanho da linha:
        Dim Distance As Double
        Distance = Sqr((PlayerPosX - RayX) ^ 2 + (PlayerPosY - RayY) ^ 2)
        Distance = Distance * Cos(DegreesToRadians(RayAngle - PlayerAngle))
        
        Dim WallHeight As Double
        WallHeight = Fix(ScreenHalfHeight / Distance)
        If (WallHeight > ScreenHalfHeight) Then WallHeight = ScreenHalfHeight
        
        'Desenhar a linha da parede:
        If (blnWallHit = 1) Then
            drawLine RayCount, ScreenHalfHeight - WallHeight, RayCount, ScreenHalfHeight + WallHeight, vbYellow
        ElseIf (blnWallHit = 2) Then
            drawLine RayCount, ScreenHalfHeight - WallHeight, RayCount, ScreenHalfHeight + WallHeight, vbGreen
        End If
        blnWallHit = 0
        'Incrementar
        RayAngle = RayAngle + PlayerFOV / ScreenWidth
    Next RayCount
End Sub

Private Sub Form_Load()
    ScreenWidth = 300
    ScreenHeight = 200
    ScreenHalfHeight = ScreenHeight / 2
    
    RenderDelay = 16
    RayCastingPrecision = 10
    PlayerFOV = 60
    PlayerPosX = 5
    PlayerPosY = 3
    PlayerAngle = 0
    PlayerSpeedMovement = 0.5
    PlayerSpeedRotation = 0.2
    
    LevelMap(0) = Array(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)
    LevelMap(1) = Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    LevelMap(2) = Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    LevelMap(3) = Array(1, 0, 0, 0, 2, 0, 0, 0, 0, 1)
    LevelMap(4) = Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    LevelMap(5) = Array(1, 0, 0, 1, 0, 0, 1, 0, 0, 1)
    LevelMap(6) = Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    LevelMap(7) = Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    LevelMap(8) = Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    LevelMap(9) = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
    
    Me.Show
    
    blnGameLoop = True
    
    While (blnGameLoop = True)
        Me.Cls
        RayCasting
        DoEvents
    Wend
End Sub

Private Sub Form_Unload(Cancel As Integer)
    blnGameLoop = False
End Sub

mas noto 2 erros:
1 - o efeito de peixe não foi resolvido;
2 -  o que se passa com este 'while' e 'if'?

Private Sub RayCasting()
    Dim RayAngle As Double
    Dim RayCos As Double
    Dim RaySin As Double
    RayAngle = PlayerAngle - PlayerFOV / 2
    RayCos = Cos(DegreesToRadians(RayAngle)) / RayCastingPrecision
    RaySin = Sin(DegreesToRadians(RayAngle)) / RayCastingPrecision
    Dim RayCount As Integer
    
    For RayCount = 0 To ScreenWidth
        Dim RayX As Double
        Dim RayY As Double
        RayX = PlayerPosX
        RayY = PlayerPosY
        
        'Detectar se atinge a parede:
        Dim blnWallHit As Variant
        blnWallHit = 0
        While (blnWallHit < 1)
        
            RayX = RayX + RayCos
            RayY = RayY + RaySin
            blnWallHit = LevelMap(Fix(RayY))(Fix(RayX))
        Wend
        
        'calcular a distancia a tamanho da linha:
        Dim Distance As Double
        Distance = Sqr((PlayerPosX - RayX) ^ 2 + (PlayerPosY - RayY) ^ 2)
        Distance = Distance * Cos(DegreesToRadians(RayAngle - PlayerAngle))
        
        Dim WallHeight As Double
        WallHeight = Fix(ScreenHalfHeight / Distance)
        If (WallHeight > ScreenHalfHeight) Then WallHeight = ScreenHalfHeight
        
        'Desenhar a linha da parede:
        If (blnWallHit = 1) Then
            drawLine RayCount, ScreenHalfHeight - WallHeight, RayCount, ScreenHalfHeight + WallHeight, vbYellow
        ElseIf (blnWallHit = 2) Then
            drawLine RayCount, ScreenHalfHeight - WallHeight, RayCount, ScreenHalfHeight + WallHeight, vbGreen
        End If
        blnWallHit = 0
        'Incrementar
        RayAngle = RayAngle + PlayerFOV / ScreenWidth
    Next RayCount
End Sub

porque não consigo meter 2 linhas verticais com cores diferentes... fica tudo de 1 cor(mesmo o anterior) :( só se os cálculos estão errados :(

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!