Skip to content
This repository has been archived by the owner on Sep 25, 2022. It is now read-only.

Commit

Permalink
Merge pull request #9 from nickdelgrosso/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
nickdelgrosso committed Jun 5, 2018
2 parents 44a5654 + 5aff171 commit e4812e8
Show file tree
Hide file tree
Showing 20 changed files with 484 additions and 53 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ python:
branches:
only:
- master
- dev
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


# ratcave
3D Graphics Engine running off Python, Psychopy, and Pyglet
3D Graphics Engine running off Python, Psychopy, and Pyglet using modern OpenGL conventions.

Full Documentation and Tutorials can be found at http://ratcave.readthedocs.io/

Expand Down
Binary file added docs/_static/solar_system.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
239 changes: 239 additions & 0 deletions docs/solar_system.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
Tutorial 5: Parenting objects together - Solar System
+++++++++++++++++++++++++++++++++++++++++++++++++++++

This tutorial is based on previous.

In this tutorial you will learn how to use ratcave to create solar system animation.
We will show how to create layout dependencies (in between parent and children objects), by defining relationships between objects.
Additionally the :py:class:`.Empty Entity` objects will be introduced.

.. warning:: This tutorial builds on the previous tutorials. If you're just getting started, it's recommended to go back and do those tutorials first!

Initial Script
--------------

Since the previous tutorials have already covered a lot of ratcave methods, let's just start with the following script::

import pyglet
import ratcave as rc

# Create Window
window = pyglet.window.Window(resizable=True)

def update(dt):
pass
pyglet.clock.schedule(update)

# Insert filename into WavefrontReader.
obj_filename = rc.resources.obj_primitives
obj_reader = rc.WavefrontReader(obj_filename)


Meshes and Empty Entities
-------------------------

We can not define more then one rotation speed for the sun object. To introduce different rotation for each of the planets, we need to use Empty Entities.
Empty Entities are objects, that occupie physical space, but doesn't actually draw anything when :py:func:`Scene.draw()` is called (just passing the values).
Later, we can set rotation speed for each of the :py:class:`.Empty Entity` object::

# Create Meshes
sun = obj_reader.get_mesh("Sphere", name='sun')
merkury = obj_reader.get_mesh("Sphere", scale =.1, name='merkury')
venus = obj_reader.get_mesh("Sphere", scale =.2, name='venus')
earth = obj_reader.get_mesh("Sphere", scale =.2, name='earth')
mars = obj_reader.get_mesh("Sphere", scale =.2, name='mars')
jupyter = obj_reader.get_mesh("Sphere", scale =.4, name='jupyter')
moon = obj_reader.get_mesh("Sphere", scale =.5, name='moon')

# Create Empty Entities
empty_merkury = rc.EmptyEntity(name='sun_merkury')
empty_venus = rc.EmptyEntity(name='sun_venus')
empty_earth = rc.EmptyEntity(name='sun_earth')
empty_mars = rc.EmptyEntity(name='sun_mars')
empty_jupyter = rc.EmptyEntity(name='sun_jupyter')


Define Relationships and Relative Positions
-------------------------------------------

Relationships Between Objects
=============================

To define layout relationship in between objects in ratcave, user has to link them togheter using :py:class:`.SceneGraph` properties:
- :py:func:`Mesh.add_child()`
- :py:func:`Mesh.add_children()`
- :py:func:`Mesh.parent()`

The following code does the job::

# Define Relationships
sun.add_children(empty_merkury, empty_earth, empty_venus, empty_mars, empty_jupyter)

empty_merkury.add_child(merkury)
empty_venus.add_child(venus)
empty_earth.add_child(earth)
empty_mars.add_child(mars)
empty_jupyter.add_child(jupyter)

earth.add_child(moon)

Relative Objects Positions
==========================

Additionally it is important to define the position of the children in relative position to the parent (position of planets in relation to the sun).
This can be done in a following way::

# Define Relative Positions
sun.rotation.x = 50
sun.position.xyz = 0, 0, -12

merkury.position.z += 1
venus.position.z += 2
earth.position.z += 3
mars.position.z += 4
jupyter.position.z += 5

moon.position.z += 1


Setting Rotations
-----------------

