Grid of rotating cubes (how to convert?)

Everything related to 3D programming
firace
Addict
Addict
Posts: 899
Joined: Wed Nov 09, 2011 8:58 am

Grid of rotating cubes (how to convert?)

Post by firace »

Would someone know how to convert this little OpenGL demo (by Peter Scarfe) to PB?
I'm not sure what to do with the meshgrid and linspace functions...

And if you have spare time, make each cube a different (random) color :)

See the result at: http://peterscarfe.com/rotatingcubesdemo.html

Code: Select all

% Clear the workspace
close all;
clearvars;
sca;

% Here we call some default settings for setting up Psychtoolbox
PsychDefaultSetup(2);

% Skip sync tests for this demo in case people are using a defective
% system. This is for demo purposes only.
Screen('Preference', 'SkipSyncTests', 2);

% Find the screen to use for display
screenid = max(Screen('Screens'));

% Initialise OpenGL
InitializeMatlabOpenGL;

% Open the main window with multi-sampling for anti-aliasing
[window, windowRect] = PsychImaging('OpenWindow', screenid, 0, [],...
    32, 2, [], 6,  []);

% Query the frame duration
ifi = Screen('GetFlipInterval', window);

% Start the OpenGL context (you have to do this before you issue OpenGL
% commands such as we are using here)
Screen('BeginOpenGL', window);

% For this demo we will assume our screen is 30cm in height. The units are
% essentially arbitary with OpenGL as it is all about ratios. But it is
% nice to define things in normal scale numbers
ar = windowRect(3) / windowRect(4);
screenHeight = 30;
screenWidth = screenHeight * ar;

% Enable lighting
glEnable(GL.LIGHTING);

% Define a local light source
glEnable(GL.LIGHT0);

% Enable proper occlusion handling via depth tests
glEnable(GL.DEPTH_TEST);

% Lets set up a projection matrix, the projection matrix defines how images
% in our 3D simulated scene are projected to the images on our 2D monitor
glMatrixMode(GL.PROJECTION);
glLoadIdentity;

% Calculate the field of view in the y direction assuming a distance to the
% objects of 100cm
dist = 100;
angle = 2 * atand(screenHeight / dist);

% Set up our perspective projection. This is defined by our field of view
% (here given by the variable "angle") and the aspect ratio of our frustum
% (our screen) and two clipping planes. These define the minimum and
% maximum distances allowable here 0.1cm and 200cm.
gluPerspective(angle, ar, 0.1, 200);

% Setup modelview matrix: This defines the position, orientation and
% looking direction of the virtual camera that will be look at our scene.
glMatrixMode(GL.MODELVIEW);
glLoadIdentity;

% Our point lightsource is at position (x,y,z) == (1,2,3)
glLightfv(GL.LIGHT0, GL.POSITION, [1 2 3 0]);

% Location of the camera is at the origin
cam = [0 0 0];

% Set our camera to be looking directly down the Z axis (depth) of our
% coordinate system
fix = [0 0 -100];

% Define "up"
up = [0 1 0];

% Here we set up the attributes of our camera using the variables we have
% defined in the last three lines of code
gluLookAt(cam(1), cam(2), cam(3), fix(1), fix(2), fix(3), up(1), up(2), up(3));

% Set background color to 'black' (the 'clear' color)
glClearColor(0, 0, 0, 0);

% Clear out the backbuffer
glClear;

% Change the light reflection properties of the material to blue. We could
% force a color to the cubes or do this.
glMaterialfv(GL.FRONT_AND_BACK,GL.AMBIENT, [0.0 0.0 1.0 1]);
glMaterialfv(GL.FRONT_AND_BACK,GL.DIFFUSE, [0.0 0.0 1.0 1]);

% End the OpenGL context now that we have finished setting things up
Screen('EndOpenGL', window);

% Setup the positions of the spheres using the mexhgrid command
[cubeX, cubeY] = meshgrid(linspace(-25, 25, 10), linspace(-20, 20, 8));
[s1, s2] = size(cubeX);
cubeX = reshape(cubeX, 1, s1 * s2);
cubeY = reshape(cubeY, 1, s1 * s2);

% Define the intial rotation angles of our cubes
rotaX = rand(1, length(cubeX)) .* 360;
rotaY = rand(1, length(cubeX)) .* 360;
rotaZ = rand(1, length(cubeX)) .* 360;

