Пример #1
0
class TestWorldCoords(unittest.TestCase):
    def setUp(self):
        self.coords = WorldCoords([-1, -1, -1], 0.1)

    def test_fixed_to_world(self):
        f = [0, 1, 100]
        assert_array_max_ulp(self.coords.fixed_to_world(f), [-1.0, -0.9, 9.0],
                             dtype=np.float32)

    def test_world_to_fixed(self):
        w = [-1.0, -0.9, 9.0]
        assert_array_equal(self.coords.world_to_fixed(w), [0, 1, 100])

    def test_fixed_array_to_world(self):
        f = [[0, 1, 100], [20, 40, 60], [210, 310, 410]]

        assert_array_max_ulp(
            self.coords.fixed_to_world(f),
            [[-1.0, -0.9, 9.0], [1.0, 3.0, 5.0], [20.0, 30.0, 40.0]],
            dtype=np.float32)

    def test_world_array_to_fixed(self):
        w = [[-1.0, -0.9, 9.0], [1.0, 3.0, 5.0], [20.0, 30.0, 40.0]]
        assert_array_equal(self.coords.world_to_fixed(w),
                           [[0, 1, 100], [20, 40, 60], [210, 310, 410]])

    def test_out_of_range(self):
        with self.assertRaises(OutOfRangeError):
            self.coords.world_to_fixed([-2.0, 0.0, 0.0])
        with self.assertRaises(OutOfRangeError):
            self.coords.world_to_fixed([0.0, 1e9, 0.0])
Пример #2
0
def create_bvh():
    # 3 layer binary tree
    degree = 2
    world_coords = WorldCoords(np.array([-1.0, -1.0, -1.0]), 0.1)
    layer_bounds = [0, 1, 3, 7]
    nodes = np.empty(shape=layer_bounds[-1], dtype=uint4)

    # bottom layer
    layer = lslice(layer_bounds, 2)
    nodes['x'][layer] = [0x00010000, 0x00020001, 0x00010000, 0x00010000]
    nodes['y'][layer] = [0x00010000, 0x00010000, 0x00020001, 0x00010000]
    nodes['z'][layer] = [0x00010000, 0x00010000, 0x00010000, 0x00020001]
    nodes['w'][layer] = 0x80000000  # leaf nodes

    # middle layer
    layer = lslice(layer_bounds, 1)
    nodes['x'][layer] = [0x00020000, 0x00010000]
    nodes['y'][layer] = [0x00010000, 0x00020000]
    nodes['z'][layer] = [0x00010000, 0x00020000]
    nodes['w'][layer] = [0x00000003, 0x00000005]

    # top layer
    layer = lslice(layer_bounds, 0)
    nodes['x'][layer] = [0x00020000]
    nodes['y'][layer] = [0x00020000]
    nodes['z'][layer] = [0x00020000]
    nodes['w'][layer] = [0x00000001]

    layer_offsets = list(layer_bounds[:-1])  # trim last entry
    bvh = BVH(world_coords=world_coords,
              nodes=nodes,
              layer_offsets=layer_offsets)

    return bvh
Пример #3
0
class TestWorldCoords(unittest.TestCase):
    def setUp(self):
        self.coords = WorldCoords([-1,-1,-1], 0.1)

    def test_fixed_to_world(self):
        f = [0, 1, 100]
        assert_array_max_ulp(self.coords.fixed_to_world(f), 
                             [-1.0, -0.9, 9.0], dtype=np.float32)
    
    def test_world_to_fixed(self):
        w = [-1.0, -0.9, 9.0]
        assert_array_equal(self.coords.world_to_fixed(w), 
                           [0, 1, 100])


    def test_fixed_array_to_world(self):
        f = [[0, 1, 100],
             [20, 40, 60],
             [210, 310, 410]]

        assert_array_max_ulp(self.coords.fixed_to_world(f), 
                             [[-1.0, -0.9, 9.0], 
                              [1.0, 3.0, 5.0],
                              [20.0, 30.0, 40.0]],
                             dtype=np.float32)

    def test_world_array_to_fixed(self):
        w = [[-1.0, -0.9, 9.0], 
             [1.0, 3.0, 5.0],
             [20.0, 30.0, 40.0]]
        assert_array_equal(self.coords.world_to_fixed(w), 
                           [[0, 1, 100],
                            [20, 40, 60],
                            [210, 310, 410]])

    def test_out_of_range(self):
        with self.assertRaises(OutOfRangeError):
            self.coords.world_to_fixed([-2.0, 0.0, 0.0])
        with self.assertRaises(OutOfRangeError):
            self.coords.world_to_fixed([0.0, 1e9, 0.0])