Each of the roations has to be set separately::

def on_draw():
with rc.default_shader:
sun.rotation.y += 0.5
earth.rotation.y += 0.5
empty_merkury.rotation.y += 2
empty_venus.rotation.y += 1.5
empty_earth.rotation.y += 1
empty_mars.rotation.y += 0.75
empty_jupyter.rotation.y += 0.5

Scene - Update
------

After defintion of a scene::

scene = rc.Scene(meshes=sun, bgColor=(0,0,0))

sun and all of its children now get drawn when :py:func:`scene.draw()` gets called. There is no further need of updating any of the Meshes (or its children) included in the scene.
You can also decide which of the elements are going to be drawn, by calling them separately, the position of the planets will still be relative to the sun (also when sun itself is not being drawn)::

def on_draw():
window.clear()
with rc.default_shader, scene.camera, scene.light:
sun.draw()
earth.draw()

Additionally you can parent the camera and light to one of the Mesh objects. It can be done in following manner::

#Define Relationships For Cameras and Objects
earth.add_child(scene.camera)
earth.add_child(scene.light)


If you run it, you should see this simulation of solar system:

.. image:: _static/solar_system.png

Summary
-------

Here is the full code for the Tutorial 5::

import pyglet
from pyglet.window import key
import ratcave as rc

# Create Window
window = pyglet.window.Window(resizable=True)
keys = key.KeyStateHandler()
window.push_handlers(keys)


def update(dt):
pass
pyglet.clock.schedule(update)

# Insert filename into WavefrontReader.
obj_filename = rc.resources.obj_primitives
obj_reader = rc.WavefrontReader(obj_filename)

# Create Meshes
sun = obj_reader.get_mesh("Sphere", name='sun')
merkury = obj_reader.get_mesh("Sphere", scale =.1, name='merkury')
venus = obj_reader.get_mesh("Sphere", scale =.2, name='venus')
earth = obj_reader.get_mesh("Sphere", scale =.2, name='earth')
mars = obj_reader.get_mesh("Sphere", scale =.2, name='mars')
jupyter = obj_reader.get_mesh("Sphere", scale =.4, name='jupyter')
moon = obj_reader.get_mesh("Sphere", scale =.5, name='moon')

# Create Empty Entities
empty_merkury = rc.EmptyEntity(name='sun_merkury')
empty_venus = rc.EmptyEntity(name='sun_venus')
empty_earth = rc.EmptyEntity(name='sun_earth')
empty_mars = rc.EmptyEntity(name='sun_mars')
empty_jupyter = rc.EmptyEntity(name='sun_jupyter')

# Define Relationships
sun.add_children(empty_merkury, empty_earth, empty_venus, empty_mars, empty_jupyter)

empty_merkury.add_child(merkury)
empty_venus.add_child(venus)
empty_earth.add_child(earth)
empty_mars.add_child(mars)
empty_jupyter.add_child(jupyter)

earth.add_child(moon)

# Define Relative Positions
sun.rotation.x = 50
sun.position.xyz = 0, 0, -12

merkury.position.z += 1
venus.position.z += 2
earth.position.z += 3
mars.position.z += 4
jupyter.position.z += 5

moon.position.z += 1

sun.textures.append(rc.Texture.from_image(rc.resources.img_colorgrid))

# Create Scene
scene = rc.Scene(meshes=sun, bgColor=(0,0,0))
scene.camera.projection.z_far = 20

# Define Relationships For Cameras and Objects
# earth.add_child(scene.camera)
# earth.add_child(scene.light)

planets = [sun, earth, jupyter]

def move_camera(dt):
'''function used to parent the camera to a different planet'''
if keys[key.LEFT]:
cam_parent = planets.pop(0)
cam_parent.add_child(scene.camera)
planets.append(cam_parent)

pyglet.clock.schedule(move_camera)


@window.event
def on_draw():
window.clear()
sun.rotation.y += 0.5
earth.rotation.y += 0.5
empty_merkury.rotation.y += 2
empty_venus.rotation.y += 1.5
empty_earth.rotation.y += 1
empty_mars.rotation.y += 0.75
empty_jupyter.rotation.y += 0.5

with rc.default_shader:
scene.draw()