% Now we define how many degrees our cubes will rotated per second and per
% frame. Note we use Degrees here (not Radians)
degPerSec = 180;
degPerFrame = degPerSec * ifi;

% Get a time stamp with a flip
vbl = Screen('Flip', window);

% Set the frames to wait to one
waitframes = 1;

while ~KbCheck

    % Begin the OpenGL context now we want to issue OpenGL commands again
    Screen('BeginOpenGL', window);

    % To start with we clear everything
    glClear;

    % Draw all the cubes
    for i = 1:1:length(cubeX)

        % Push the matrix stack
        glPushMatrix;

        % Translate the cube in xyz
        glTranslatef(cubeX(i), cubeY(i), -dist);

        % Rotate the cube randomly in xyz
        glRotatef(rotaX(i), 1, 0, 0);
        glRotatef(rotaY(i), 0, 1, 0);
        glRotatef(rotaZ(i), 0, 0, 1);

        % Draw the solid cube
        glutSolidCube(3);

        % Pop the matrix stack for the next cube
        glPopMatrix;

    end

    % End the OpenGL context now that we have finished doing OpenGL stuff.
    % This hands back control to PTB
    Screen('EndOpenGL', window);

    % Show rendered image at next vertical retrace
    vbl = Screen('Flip', window, vbl + (waitframes - 0.5) * ifi);

    % Rotate the cubes for the next drawing loop
    rotaX = rotaX + degPerFrame;
    rotaY = rotaY + degPerFrame;
    rotaZ = rotaZ + degPerFrame;

end

% Shut the screen down
sca;
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: Grid of rotating cubes (how to convert?)

Post by DK_PETER »

I'm not sure if you want an version with OpenGLGadget or using the Engine...
Here's a simple example using my favorite Engine.

Code: Select all

InitEngine3D()
InitSprite()
InitKeyboard()

Structure Vector3D
  x.f
  y.f
  z.f
EndStructure

Structure Cubes
  ms.i
  ma.i
  tx.i
  id.i
  direction.i ;only for cubes
EndStructure

Declare OrbitCalc3D(*ReturnVec.Vector3D, CenterX.f, CenterY.f, CenterZ.f, AngleX.f, AngleY.f, Radius.i)

Global Dim cubes.Cubes(9, 7), v.Vector3D, Dim tubes.Cubes(36), nod.i, el.i, basex.i = -4, basey.i = -3.2

