Example #1
0
def get_color(point):
    # Color c[34]B, can we use 4 for water?
    color_grass = [10, 150, 50]
    color_mountain = [255, 255, 255]
    color_sand = [200, 200, 0]
    mountain_height = 1.1
    # Slight offset from ocean, so that some land is colored as sand
    grass_height = 1.005
    mag = math_helper.get_mag(point)

    if mag > mountain_height:
        main_color = color_mountain
    elif mag > grass_height:
        main_color = color_grass
    else:
        main_color = color_sand
    return main_color
Example #2
0
def generate_icosahedron(radius=1):
    """
    Generates an icosahedron, returns a list of coordinates
    """

    # TODO - Looks like radius isnt working correctly
    # TODO - Might be able to remove radius from t
    t = radius * ((1.0 + math.sqrt(5.0)) / 2.0)
    t = (1.0 + math.sqrt(5.0)) / 2.0

    points = [[-1, t, 0],
              [1, t, 0],
              [-1, -t, 0],
              [1, -t, 0],

              [0, -1, t],
              [0, 1, t],
              [0, -1, -t],
              [0, 1, -t],

              [t, 0, -1],
              [t, 0, 1],
              [-t, 0, -1],
              [-t, 0, 1]
              ]

    # Normalize all verts
    # TODO - Could be written better
    points_out = []
    for coord in points:
        # TODO - Add radius to scale
        scale = 1.0
        scale = radius
        b = []
        mag = math_helper.get_mag(coord)

        # Refactor into list comp
        for point in coord:
            b.append((point / mag) * scale)
        points_out.append(b)

    return points_out
Example #3
0
def generate_edges(icosahedron, divs, main_displacement, roughness):
    """
    Return a list of edges along each face of the icosahedron
    """
    # If theres an easier way to express edges, we can generalise the solution and increase the resolution of the system
    # Edges that connect the icosahedron together

    edges = get_icosahedron_edges()
    # This stage generates the edges, need to do another generation to fill out triangles
    final_edges = {}
    for i in edges:

        final_edges[i] = [icosahedron[i[0]], icosahedron[i[1]]]
        # Reset starting displacement for each edge

        displacement = main_displacement

        # This needs to be moved to its own function
        for divisions in range(divs):
            displacement *= 2 ** -roughness
            n = 1
            for j in range(len(final_edges[i]) - 1):
                mid = math_helper.get_midpoint(final_edges[i][n - 1], final_edges[i][n])
                mag = math_helper.get_mag(mid)
                scale = random.uniform(mag - displacement, mag + displacement) / mag

                a = mid[0] * scale
                b = mid[1] * scale
                c = mid[2] * scale

                final_edges[i].insert(n, [a, b, c])

                n += 2

        # Create the reverse edge
        final_edges[(i[1], i[0])] = list(reversed(final_edges[i]))

    return final_edges