pyglet.app.run()
1 change: 1 addition & 0 deletions docs/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ These Tutorials are meant to help you get started!
tutorial2
tutorial3
tutorial4
solar_system
79 changes: 79 additions & 0 deletions examples/solar_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pyglet
from pyglet.window import key
import ratcave as rc

# Create Window
window = pyglet.window.Window(resizable=True)
keys = key.KeyStateHandler()
window.push_handlers(keys)


def update(dt):
pass
pyglet.clock.schedule(update)

# Insert filename into WavefrontReader.
obj_filename = rc.resources.obj_primitives
obj_reader = rc.WavefrontReader(obj_filename)

# Create Meshes
sun = obj_reader.get_mesh("Sphere", name='sun')
merkury = obj_reader.get_mesh("Sphere", scale =.1, name='merkury')
venus = obj_reader.get_mesh("Sphere", scale =.2, name='venus')
earth = obj_reader.get_mesh("Sphere", scale =.2, name='earth')
mars = obj_reader.get_mesh("Sphere", scale =.2, name='mars')
jupyter = obj_reader.get_mesh("Sphere", scale =.4, name='jupyter')
moon = obj_reader.get_mesh("Sphere", scale =.5, name='moon')

# Create Empty Entities
empty_merkury = rc.EmptyEntity(name='sun_merkury')
empty_venus = rc.EmptyEntity(name='sun_venus')
empty_earth = rc.EmptyEntity(name='sun_earth')
empty_mars = rc.EmptyEntity(name='sun_mars')
empty_jupyter = rc.EmptyEntity(name='sun_jupyter')

# Define Relationships
sun.add_children(empty_merkury, empty_earth, empty_venus, empty_mars, empty_jupyter)

empty_merkury.add_child(merkury)
empty_venus.add_child(venus)
empty_earth.add_child(earth)
empty_mars.add_child(mars)
empty_jupyter.add_child(jupyter)

earth.add_child(moon)

# Define Relative Positions
sun.rotation.x = 50
sun.position.xyz = 0, 0, -12

merkury.position.z += 1
venus.position.z += 2
earth.position.z += 3
mars.position.z += 4
jupyter.position.z += 5

moon.position.z += 1

# Add Texture
sun.textures.append(rc.Texture.from_image(rc.resources.img_colorgrid))

# Create Scene
scene = rc.Scene(meshes=sun, bgColor=(0,0,0))
scene.camera.projection.z_far = 20


@window.event
def on_draw():
sun.rotation.y += 0.5
earth.rotation.y += 0.5
empty_merkury.rotation.y += 2
empty_venus.rotation.y += 1.5
empty_earth.rotation.y += 1
empty_mars.rotation.y += 0.75
empty_jupyter.rotation.y += 0.5

with rc.default_shader:
scene.draw()

pyglet.app.run()
2 changes: 1 addition & 1 deletion examples/tutorial1.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ def on_draw():
with rc.default_shader:
scene.draw()

pyglet.app.run()
pyglet.app.run()
6 changes: 3 additions & 3 deletions ratcave/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .physical import PhysicalGraph
import pyglet.gl as gl
from collections import namedtuple
from .shader import HasUniforms
from .shader import HasUniformsUpdater
from .utils import NameLabelMixin, get_viewport

Viewport = namedtuple('Viewport', 'x y width height')
Expand Down Expand Up @@ -207,7 +207,7 @@ def _update_projection_matrix(self):



class Camera(PhysicalGraph, HasUniforms, NameLabelMixin):
class Camera(PhysicalGraph, HasUniformsUpdater, NameLabelMixin):

def __init__(self, projection=None, orientation0=(0, 0, -1), **kwargs):
kwargs['orientation0'] = orientation0
Expand All @@ -219,6 +219,7 @@ def __repr__(self):
return "<Camera(name='{self.name}', position_rel={self.position}, position_glob={self.position_global}, rotation={self.rotation})".format(self=self)

def __enter__(self):
self.update()
self.uniforms.send()
return self

Expand Down Expand Up @@ -248,4 +249,3 @@ def reset_uniforms(self):
@property
def projection_matrix(self):
return self.projection.projection_matrix.view()

Loading

0 comments on commit e4812e8

Please sign in to comment.