[Gambas-user] gb3: OpenGL, rotation and translation of matrix affecting multiple quads

Kevin Fishburne kevinfishburne at ...1887...
Wed Aug 10 18:58:16 CEST 2011


On 08/09/2011 02:02 AM, tommyline at ...2340... wrote:
>
>
> ----- Original Message -----
> From: "Kevin Fishburne"<kevinfishburne at ...1887...>
> To: gambas-user at lists.sourceforge.net
> Sent: Tuesday, 9 August, 2011 2:44:10 AM
> Subject: [Gambas-user] gb3: OpenGL, rotation and translation of matrix affecting multiple quads
>
> Here's looking at you Tomek, although anyone who knows give me a shout out.
>
> I'm using a nested For...Next loop to render a 2D grid of quads. I need
> the grid of quads to be rotated about its "center", but would like to
> make a single matrix transformation instead of doing one for each quad.
> Is this possible, and if so, how? Even if I have to do multiple matrix
> transformations, that is fine, as long as I don't have to do one for
> every single quad.
>
> Right now my code (removing all experiments, just bare code) looks like
> this:
>
> Public Sub Tile_Grid()
>
>     ' Draw tile grid texture array in render window.
>
>     ' General declarations.
>     Dim TileGridX As Short  ' Tile in tile grid texture array being rendered.
>     Dim TileGridY As Short  ' Tile in tile grid texture array being rendered.
>     Dim TileGridX1 As Short ' Starting tile in tile grid texture array to
> be rendered.
>     Dim TileGridY1 As Short ' Starting tile in tile grid texture array to
> be rendered.
>     Dim TileGridX2 As Short ' Ending tile in tile grid texture array to
> be rendered.
>     Dim TileGridY2 As Short ' Ending tile in tile grid texture array to
> be rendered.
>     Dim PixelX As Short     ' Pixel coordinates of tile being rendered.
>     Dim PixelY As Short     ' Pixel coordinates of tile being rendered.
>     Dim OffsetX As Short    ' Number of pixels to offset matrix to
> accommodate camera position and tile grid resolution.
>     Dim OffsetY As Short    ' Number of pixels to offset matrix to
> accommodate camera position and tile grid resolution.
>     Dim StepX As Short      ' Direction to step through tile grid texture
> array loop.
>     Dim StepY As Short      ' Direction to step through tile grid texture
> array loop.
>
>     ' Assign initial values to variables.
>     TileGridX1 = TileGrid.CenterX
>     TileGridY1 = TileGrid.CenterY
>     TileGridX2 = TileGrid.CenterX + TileGrid.Size - 1
>     TileGridY2 = TileGrid.CenterY + TileGrid.Size - 1
>     If TileGridX1<  TileGridX2 Then
>       StepX = 1
>     Else
>       StepX = -1
>     Endif
>     If TileGridY1<  TileGridY2 Then
>       StepY = 1
>     Else
>       StepY = -1
>     Endif
>
>     ' Rotate and translate matrix.
>     Gl.LoadIdentity()
>     Gl.Translatef(- OffsetX, - OffsetY, 0)
>     Gl.Rotatef(- Client.Orientation, 0, 0, 1)
>     Gl.Translatef(OffsetX, OffsetY, 0)
>
>     ' Render specified tiles in cell grid to tile grid.
>     For TileGridY = TileGridY1 To TileGridY2 Step StepY
>       For TileGridX = TileGridX1 To TileGridX2 Step StepX
>         ' Select texture using its ID.
>         Gl.BindTexture(Gl.GL_TEXTURE_2D, tTileGrid[Convert.Wrap_Short(0,
> TileGrid.Size - 1, TileGridX), Convert.Wrap_Short(0, TileGrid.Size - 1,
> TileGridY)][0])
>         ' Create the quad the texture is drawn on.
>         Gl.Begin(Gl.GL_QUADS)
>           ' Bottom-left vertex.
>           Gl.TexCoord2i(0, 0)
>           Gl.Vertex3i(PixelX + OffsetX, PixelY + OffsetY, 0)
>           ' Bottom-right vertex.
>           Gl.TexCoord2i(1, 0)
>           Gl.Vertex3i(PixelX + OffsetX + 128, PixelY + OffsetY, 0)
>           ' Top-right vertex.
>           Gl.TexCoord2i(1, 1)
>           Gl.Vertex3i(PixelX + OffsetX + 128, PixelY + OffsetY + 128, 0)
>           ' Top-left vertex.
>           Gl.TexCoord2i(0, 1)
>           Gl.Vertex3i(PixelX + OffsetX, PixelY + OffsetY + 128, 0)
>         Gl.End()
>         ' Adjust pixel position.
>         PixelX = PixelX + 128
>         If PixelX = TileGrid.Size * 128 Then PixelX = 0
>       Next
>       ' Adjust pixel positions.
>       PixelX = 0
>       PixelY = PixelY + 128
>       If PixelY = TileGrid.Size * 128 Then PixelY = 0
>     Next
>
>     ' Reset matrices so subsequent SDL writes won't get botched.
>     Gl.LoadIdentity()
>
> End
>
> Notice I didn't assign values to OffsetX or OffsetY. Didn't want to
> include any failed experiments. I also attached the code for better
> legibility.
>
> I can offset the position of the quads easily using Gl.Translatef, but
> the group ALWAYS seems to rotate with the upper-left corner as the
> origin. I need to be able to control the origin. I can do this easily
> with a single quad, but seem to have trouble doing it "globally" with
> the For...Next loops of quads.
>
> ----- End Original Message -----
>
>
> Hi Kevin,
> You can't do this in one rotatef() function.
>
> You have to rotate every quad separately, using sequence:
> gl.Loadidentity - to reset matrix at 0,0,0
> for each quad do
> gl.pushmatrix() - save the global matrix
> gl.translatei() - move to the center of each quad
> gl.rotatef(angle,x,y,z) - rotate each quad
> draw each quad
> gl.popmatrix() - back to the 0,0,0 origin.
>
> Tomek.
>