Example #4
0
def generate_surface(divs, edges, roughness=0, displacement=0):
    """
    Modified version of the midpoint displacement algorithm, or diamond square algorithm,
    made to work with a triangular section of terrian (Face of an icosahedron).

    divs: The number of divisions required on the face
    edges: Edges of the face, can be single points for corners or entire edge.
          Other values will cause an exception
          [[Edge from A to B], [Edge from B to C], [Edge from C to A]]
          where each edge is an array of [x, y, z] coordinates
            B
            |\
            | \
            |  \
            |   \
            |    \
            |_____\
            A      C
            AB - [[0,0] -> [0,n]]
            BC - [[0,n] -> [n,0]]
            CA - [[n,0] -> [0,0]]

    roughness: Controls the decay of surface displacement over successive steps
    displacement: Controls the magnitude of the change in surface
    Returns the generated surface as a triangular array
    """

    max_points = 2 ** divs + 1
    surface = []
    for i in range(max_points):
        surface.append([])
        for j in range(max_points - i):
            surface[i].append(None)

    # AB
    if len(edges[0]) == 1 and len(edges[1]) == 1 and len(edges[2]):
        # A
        surface[0][0] = edges[0][0]
        # B
        surface[0][max_points-1] = edges[1][0]
        # C
        surface[max_points-1][0] = edges[2][0]

    elif len(edges[0]) == max_points and len(edges[1]) == max_points and len(edges[2]) == max_points:
        # AB
        for i in range(0, max_points):
            surface[0][i] = edges[0][i]
        # BC
        for i in range(0, max_points):
            # TODO - This one is iterating backwards
            surface[max_points - 1 - i][i] = edges[1][i]
        # CA
        for i in range(0, max_points):
            surface[max_points - 1 - i][0] = edges[2][i]

    else:
        raise Exception('Incorrect number of points in edge, should be either entire edge or single point')

    step = max_points

    for d in range(divs):
        # Control the displacement decay of the algorithm
        displacement *= 2 ** -roughness
        step //= 2
        for i, x in enumerate(range(0, max_points, step)):
            for j, y in enumerate(range(0, len(surface[x]), step)):
                if surface[x][y] is None:
                    # TODO - Could use a diagram
                    # Select points to calculate the midpoint, the nearest points within the grid are dependant on
                    # the current step size and the parity on the x axis.
                    # The nearest point is then either horizontal line, vertical line or a diagonal line

                    # Horizontal line
                    if j % 2 == 0:
                        upper = surface[x + step][y]
                        lower = surface[x - step][y]

                    else:
                        # Vertical line
                        if i % 2 == 0:
                            upper = surface[x][y + step]
                            lower = surface[x][y - step]

                        # Diagonal line
                        else:
                            upper = surface[x + step][y - step]
                            lower = surface[x - step][y + step]

                    # Find the x,y,z midpoint between the two points
                    mid = math_helper.get_midpoint(upper, lower)
                    # Find the magnitude of the vector
                    mag = math_helper.get_mag(mid)
                    # Scale the vector around its current position and normalize it
                    scale = random.uniform(mag - displacement, mag + displacement) / mag
                    a = mid[0] * scale
                    b = mid[1] * scale
                    c = mid[2] * scale

                    surface[x][y] = [a, b, c]
    return surface