Пример #4
0
def create_leaf_nodes(mesh,
                      morton_bits=16,
                      round_to_multiple=1,
                      nthreads_per_block=32,
                      max_blocks=16):
    '''Compute the leaf nodes surrounding a triangle mesh.

      ``mesh``: chroma.geometry.Mesh
        Triangles to box
      ``morton_bits``: int
        Number of bits to use per dimension when computing Morton code.
      ``round_to_multiple``: int
        Round the number of nodes created up to multiple of this number
        Extra nodes will be all zero.
        
    Returns (world_coords, nodes, morton_codes), where
      ``world_coords``: chroma.bvh.WorldCoords
        Defines the fixed point coordinate system
      ``nodes``: ndarray(shape=len(mesh.triangles), dtype=uint4)
        List of leaf nodes.  Child IDs will be set to triangle offsets.
      ``morton_codes``: ndarray(shape=len(mesh.triangles), dtype=np.uint64)
        Morton codes for each triangle, using ``morton_bits`` per axis.
        Must be <= 16 bits.
    '''
    # it would be nice not to duplicate code, make functions transparent...
    context = None
    queue = None
    if gpuapi.is_gpu_api_opencl():
        context = cltools.get_last_context()
        #print context
        queue = cl.CommandQueue(context)

    # Load GPU functions
    if gpuapi.is_gpu_api_cuda():
        bvh_module = get_module('bvh.cu',
                                options=api_options,
                                include_source_directory=True)
    elif gpuapi.is_gpu_api_opencl():
        # don't like the last context method. trouble. trouble.
        bvh_module = get_module('bvh.cl',
                                cltools.get_last_context(),
                                options=api_options,
                                include_source_directory=True)
    bvh_funcs = GPUFuncs(bvh_module)

    # compute world coordinates
    world_origin_np = mesh.vertices.min(axis=0)
    world_scale = np.max(
        (mesh.vertices.max(axis=0) - world_origin_np)) / (2**16 - 2)
    world_coords = WorldCoords(world_origin=world_origin_np,
                               world_scale=world_scale)

    # Put triangles and vertices into host and device memory
    # unfortunately, opencl and cuda has different methods for managing memory here
    # we have to write divergent code
    if gpuapi.is_gpu_api_cuda():
        # here cuda supports a nice feature where we allocate host and device memory that are mapped onto one another.
        # no explicit requests for transfers here
        triangles = cutools.mapped_empty(shape=len(mesh.triangles),
                                         dtype=ga.vec.uint3,
                                         write_combined=True)
        triangles[:] = to_uint3(mesh.triangles)
        vertices = cutools.mapped_empty(shape=len(mesh.vertices),
                                        dtype=ga.vec.float3,
                                        write_combined=True)
        vertices[:] = to_float3(mesh.vertices)
        #print triangles[0:10]
        #print vertices[0:10]

        # Call GPU to compute nodes
        nodes = ga.zeros(shape=round_up_to_multiple(len(triangles),
                                                    round_to_multiple),
                         dtype=ga.vec.uint4)
        morton_codes = ga.empty(shape=len(triangles), dtype=np.uint64)

        # Convert world coords to GPU-friendly types
        world_origin = ga.vec.make_float3(*world_origin_np)
        world_scale = np.float32(world_scale)

        # generate morton codes on GPU
        for first_index, elements_this_iter, nblocks_this_iter in \
                chunk_iterator(len(triangles), nthreads_per_block,
                               max_blocks=30000):
            bvh_funcs.make_leaves(np.uint32(first_index),
                                  np.uint32(elements_this_iter),
                                  cutools.Mapped(triangles),
                                  cutools.Mapped(vertices),
                                  world_origin,
                                  world_scale,
                                  nodes,
                                  morton_codes,
                                  block=(nthreads_per_block, 1, 1),
                                  grid=(nblocks_this_iter, 1))

        morton_codes_host = morton_codes.get() >> (16 - morton_bits)

    elif gpuapi.is_gpu_api_opencl():
        # here we need to allocate a buffer on the host and on the device
        triangles = np.empty(len(mesh.triangles), dtype=ga.vec.uint3)
        copy_to_uint3(mesh.triangles, triangles)
        vertices = np.empty(len(mesh.vertices), dtype=ga.vec.float3)
        copy_to_float3(mesh.vertices, vertices)
        # now create a buffer object on the device and push data to it
        triangles_dev = ga.to_device(queue, triangles)
        vertices_dev = ga.to_device(queue, vertices)

        # Call GPU to compute nodes
        nodes = ga.zeros(queue,
                         shape=round_up_to_multiple(len(triangles),
                                                    round_to_multiple),
                         dtype=ga.vec.uint4)
        morton_codes = ga.empty(queue, shape=len(triangles), dtype=np.uint64)

        # Convert world coords to GPU-friendly types
        #world_origin = np.array(world_origin_np,dtype=np.float32)
        world_origin = np.empty(1, dtype=ga.vec.float3)
        world_origin['x'] = world_origin_np[0]
        world_origin['y'] = world_origin_np[1]
        world_origin['z'] = world_origin_np[2]
        world_scale = np.float32(world_scale)
        #print world_origin, world_scale

        # generate morton codes on GPU
        for first_index, elements_this_iter, nblocks_this_iter in \
                chunk_iterator(len(triangles), nthreads_per_block, max_blocks):
            print first_index, elements_this_iter, nblocks_this_iter
            bvh_funcs.make_leaves(
                queue,
                (nblocks_this_iter, 1, 1),
                (nthreads_per_block, 1, 1),
                #bvh_funcs.make_leaves( queue, (elements_this_iter,1,1), None,
                np.uint32(first_index),
                np.uint32(elements_this_iter),
                triangles_dev.data,
                vertices_dev.data,
                world_origin,
                world_scale,
                nodes.data,
                morton_codes.data,
                g_times_l=True).wait()

        morton_codes_host = morton_codes.get() >> (16 - morton_bits)

    return world_coords, nodes.get(), morton_codes_host