I think people need to tell me things aren't possible more frequently. 
;) I got it to work, though it required some thinking my brain isn't 
used to doing. Ouch. I attached the working procedure.

First I offset the matrix using Translatef to set the origin at the 
camera position in the grid of quads to be rendered. Then I rotated the 
matrix and translated it back to its starting point.

Next I had two create two "offset" variables (OffsetX and OffsetY), 
which are the number of pixels each quad should be offset horizontally 
and vertically along the newly rotated matrix so that the quad grid's 
origin (camera position) is at the center of the screen. I'm working 
with arbitrary screen resolutions and quad grid dimensions, so it was 
extra tricky for me. Here's the crazy part. Because the matrix had been 
rotated, but I was trying to center the grid relative to the screen 
resolution, I had to "undo" the matrix rotation transformation when 
calculating the offsets:

OffsetX = Convert.RotateX((swidth - TileGrid.Size * 128) / 2 - 
CameraOffsetX + 64, (sheight - TileGrid.Size * 128) / 2 - CameraOffsetY 
+ 64, 0, 0, Client.Orientation)

OffsetY = Convert.RotateY((swidth - TileGrid.Size * 128) / 2 - 
CameraOffsetX + 64, (sheight - TileGrid.Size * 128) / 2 - CameraOffsetY 
+ 64, 0, 0, Client.Orientation)

The conversion functions look like this:

Public Function RotateX(ObjectX As Single, ObjectY As Single, OriginX As 
Single, OriginY As Single, Orientation As Single) As Single

   ' Rotate specified point about specified point and return new X 
coordinate.

   Return (OriginX + (Cos(Rad(Orientation)) * (ObjectX - OriginX) - 
Sin(Rad(Orientation)) * (ObjectY - OriginY)))

End

Public Function RotateY(ObjectX As Single, ObjectY As Single, OriginX As 
Single, OriginY As Single, Orientation As Single) As Single

   ' Rotate specified point about specified point and return new Y 
coordinate.

   Return (OriginY + (Sin(Rad(Orientation)) * (ObjectX - OriginX) + 
Cos(Rad(Orientation)) * (ObjectY - OriginY)))

End

I don't know why I had to add 64 to each offset manually, but it works 
so I'm happy. Now I just need to add similar logic to my Texture() 
procedure so that the game objects don't fly all over the place like 
they're doing now...


-- 
Kevin Fishburne
Eight Virtues
www: http://sales.eightvirtues.com
e-mail: sales at ...1887...
phone: (770) 853-6271

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: muti-quad rotation and translation with arbitrary origin
URL: <http://lists.gambas-basic.org/pipermail/user/attachments/20110810/160d8da1/attachment.ksh>


More information about the User mailing list