Example #5
0
    def __init__(self):
        self.throttle = 500
        self.icosahedron = generator.generate_icosahedron()

        self.ocean_batch = pyglet.graphics.Batch()
        self.cloud_batch = pyglet.graphics.Batch()


        self.sun_batch = pyglet.graphics.Batch()

        self.chunks = {}

        self.queue = Queue.Queue()

        self.background_stars = stars.Stars()

        divs = 6
        main_displacement = 0.3

        roughness = 1.0

        # First apply random steps to each vertex
        new_icosahedron = self.icosahedron
        final_edges = generator.generate_edges(new_icosahedron, divs, main_displacement, roughness)

        faces = generator.get_icosahedron_faces()

        ocean_icosahedron = generator.generate_icosahedron()


        new_ocean = []
        for face in faces:
            # Not the most elegant solution
            a = ocean_icosahedron[face[0]]
            b = ocean_icosahedron[face[1]]
            c = ocean_icosahedron[face[2]]

            surface = generator.generate_surface(divs, [[a], [b], [c]])
            new_ocean.append(surface)

        ocean_color = [0, 0, 255, 170]
        verts = []
        max_points = 2 ** divs + 1
        for face in new_ocean:
            for i in range(0, max_points - 1):
                # Create a counter k, this is used in place of j when we draw the triangle at the end of the row
                k = 0
                for j in range(max_points - i - 2):
                    # Add both triangle in the square to the render batch
                    #
                    #  b______d           .
                    #  |\     |           |\
                    #  | \    |           | \
                    #  |  \ 2 |           |  \
                    #  | 1 \  |           | 3 \
                    #  |    \ |           |    \
                    # a|_____\|c ........ |_____\

                    a = face[i][j]
                    b = face[i][j + 1]
                    c = face[i + 1][j]
                    d = face[i + 1][j + 1]

                    # Triangle 1
                    verts += a + b + c
                    # Triangle 2,  bdc to maintain clockwise winding order
                    verts += b + d + c

                    k += 1

                # Add remaining triangle at the end of the row, Triangle 3
                a = face[i][k]
                b = face[i][k + 1]
                c = face[i + 1][k]
                verts += a + b + c

        num_triangles = len(verts) / 3
        # As water color is uniform, add all colors at the end
        colors = ocean_color * num_triangles

        # Example of group, class overrides functions, functions within pyglet are all pass
        # https: // github.com / reidrac / pyglet - obj - batch / blob / master / obj_batch.py
        group = pyglet.graphics.Group
        # print group.


        # water_group = material.Material()
        water_group = None

        self.ocean_batch.add(num_triangles, pyglet.gl.GL_TRIANGLES, water_group, ('v3f', verts), ('n3f', verts),
                             ('c4B', colors))

        cloud_icosahedron = generator.generate_icosahedron(2)


        new_clouds = []
        new_cloud_density = []

        cloud_displacement = 0.9
        cloud_roughness = 1
        scale_div = 2
        cloud_cutoff = 0
        cloud_edges = generator.generate_edges(new_icosahedron, divs, cloud_displacement, cloud_roughness)
        for face in faces:
            # Not the most elegant solution
            a = cloud_icosahedron[face[0]]
            b = cloud_icosahedron[face[1]]
            c = cloud_icosahedron[face[2]]

            edges = [cloud_edges[(face[0], face[1])], \
                     # Note, this edge is backwards
                     cloud_edges[(face[2], face[1])], \
                     cloud_edges[(face[2], face[0])]]
            #surface = generator.generate_surface(divs, [[a], [b], [c]])
            # Need to pre generate the edges for this one
            surface = generator.generate_surface(divs, [[a], [b], [c]])
            new_clouds.append(surface)
            surface_density = generator.generate_surface(divs, edges, cloud_displacement, cloud_roughness)
            new_cloud_density.append(surface_density)


        # Need a function to generate density
        # Add the water to the render batch
        cloud_color = [0, 250, 255, 170]
        verts = []

        max_points = 2 ** divs + 1
        for f, face in enumerate(new_clouds):


            for i in range(0, max_points - 1):
                # Create a counter k, this is used in place of j when we draw the triangle at the end of the row
                k = 0
                for j in range(max_points - i - 2):
                    # Add both triangle in the square to the render batch
                    #
                    #  b______d           .
                    #  |\     |           |\
                    #  | \    |           | \
                    #  |  \ 2 |           |  \
                    #  | 1 \  |           | 3 \
                    #  |    \ |           |    \
                    # a|_____\|c ........ |_____\

                    a = face[i][j]
                    b = face[i][j+1]
                    c = face[i+1][j]
                    d = face[i+1][j+1]

                    verts = []
                    verts += a + b + c
                    color = []
                    # get mag new_cloud_density[f][i][j] + new_cloud_density[f][i][j + 1] + new_cloud_density[f][i + 1][j]

                    mag1 = int((255 / scale_div) * math_helper.get_mag(new_cloud_density[f][i][j]))
                    mag2 = int((255 / scale_div) * math_helper.get_mag(new_cloud_density[f][i][j + 1]))
                    mag3 = int((255 / scale_div) * math_helper.get_mag(new_cloud_density[f][i + 1][j]))
                    if mag1 < cloud_cutoff:
                        mag1 = 0
                    if mag2 < cloud_cutoff:
                        mag2 = 0
                    if mag3 < cloud_cutoff:
                        mag3 = 0
                    color = [255, 255, 255, mag1, 255, 255, 255, mag2, 255, 255, 255, mag3]

                    self.cloud_batch.add(3, pyglet.gl.GL_TRIANGLES, None, ('v3f', verts), ('n3f', verts),('c4B', color))
                                         #('c4B', [0, 255, 255, 180]))                    # Triangle 1
                    #verts += a + b + c
                    # Triangle 2,  bdc to maintain clockwise winding order

                    verts = []
                    verts += b + d + c

                    color = []
                    mag1 = int((255/scale_div) * math_helper.get_mag(new_cloud_density[f][i][j + 1]))
                    mag2 = int((255/scale_div) * math_helper.get_mag(new_cloud_density[f][i+1][j + 1]))
                    mag3 = int((255/scale_div) * math_helper.get_mag(new_cloud_density[f][i+1][j]))


                    if mag1 < cloud_cutoff:
                        mag1 = 0
                    if mag2 < cloud_cutoff:
                        mag2 = 0
                    if mag3 < cloud_cutoff:
                        mag3 = 0

                    color = [255, 255, 255, mag1, 255, 255, 255, mag2, 255, 255, 255, mag3]

                    #Get mag - new_cloud_density[f][i][j + 1] + new_cloud_density[f][i + 1][j + 1] + new_cloud_density[f][i + 1][j]
                    #color = [0, 255, 255, 180]*3
                    self.cloud_batch.add(3, pyglet.gl.GL_TRIANGLES, None, ('v3f', verts), ('n3f', verts),('c4B', color))
                                         #('c4B', [0, 255, 255, 180]))  # Triangle 1

                    k += 1

                # Add remaining triangle at the end of the row, Triangle 3
                a = face[i][k]
                b = face[i][k + 1]
                c = face[i + 1][k]
                # verts += a + b + c
                verts = []
                verts += a + b + c
                color = []

                # TODO - Remember to use k here, not j
                mag1 = int((255 / scale_div) * math_helper.get_mag(new_cloud_density[f][i][k]))
                mag2 = int((255 / scale_div) * math_helper.get_mag(new_cloud_density[f][i][k + 1]))
                mag3 = int((255 / scale_div) * math_helper.get_mag(new_cloud_density[f][i + 1][k]))
                if mag1 < cloud_cutoff:
                    mag1 = 0
                if mag2 < cloud_cutoff:
                    mag2 = 0
                if mag3 < cloud_cutoff:
                    mag3 = 0

                color = [255, 255, 255, mag1, 255, 255, 255, mag2, 255, 255, 255, mag3]
                self.cloud_batch.add(3, pyglet.gl.GL_TRIANGLES, None, ('v3f', verts),('n3f', verts), ('c4B', color))

        #num_triangles = len(verts)/3




        # TODO - Maybe create solar system class
        sun_icosahedron = generator.generate_icosahedron(10)
        print sun_icosahedron



        new_sun = []
        for face in faces:
            a = sun_icosahedron[face[0]]
            b = sun_icosahedron[face[1]]
            c = sun_icosahedron[face[2]]

            surface = generator.generate_surface(divs, [[a], [b], [c]])
            new_sun.append(surface)

        sun_color = [255, 255, 50]
        verts = []
        max_points = 2 ** divs + 1
        for face in new_sun:
            for i in range(0, max_points - 1):
                # Create a counter k, this is used in place of j when we draw the triangle at the end of the row
                k = 0
                for j in range(max_points - i - 2):
                    # Add both triangle in the square to the render batch
                    #
                    #  b______d           .
                    #  |\     |           |\
                    #  | \    |           | \
                    #  |  \ 2 |           |  \
                    #  | 1 \  |           | 3 \
                    #  |    \ |           |    \
                    # a|_____\|c ........ |_____\

                    a = face[i][j]
                    b = face[i][j + 1]
                    c = face[i + 1][j]
                    d = face[i + 1][j + 1]

                    # Triangle 1
                    verts += a + b + c
                    # Triangle 2,  bdc to maintain clockwise winding order
                    verts += b + d + c

                    k += 1

                # Add remaining triangle at the end of the row, Triangle 3
                a = face[i][k]
                b = face[i][k + 1]
                c = face[i + 1][k]
                verts += a + b + c

        num_triangles = len(verts) / 3
        # As water color is uniform, add all colors at the end
        colors = sun_color * num_triangles

        # Update x position
        for i in range(0, len(verts), 3):
            verts[i] += 20

        self.sun_batch.add(num_triangles, pyglet.gl.GL_TRIANGLES, None, ('v3f', verts), ('n3f', verts),
                             ('c3B', colors))

        # Seems to work if I up the number of processes above the cpu count
        # Should either remove multiprocessing, or find a way to make it work correctly
        pool = Pool(processes=7)  # process per core

        # Output isn't in same order
        self.chunks = pool.map(chunk.Chunk(divs, final_edges, main_displacement, roughness), faces)

        # Needs to be done outside of multiprocess, as some parts of pyglet arnt thread safe
        for i in self.chunks:
            i.generate_batch()