OpenWindow(0, 0, 0, 800, 600, "Cubes", #PB_Window_ScreenCentered|#PB_Window_Maximize|#PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, #True, 0, 0)
CreateCamera(0, 0, 0, 100, 100)
CreateLight(0, $FFFFFF, -3, -5, 0)

For y = 0 To 7
  For x = 0 To 9
    With Cubes(x,y)
      col = RGB(Random(55, 20), Random(55,20), Random(55, 20))
      \tx = CreateTexture(#PB_Any, 10, 10, "tx_x_" + Str(Random(6000)))
      StartDrawing(TextureOutput(\tx))
      Box(0, 0, 10, 10, col)
      Circle(3, 4, 2, $AAAAAA) : Circle(7, 4, 2, $AAAAAA)
      Circle(5, 4, 1, col)
      StopDrawing()
      \ma = CreateMaterial(#PB_Any, TextureID(\tx)) 
      \ms = CreateCube(#PB_Any, 0.5)
      \id = CreateEntity(#PB_Any, MeshID(\ms), MaterialID(\ma), basex + x * 0.8, basey + y * 0.8, -16)
      \direction = Random(50)
    EndWith
  Next x
Next y
nod = CreateNode(#PB_Any, 0, 0, 0)
For x = 0 To 36
  With tubes(x)
    Select Random(90)
      Case 0 To 30
        \ms = CreateCapsule(#PB_Any, 0.2, 0.3)
      Case 31 To 50
        \ms = CreateCone(#PB_Any, 0.2, 0.35)
      Case 51 To 70
        \ms = CreateTorus(#PB_Any, 0.2, 0.02)
      Case 71 To 90
        \ms = CreateSphere(#PB_Any, 0.2)
    EndSelect
    \ma = CopyMaterial(Cubes(Random(9), Random(7))\ma, #PB_Any)
    OrbitCalc3D(v, 0, 0, -18, x*9.0, 0, 7)
    \id = CreateEntity(#PB_Any, MeshID(\ms), MaterialID(\ma), v\x, v\y, v\z)
    AttachNodeObject(nod, EntityID(\id))
  EndWith
Next x
Repeat
  Repeat : ev = WindowEvent() : Until ev = 0
  For y = 0 To 7
    For x = 0 To 9
      With cubes(x,y)
        Select \direction
          Case 0 To 10
            RotateEntity(\id, 0.6, 0.6, 0.6, #PB_Relative)
          Case 11 To 20
            RotateEntity(\id, -0.6, 0.6, 0.6, #PB_Relative)
          Case 21 To 30
            RotateEntity(\id, 0.6, 0.6, -0.6, #PB_Relative)
          Case 31 To 40
            RotateEntity(\id, 0.6, -0.6, 0.6, #PB_Relative)
          Default
            RotateEntity(\id, -0.6, -0.6, -0.6, #PB_Relative)
        EndSelect
      EndWith
    Next x
  Next y
  If ElapsedMilliseconds() - el > 500
    SetLightColor(0, #PB_Light_DiffuseColor, RGB(Random(255,50), Random(255,50), Random(255, 50))) ; change light
    el = ElapsedMilliseconds()
  EndIf
  For x = 0 To 36
    RotateEntity(tubes(x)\id, 0.4, 0.2, 0.6, #PB_Relative)
  Next x
  RotateNode(nod, 0, 0, 0.5, #PB_Relative)
  RenderWorld()
  FlipBuffers()
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)

Procedure OrbitCalc3D(*ReturnVec.Vector3D, CenterX.f, CenterY.f, CenterZ.f, AngleX.f, AngleY.f, Radius.i)
  *ReturnVec\X = CenterX + Radius*Cos(AngleY)*Cos(AngleX)
  *ReturnVec\Y = CenterY + Radius*Sin(AngleX)
  *ReturnVec\Z = CenterZ + Radius*Sin(AngleY)*Cos(AngleX)
EndProcedure
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
firace
Addict
Addict
Posts: 899
Joined: Wed Nov 09, 2011 8:58 am

Re: Grid of rotating cubes (how to convert?)

Post by firace »

DK_PETER wrote:I'm not sure if you want an version with OpenGLGadget or using the Engine...
Here's a simple example using my favorite Engine.
That's a great adaptation, I like it very much. Thanks!

PS: I think it would still be a nice plus to have a pure openGL/Windows example, just to avoid the external DLL dependency.
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: Grid of rotating cubes (how to convert?)

Post by applePi »

@DK_PETER , thanks for the nice example
@firace, in PB Ogre we create entities once and then we render it, while in classic opengl we create the graphics from scratch again and again all the time and then we render it. so it is here much slower, [EDIT: not always this is the case: there are other ways to speed the rendering of opengl objects. look the end of my post here under EDIT word] here is the example depends on the OpenGLGadget.pb example using one cube and then we call its manufacturing procedure 10x8 times while translating it.
we use

Code: Select all

glPushMatrix_()
DrawCube()
glPopMatrix_()
to make it possible to distiguish one graphics from another (not entities like PB Ogre)
if you want to use glutSolidCube_(0.5) like in your program then comment DrawCube() and uncomment glutSolidCube_(0.5) or glutWireCube_(0.5) but then you need to download glut-3.7.6-bin.zip (117 KB) from http://user.xmission.com/~nate/glut.html and then copy glut32.dll to somewhere, it is in my system in windows\system32 and it needs PureBasic/32 bit
here is 10x8 cubes in a grid but rotating in one direction.
try to make it rotate like you want, remember that

Code: Select all

glRotatef_(rotaX, 1, 0, 0);
 glRotatef_(rotaY, 0, 1, 0);
 glRotatef_(rotaZ, 0, 0, 1);
should be here

Code: Select all

glPushMatrix_()
glRotatef_(rotaX, 1, 0, 0);
 glRotatef_(rotaY, 0, 1, 0);
 glRotatef_(rotaZ, 0, 0, 1);
DrawCube()
glPopMatrix_()
we may need an array to distinguish every graphics (cube) from another so we keep tracking the rotation angle of every cube
i am stuck here and can't proceed
note: to color every cube differently, use first the glutSolidCube_ as said before and then change line 110
glColor3f_(1.0, 0.9, 0.0) the values put in an array such as glColor3f_(red(i), green(i), blue(i)) in which its color elements (0 to 1) refer to every specific graphics cube

Code: Select all

Procedure DrawCube()
  
  glDisable_(#GL_LIGHTING)
  glBegin_  (#GL_QUADS)
  
  glNormal3f_ (0,0,1.0)
  glColor3f_  (0,0,1.0)
  glVertex3f_ (0.5,0.5,0.5)   
  glColor3f_  (0,1.0,1.0)         
  glVertex3f_ (-0.5,0.5,0.5)
  glColor3f_  (1.0,1.0,1.0)
  glVertex3f_ (-0.5,-0.5,0.5)
  glColor3f_  (0,0,0)
  glVertex3f_ (0.5,-0.5,0.5) 

  ; The other face is the same than the previous one 
  ; except the colour which is nice blue To white gradiant

  glNormal3f_ (0,0,-1.0)
  glColor3f_  (0,0,1.0)
  glVertex3f_ (-0.5,-0.5,-0.5)
  glColor3f_  (0,0,1.0)
  glVertex3f_ (-0.5,0.5,-0.5)
  glColor3f_  (1.0,1.0,1.0)
  glVertex3f_ (0.5,0.5,-0.5)
  glColor3f_  (1.0,1.0,1.0)
  glVertex3f_ (0.5,-0.5,-0.5)
  
  glEnd_()
  ;0000000000000000000000000000000000000000000000000000000
  ; draw shaded faces

  glEnable_(#GL_LIGHTING)
  glEnable_(#GL_LIGHT0)
  glBegin_ (#GL_QUADS)

  glNormal3f_ (   0, 1.0,   0)
  glVertex3f_ ( 0.5, 0.5, 0.5)
  glVertex3f_ ( 0.5, 0.5,-0.5)
  glVertex3f_ (-0.5, 0.5,-0.5)
  glVertex3f_ (-0.5, 0.5, 0.5)

  glNormal3f_ (0,-1.0,0)
  glVertex3f_ (-0.5,-0.5,-0.5)
  glVertex3f_ (0.5,-0.5,-0.5)
  glVertex3f_ (0.5,-0.5,0.5)
  glVertex3f_ (-0.5,-0.5,0.5)

  glNormal3f_ (1.0,0,0)
  glVertex3f_ (0.5,0.5,0.5)
  glVertex3f_ (0.5,-0.5,0.5)
  glVertex3f_ (0.5,-0.5,-0.5)
  glVertex3f_ (0.5,0.5,-0.5)

  glNormal3f_ (-1.0,   0,   0)
  glVertex3f_ (-0.5,-0.5,-0.5)
  glVertex3f_ (-0.5,-0.5, 0.5)
  glVertex3f_ (-0.5, 0.5, 0.5)
  glVertex3f_ (-0.5, 0.5,-0.5)

  glEnd_()

  
EndProcedure

OpenWindow(0, 0, 0, 800, 600, "Psycho ...")
SetWindowColor(0, 0)
OpenGLGadget(0, 0, 0, WindowWidth(0) , WindowHeight(0), #PB_OpenGL_Keyboard )

SetActiveGadget(0) 

SetWindowColor(0, 0)

HideWindow(0, #False)
Global.f rotaX, rotaY, rotaZ
glClearColor_ (0.0, 0.0, 0.0, 0.0);
glShadeModel_ (#GL_SMOOTH)

glEnable_(#GL_LIGHTING);
glEnable_(#GL_LIGHT0);
glEnable_(#GL_DEPTH_TEST);


Procedure.l DrawGLScene()
 glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear The Screen And The Depth Buffer
 glLoadIdentity_() ;Reset The View
 gluLookAt_( 0, 0, 20, ;great explanation for gluLookAt http://www.gamedev.net/topic/211831-can-some-one-post-a-example-of-glulookat/
                0,  0, -10,
                0, 1,  0 )
  glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
  glMatrixMode_(#GL_PROJECTION)
  glLoadIdentity_()
  gluPerspective_(30.0, Abs(WindowWidth(0) / WindowHeight(0)), 0.1, 500.0)
  glMatrixMode_(#GL_MODELVIEW)
  
   ; viewing transformation  
  glTranslatef_(0.0, 0.0, -10.0); 
       
  ;glPushMatrix_()                  ; Save the original Matrix coordinates
  ;glMatrixMode_(#GL_MODELVIEW)
  glClear_ (#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  glDisable_(#GL_LIGHTING)
  

For y = -4 To 3
  
 For x=-4 To 5
 xx.f = x: yy.f = y  
 glPushMatrix_()
 glColor3f_(1.0, 0.9, 0.0)
 glTranslatef_(xx*1.5, yy*1.5, 0);
 rotaX + 0.01: rotaY + 0.01:rotaZ + 0.01
 glRotatef_(rotaX, 1, 0, 0);
 glRotatef_(rotaY, 0, 1, 0);
 glRotatef_(rotaZ, 0, 0, 1);
 DrawCube()
 ;glutSolidCube_(0.5)
 ;glutWireCube_(0.5)
 glPopMatrix_()
 
Next
Next


  
 ProcedureReturn #True ;Keep Going
 
EndProcedure


  Repeat 
    Event = WindowEvent()
    If Event = #PB_Event_Gadget And EventGadget() = 0 
      If EventType() = #PB_EventType_KeyDown
      
        key = GetGadgetAttribute(0,#PB_OpenGL_Key )
        Select key
          
          Case #PB_Shortcut_Up 
          ;some sode  
            
          Case #PB_Shortcut_Escape
            quit = 1
        EndSelect
           
      EndIf
   EndIf   
    
    
    DrawGLScene()
    SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
  
  Delay(2)
  
Until quit = 1 Or Event = #PB_Event_CloseWindow

End
EDIT:
there are ways to speed displayiing opengl graphics by using as an example opengl lists so we don't make the graphics details contineously . here is a small example i have found:
note the glist = glGenLists_(1)

Code: Select all

    Global axrng.f = 10.0
    Global x.f=0: Global y.f=0: Global r.f=0: Global count.f=0
    Global glist.l

    Declare MathArtMake()
    Declare DrawMathArt(Gadget)

    OpenWindow(0, 0, 0, 500, 500, "using glList", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

    Global axrng.f = 10.0
    Global x.f=0: Global y.f=0: Global r.f=0: Global count.f=0
    Global glist.l
    
    Declare MathArt()
    
    OpenGLGadget(3, 50, 50, 400, 400)
    ;gluOrtho2D_(left, right, bottom, top)
     gluOrtho2D_(-axrng, axrng, -axrng, axrng)
     glMatrixMode_ (#GL_MODELVIEW)
     
           
    MathArtMake()
    
    ;AddWindowTimer(0, 1, 16) ; about 60 fps
    
    Repeat
      
      Repeat
        event = WindowEvent()
        If event = #PB_Event_CloseWindow: quit = 1: EndIf
      Until event = 0
      
            ;SetGadgetAttribute(3, #PB_OpenGL_SetContext, #True)
            glClear_ (#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
            glCallList_(glist)
            SetGadgetAttribute(3, #PB_OpenGL_FlipBuffers, #True)
               
    Delay(1)     

     
    Until  event = #PB_Event_CloseWindow Or quit = 1
     
     End
     

    Procedure MathArtMake()
       
          glPushMatrix_()
         
           ; make the openGL List
           ;glGenLists_(glist.l)
            glist = glGenLists_(1)
            glNewList_(glist, #GL_COMPILE_AND_EXECUTE)
            glLoadIdentity_()
           
            x=-axrng
            While x <= axrng
              x = x + 0.03
             
              y=-axrng
              While y <= axrng
                y = y + 0.03
                count = count + 1
                r = Cos(x) + Sin(y)
                glColor3f_(Cos(y*r), Cos(x*y*r), Sin(r*x))
                glBegin_(#GL_POINTS)
                glVertex3f_(x, y,0)
                glEnd_() ; finished
                 
               Wend
             Wend
             glEndList_()
             glPopMatrix_()
             glFinish_()
                   
       
     EndProcedure
    
Last edited by applePi on Wed Jul 04, 2018 8:45 am, edited 1 time in total.
firace
Addict
Addict
Posts: 899
Joined: Wed Nov 09, 2011 8:58 am

Re: Grid of rotating cubes (how to convert?)

Post by firace »

Thanks a lot applePi, very interesting examples and information! :)
Post Reply