Пример #5
0
 def setUp(self):
     self.coords = WorldCoords([-1, -1, -1], 0.1)
Пример #6
0
 def setUp(self):
     self.coords = WorldCoords([-1,-1,-1], 0.1)
Пример #7
0
def create_leaf_nodes(mesh, morton_bits=16, round_to_multiple=1):
    '''Compute the leaf nodes surrounding a triangle mesh.

      ``mesh``: chroma.geometry.Mesh
        Triangles to box
      ``morton_bits``: int
        Number of bits to use per dimension when computing Morton code.
      ``round_to_multiple``: int
        Round the number of nodes created up to multiple of this number
        Extra nodes will be all zero.
        
    Returns (world_coords, nodes, morton_codes), where
      ``world_coords``: chroma.bvh.WorldCoords
        Defines the fixed point coordinate system
      ``nodes``: ndarray(shape=len(mesh.triangles), dtype=uint4)
        List of leaf nodes.  Child IDs will be set to triangle offsets.
      ``morton_codes``: ndarray(shape=len(mesh.triangles), dtype=np.uint64)
        Morton codes for each triangle, using ``morton_bits`` per axis.
        Must be <= 16 bits.
    '''
    # Load GPU functions
    bvh_module = get_cu_module('bvh.cu',
                               options=cuda_options,
                               include_source_directory=True)
    bvh_funcs = GPUFuncs(bvh_module)

    # compute world coordinates
    world_origin = mesh.vertices.min(axis=0)
    world_scale = np.max((mesh.vertices.max(axis=0) - world_origin)) \
        / (2**16 - 2)
    world_coords = WorldCoords(world_origin=world_origin,
                               world_scale=world_scale)

    # Put triangles and vertices in mapped host memory
    triangles = mapped_empty(shape=len(mesh.triangles),
                             dtype=ga.vec.uint3,
                             write_combined=True)
    triangles[:] = to_uint3(mesh.triangles)
    vertices = mapped_empty(shape=len(mesh.vertices),
                            dtype=ga.vec.float3,
                            write_combined=True)
    vertices[:] = to_float3(mesh.vertices)

    # Call GPU to compute nodes
    nodes = ga.zeros(shape=round_up_to_multiple(len(triangles),
                                                round_to_multiple),
                     dtype=ga.vec.uint4)
    morton_codes = ga.empty(shape=len(triangles), dtype=np.uint64)

    # Convert world coords to GPU-friendly types
    world_origin = ga.vec.make_float3(*world_origin)
    world_scale = np.float32(world_scale)

    nthreads_per_block = 256
    for first_index, elements_this_iter, nblocks_this_iter in \
            chunk_iterator(len(triangles), nthreads_per_block,
                           max_blocks=30000):
        bvh_funcs.make_leaves(np.uint32(first_index),
                              np.uint32(elements_this_iter),
                              Mapped(triangles),
                              Mapped(vertices),
                              world_origin,
                              world_scale,
                              nodes,
                              morton_codes,
                              block=(nthreads_per_block, 1, 1),
                              grid=(nblocks_this_iter, 1))

    morton_codes_host = morton_codes.get() >> (16 - morton_bits)
    return world_coords, nodes.get(), morton_codes_host