Relative Objects - Demo 11¶
Objective¶
Introduce relative objects, by making a small blue square that is defined relative to the left paddle, but offset some in the x direction. When the paddle on the left moves or rotates, the blue square moves with it, because it is defined relative to it.
Demo 11¶
How to Execute¶
Load src/modelviewprojection/demo11.py in Spyder and hit the play button.
Move the Paddles using the Keyboard¶
Keyboard Input |
Action |
|---|---|
w |
Move Left Paddle Up |
s |
Move Left Paddle Down |
k |
Move Right Paddle Down |
i |
Move Right Paddle Up |
d |
Increase Left Paddle’s Rotation |
a |
Decrease Left Paddle’s Rotation |
l |
Increase Right Paddle’s Rotation |
j |
Decrease Right Paddle’s Rotation |
UP |
Move the camera up, moving the objects down |
DOWN |
Move the camera down, moving the objects up |
LEFT |
Move the camera left, moving the objects right |
RIGHT |
Move the camera right, moving the objects left |
Description¶
Cayley Graph¶
In the graph below, all we have added is “Square space”, relative to paddle 1 space.
Demo 11¶
In the picture below, in 3D space, we see that the square has its own modelspace (as evidenced by the 3 arrows), and we are going to define its position and orientation relative to paddle 1.
Coordinate Frames¶
Code¶
Define the geometry of the square in its own modelspace.
126square: list[mu2d.Vector2D] = [
127 mu2d.Vector2D(x=-0.5, y=-0.5),
128 mu2d.Vector2D(x=0.5, y=-0.5),
129 mu2d.Vector2D(x=0.5, y=0.5),
130 mu2d.Vector2D(x=-0.5, y=0.5),
131]
Event Loop¶
174while not glfw.window_should_close(window):
...
Draw paddle 1, just as before.
195 GL.glColor3f(*iter(paddle1.color))
196
197 GL.glBegin(GL.GL_QUADS)
198 for p1_v_ms in paddle1.vertices:
199 ms_to_ndc: mu2d.InvertibleFunction = mu2d.compose(
200 [
201 # camera space to NDC
202 mu2d.uniform_scale(1.0 / 10.0),
203 # world space to camera space
204 mu2d.inverse(mu2d.translate(camera.position_ws)),
205 # model space to world space
206 mu2d.compose(
207 [
208 mu2d.translate(paddle1.position),
209 mu2d.rotate(paddle1.rotation),
210 ]
211 ),
212 ]
213 )
214
215 paddle1_vector_ndc: mu2d.Vector2D = ms_to_ndc(p1_v_ms)
216
217 GL.glVertex2f(paddle1_vector_ndc.x, paddle1_vector_ndc.y)
218 GL.glEnd()
As a refresher, the author recommends reading the code from modelspace to worldspace from the bottom up, and from worldspace to NDC from top down.
Read from modelspace to world space, bottom up
Reset the coordinate system
Read from world space to camera space, knowing that camera transformations are implemented as the inverse of placing the camera space in world space.
Reset the coordinate system
Read camera-space to NDC
New part! Draw the square relative to the first paddle! Translate the square to the right by 2 units. We are dealing with a -1 to 1 world space, which later gets scaled down to NDC.
222 GL.glColor3f(0.0, 0.0, 1.0)
223 GL.glBegin(GL.GL_QUADS)
224 for ms in square:
225 ms_to_ndc: mu2d.InvertibleFunction = mu2d.compose(
226 [
227 # camera space to NDC
228 mu2d.uniform_scale(1.0 / 10.0),
229 # world space to camera space
230 mu2d.inverse(mu2d.translate(camera.position_ws)),
231 # model space to world space
232 mu2d.compose(
233 [
234 mu2d.translate(paddle1.position),
235 mu2d.rotate(paddle1.rotation),
236 ]
237 ),
238 # square space to paddle 1 space
239 mu2d.translate(mu2d.Vector2D(x=2.0, y=0.0)),
240 ]
241 )
242 square_vector_ndc: mu2d.Vector2D = ms_to_ndc(ms)
243 GL.glVertex2f(square_vector_ndc.x, square_vector_ndc.y)
244 GL.glEnd()
Towards that, we need to do all of the transformations to the square that we would to the paddle, and then do any extra transformations afterwards.
As such, read
Read paddle1space to world space, from bottom up
If we were to plot the square now, it would be in paddle 1’s space. We don’t want that, we want in to be moved in the X direction some units. Therefore
Read modelspace to paddle1space, from bottom up
Reset the coordinate system.
Now the square’s geometry will be in its own space!
Read from worldspace to camera-space, knowing that camera transformations are implemented as the inverse of placing the camera space in world space.
Reset the coordinate system
Read camera-space to NDC
Draw paddle 2 just like before.
248 GL.glColor3f(*iter(paddle2.color))
249
250 GL.glBegin(GL.GL_QUADS)
251 for p2_v_ms in paddle2.vertices:
252 ms_to_ndc: mu2d.InvertibleFunction = mu2d.compose(
253 [
254 # camera space to NDC
255 mu2d.uniform_scale(1.0 / 10.0),
256 # world space to camera space
257 mu2d.inverse(mu2d.translate(camera.position_ws)),
258 # model space to world space
259 mu2d.compose(
260 [
261 mu2d.translate(paddle2.position),
262 mu2d.rotate(paddle2.rotation),
263 ]
264 ),
265 ]
266 )
267
268 paddle2_vector_ndc: mu2d.Vector2D = ms_to_ndc(p2_v_ms)
269
270 GL.glVertex2f(paddle2_vector_ndc.x, paddle2_vector_ndc.y)
271 GL.glEnd()