Beispiel #1
0
    def _finalize_primitive_arrays(self, positions, orientations, colors,
                                   images, normals, indices):
        if orientations is not None:
            images = math.quatrot(orientations, images) + positions
            if normals is not None:
                normals = math.quatrot(orientations, normals)
        else:
            images = images + positions

        unfolded_shape = positions.shape[:-1]
        indices = (np.arange(unfolded_shape[0])[:, np.newaxis, np.newaxis]*unfolded_shape[1] +
                   indices)
        indices = indices.reshape((-1,)).astype(np.uint32)

        prim = self.threejs_primitive

        colors = colors.astype(np.float32).reshape((-1, 4))
        if colors[0, 3] < 1 and np.allclose(colors[:, 3], colors[0, 3]):
            # If all colors have the same alpha, enable material transparency
            prim.material.transparent = True
            prim.material.depthWrite = False
            prim.material.opacity = colors[0, 3]

        attribs = dict(position=pythreejs.BufferAttribute(images.astype(np.float32).reshape((-1, 3))),
                       color=pythreejs.BufferAttribute(colors),
                       index=pythreejs.BufferAttribute(indices))
        if normals is not None:
            attribs['normal'] = pythreejs.BufferAttribute(normals.astype(np.float32).reshape((-1, 3)))

        prim.geometry.attributes = attribs

        prim.geometry.exec_three_obj_method('computeVertexNormals')
        prim.geometry.exec_three_obj_method('normalizeNormals')

        self._dirty_attributes.clear()
Beispiel #2
0
 def _grid_views_default(self):
     # This needs to generate the geometries and access the materials
     grid_views = []
     cmap = mcm.get_cmap("inferno")
     for level in range(self.ds.max_level + 1):
         # We truncate at half of the colormap so that we just get a slight
         # linear progression
         color = mcolors.to_hex(
             cmap(self.cmap_truncate * level / self.ds.max_level))
         # Corners is shaped like 8, 3, NGrids
         this_level = self.ds.index.grid_levels[:, 0] == level
         corners = np.rollaxis(self.ds.index.grid_corners[:, :, this_level],
                               2).astype("float32")
         indices = (((np.arange(corners.shape[0]) * 8)[:, None] +
                     _CORNER_INDICES[None, :]).ravel().astype("uint32"))
         corners.shape = (corners.size // 3, 3)
         geometry = pythreejs.BufferGeometry(attributes=dict(
             position=pythreejs.BufferAttribute(array=corners,
                                                normalized=False),
             index=pythreejs.BufferAttribute(array=indices,
                                             normalized=False),
         ))
         material = pythreejs.LineBasicMaterial(color=color,
                                                linewidth=1,
                                                linecap="round",
                                                linejoin="round")
         segments = pythreejs.LineSegments(geometry=geometry,
                                           material=material)
         grid_views.append(segments)
     return grid_views
Beispiel #3
0
    def mesh(self, colors={}):
        import pythreejs as js
        import numpy as np

        lines = []
        line_colors = []

        red = [1, 0, 0]
        green = [0, 1, 0]
        exterior = self.project(exterior=True)
        interior = self.project(exterior=False)
        for color, polygons in zip([green, red], [exterior, interior]):
            for polygon in polygons:
                for segment in polygon.segments():
                    lines.extend([segment.p1, segment.p2])
                    line_colors.extend([color, color])

        lines = np.array(lines, dtype=np.float32)
        line_colors = np.array(line_colors, dtype=np.float32)
        geometry = js.BufferGeometry(attributes={
            'position':
            js.BufferAttribute(lines, normalized=False),
            'color':
            js.BufferAttribute(line_colors, normalized=False),
        }, )
        material = js.LineBasicMaterial(vertexColors='VertexColors',
                                        linewidth=1)
        return js.LineSegments(geometry, material)
Beispiel #4
0
def build_geometry(triangles, positions, normals=None, colors=None):
    attributes = {
        "position": three.BufferAttribute(
            np.array(positions, dtype="float32").reshape(-1, 3),
            normalized=False,
        ),
        "index": three.BufferAttribute(
            np.array(triangles, dtype="uint32"),
            normalized=False,
        ),
    }
    if normals:
        attributes["normal"] = three.BufferAttribute(
            np.array(normals, dtype="float32").reshape(-1, 3),
            normalized=False,
        )
    if colors:
        attributes["color"] = three.BufferAttribute(
            np.array(colors, dtype="uint8").reshape(-1, 4),
            normalized=False,
        )
    geometry = three.BufferGeometry(attributes=attributes)

    # Compute normals from face geometry if they were not specified.
    if not normals:
        geometry.exec_three_obj_method("computeVertexNormals")

    return geometry
Beispiel #5
0
    def __init__(self, trimesh, uvs, width=512, height=512, duration=5, textureMap = None):
        self.viewer = TriMeshViewer(trimesh, width, height, textureMap)

        flatPosArray = None
        if (uvs.shape[1] == 2): flatPosArray = np.array(np.pad(uvs, [(0, 0), (0, 1)], 'constant'), dtype=np.float32)
        else:                   flatPosArray = np.array(uvs, dtype=np.float32)
        flatPos     = pythreejs.BufferAttribute(array=flatPosArray, normalized=False)
        flatNormals = pythreejs.BufferAttribute(array=np.repeat(np.array([[0, 0, 1]], dtype=np.float32), uvs.shape[0], axis=0), normalized=False)

        geom = self.viewer.currMesh.geometry
        mat  = self.viewer.currMesh.material
        geom.morphAttributes = {'position': [flatPos,], 'normal': [flatNormals,]}

        # Both of these material settings are needed or else our target positions/normals are ignored!
        mat.morphTargets, mat.morphNormals = True, True

        flatteningMesh = pythreejs.Mesh(geometry=geom, material=mat)

        amplitude = np.linspace(-1, 1, 20, dtype=np.float32)
        times = (np.arcsin(amplitude) / np.pi + 0.5) * duration
        blendWeights = 0.5 * (amplitude + 1)
        track = pythreejs.NumberKeyframeTrack('name=.morphTargetInfluences[0]', times = times, values = blendWeights, interpolation='InterpolateSmooth')

        self.action = pythreejs.AnimationAction(pythreejs.AnimationMixer(flatteningMesh),
                                                pythreejs.AnimationClip(tracks=[track]),
                                                flatteningMesh, loop='LoopPingPong')

        self.viewer.meshes.children = [flatteningMesh]

        self.layout = ipywidgets.VBox()
        self.layout.children = [self.viewer.renderer, self.action]
Beispiel #6
0
def get_pointcloud_pythreejs(xyz, colors):
    points_geometry = pythreejs.BufferGeometry(attributes=dict(
        position=pythreejs.BufferAttribute(xyz, normalized=False),
        color=pythreejs.BufferAttribute(list(map(tuple, colors)))))

    points_material = pythreejs.PointsMaterial(vertexColors='VertexColors')

    return pythreejs.Points(geometry=points_geometry, material=points_material)
Beispiel #7
0
def get_voxelgrid_pythreejs(xyz, colors):
    vertices = np.array(np.meshgrid([-0.5, 0.5], [-0.5, 0.5], [-0.5, 0.5]),
                        dtype=np.float32).T.reshape(-1, 3)
    faces = np.array(
        [
            [0, 3, 2],
            [0, 1, 3],  # front
            [1, 7, 3],
            [1, 5, 7],  # right
            [5, 6, 7],
            [5, 4, 6],  # back
            [4, 2, 6],
            [4, 0, 2],  # left
            [2, 7, 6],
            [2, 3, 7],  # top
            [4, 1, 0],
            [4, 5, 1]
        ],  # bottom
        dtype=np.uint32)
    colors = pythreejs.InstancedBufferAttribute(array=colors,
                                                meshPerAttribute=3)
    offsets = pythreejs.InstancedBufferAttribute(array=xyz, meshPerAttribute=3)

    instanced_geometry = pythreejs.InstancedBufferGeometry(
        attributes={
            "position": pythreejs.BufferAttribute(array=vertices),
            "index": pythreejs.BufferAttribute(array=faces.ravel()),
            "offset": offsets,
            "color": colors,
        })

    material = pythreejs.ShaderMaterial(vertexShader='''
    precision highp float;
    attribute vec3 offset;
    varying vec3 vPosition;
    varying vec4 vColor;
    void main(){

        vPosition = position + offset;
        vColor = vec4( color, 1 );
        gl_Position = projectionMatrix * modelViewMatrix * vec4( vPosition, 1.0 );
    }
    ''',
                                        fragmentShader='''
    precision highp float;
    varying vec4 vColor;
    void main() {
        gl_FragColor = vec4( vColor );
    }
    ''',
                                        vertexColors='VertexColors',
                                        transparent=False)

    return pythreejs.Mesh(instanced_geometry, material, frustumCulled=False)
Beispiel #8
0
    def add_points(self, points, c=None, shading={}, obj=None, **kwargs):
        shading.update(kwargs)
        if len(points.shape) == 1:
            if len(points) == 2:
                points = np.array([[points[0], points[1], 0]])
        else:
            if points.shape[1] == 2:
                points = np.append(points, np.zeros([points.shape[0], 1]), 1)
        sh = self.__get_shading(shading)
        points = points.astype("float32", copy=False)
        mi = np.min(points, axis=0)
        ma = np.max(points, axis=0)

        g_attributes = {
            "position": p3s.BufferAttribute(points, normalized=False)
        }
        m_attributes = {"size": sh["point_size"]}

        if sh["point_shape"] == "circle":  # Plot circles
            tex = p3s.DataTexture(data=gen_circle(16, 16),
                                  format="RGBAFormat",
                                  type="FloatType")
            m_attributes["map"] = tex
            m_attributes["alphaTest"] = 0.5
            m_attributes["transparency"] = True
        else:  # Plot squares
            pass

        colors, v_colors = self.__get_point_colors(points, c, sh)
        if v_colors:  # Colors per point
            m_attributes["vertexColors"] = 'VertexColors'
            g_attributes["color"] = p3s.BufferAttribute(colors,
                                                        normalized=False)

        else:  # Colors for all points
            m_attributes["color"] = colors

        material = p3s.PointsMaterial(**m_attributes)
        geometry = p3s.BufferGeometry(attributes=g_attributes)
        points = p3s.Points(geometry=geometry, material=material)
        point_obj = {
            "geometry": geometry,
            "mesh": points,
            "material": material,
            "max": ma,
            "min": mi,
            "type": "Points",
            "wireframe": None
        }

        if obj:
            return self.__add_object(point_obj, obj), point_obj
        else:
            return self.__add_object(point_obj)
Beispiel #9
0
 def create_points_geometry(self):
     """
     Make a PointsGeometry using pythreejs
     """
     points_geometry = p3.BufferGeometry(
         attributes={
             'position': p3.BufferAttribute(array=self.positions),
             'rgba_color': p3.BufferAttribute(array=self.slice_data(None))
         })
     points_material = self.create_points_material()
     points = p3.Points(geometry=points_geometry, material=points_material)
     return points_geometry, points_material, points
Beispiel #10
0
 def _create_point_cloud(self, pos_array):
     """
     Make a PointsGeometry using pythreejs
     """
     rgba_shape = list(pos_array.shape)
     rgba_shape[1] += 1
     self.points_geometry = p3.BufferGeometry(
         attributes={
             'position':
             p3.BufferAttribute(array=pos_array),
             'rgba_color':
             p3.BufferAttribute(array=np.ones(rgba_shape, dtype=np.float32))
         })
     self.point_cloud = p3.Points(geometry=self.points_geometry,
                                  material=self.points_material)
Beispiel #11
0
        def traverse_func(node, trans):
            # Underlying mesh
            mesh = node.primitive.mesh
            if mesh is None:
                return

            # Iterate through all triangles
            vs = []

            def process_triangle(face_index, tri):
                vs.append(list(tri.p1.p))
                vs.append(list(tri.p2.p))
                vs.append(list(tri.p3.p))

            mesh.foreach_triangle(process_triangle)

            # Create geometry
            ps_attr = three.BufferAttribute(array=vs, normalized=False)
            geom = three.BufferGeometry(attributes={'position': ps_attr})

            # Create mesh
            mesh = three.Mesh(geometry=geom, material=mat_default)
            mesh.matrixAutoUpdate = False
            mesh.matrix = trans.T.flatten().tolist()
            scene.add(mesh)
Beispiel #12
0
 def geometry(self):
     attributes = dict(
         position=pythreejs.BufferAttribute(self.vertices, normalized=False),
         index=pythreejs.BufferAttribute(
             self.indices.ravel(order="C").astype("u4"), normalized=False
         ),
     )
     if self.attributes is not None:
         attributes["color"] = pythreejs.BufferAttribute(self.attributes)
         # Face colors requires
         # https://speakerdeck.com/yomotsu/low-level-apis-using-three-dot-js?slide=22
         # and
         # https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderLib.js
     geometry = pythreejs.BufferGeometry(attributes=attributes)
     geometry.exec_three_obj_method("computeFaceNormals")
     return geometry
Beispiel #13
0
    def __add_line_geometry(self, lines, shading, obj=None):
        lines = lines.astype("float32", copy=False)
        mi = np.min(lines, axis=0)
        ma = np.max(lines, axis=0)
        geometry = p3s.BufferGeometry(
            attributes={
                'position': p3s.BufferAttribute(lines, normalized=False)
            })
        material = p3s.LineBasicMaterial(linewidth=shading["line_width"],
                                         color=shading["line_color"])
        #, vertexColors='VertexColors'),
        lines = p3s.LineSegments(geometry=geometry,
                                 material=material)  #type='LinePieces')
        line_obj = {
            "geometry": geometry,
            "mesh": lines,
            "material": material,
            "max": ma,
            "min": mi,
            "type": "Lines",
            "wireframe": None
        }

        if obj:
            return self.__add_object(line_obj, obj), line_obj
        else:
            return self.__add_object(line_obj)
Beispiel #14
0
def scatter_children(points, color="red", size=4):
    scene_children = []
    geometry_point = p3js.BufferGeometry(
        attributes={"position": p3js.BufferAttribute(array=points)})
    material_point = p3js.PointsMaterial(color=color, size=size)
    pts = p3js.Points(geometry_point, material_point)
    scene_children.append(pts)
    return scene_children
def buffer_normals(trimesh):
    """Extract surface normals and return a buffer attribute."""
    if 'Normals' in trimesh.point_data:
        normals = trimesh.point_data['Normals']
    else:
        normals = trimesh.point_normals
    normals = normals.astype(np.float32, copy=False)
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", message="Given trait value dtype")
        return tjs.BufferAttribute(array=normals)
def array_to_float_buffer(points):
    """Convert a numpy array to a pythreejs compatible point buffer."""
    # create buffered points
    points = points.astype(np.float32, copy=False)

    # ignore invalid warning.  BufferAttribute type is None and is
    # improperly recognized as float64.  Same for the rest
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", message="Given trait value dtype")
        position = tjs.BufferAttribute(array=points, normalized=False)
    return position
def cast_to_min_size(ind, max_index):
    """Return a buffered attribute of the minimum index size."""
    ind = ind.ravel()
    if max_index < np.iinfo(np.uint16).max:
        ind = ind.astype(np.uint16, copy=False)
    elif max_index < np.iinfo(np.uint32).max:
        ind = ind.astype(np.uint32, copy=False)
    else:
        raise ValueError(
            'pythreejs does not support a maximum index more than '
            f'{np.iinfo(np.uint32).max}')
    return tjs.BufferAttribute(array=ind, normalized=False)
Beispiel #18
0
    def visualize(self, colors={}):
        from ..space import Vector
        import pythreejs as js
        import numpy as np

        prior = Motion(x=0, y=0, z=0, f=0)
        lines = []
        line_colors = []

        for parent, command in self.commands():
            if isinstance(command, Motion):
                updated = prior.merge(command)
                pv = Vector(*prior.xyz)
                uv = Vector(*updated.xyz)
                delta = pv - uv
                start = (uv + pv) / 2
                lines.extend([prior.xyz, updated.xyz])
                a1 = delta.rotate(Vector(0, 0, 1), tau / 16) * 0.1
                a2 = delta.rotate(Vector(0, 0, 1), -tau / 16) * 0.1
                lines.extend(
                    [start, (a1 + start).xyz, start, (a2 + start).xyz])
                prior = updated
                color = getattr(parent, 'color', [0, 1, 0])
                line_colors.extend([color, color])
                line_colors.extend([color, color])
                line_colors.extend([color, color])

        lines = np.array(lines, dtype=np.float32)
        line_colors = np.array(line_colors, dtype=np.float32)
        geometry = js.BufferGeometry(attributes={
            'position':
            js.BufferAttribute(lines, normalized=False),
            'color':
            js.BufferAttribute(line_colors, normalized=False),
        }, )
        material = js.LineBasicMaterial(vertexColors='VertexColors',
                                        linewidth=1)
        return js.LineSegments(geometry, material)
Beispiel #19
0
    def getArrows(self,
                  visVertices,
                  visTris,
                  vmin=None,
                  vmax=None,
                  alpha=1.0,
                  material=None,
                  existingMesh=None):
        vectors, colors, mask = self.arrowData(vmin, vmax, alpha)
        V, N, F = self.arrowGeometry()
        pos = None
        if (self.domainType == DomainType.PER_VTX): pos = visVertices
        if (self.domainType == DomainType.PER_TRI):
            pos = np.mean(visVertices[visTris], axis=1)  # triangle barycenters
        pos = pos[mask]

        if (pos is None): raise Exception('Unhandled domainType')

        if (material is None):
            material = vis.shaders.loadShaderMaterial('vector_field')

        rawInstancedAttr = {
            'arrowColor': np.array(colors, dtype=np.float32),
            'arrowVec': np.array(vectors, dtype=np.float32),
            'arrowPos': np.array(pos, dtype=np.float32)
        }
        rawAttr = {'position': V, 'index': F.ravel(), 'normal': N}

        arrowMesh = None
        if (existingMesh is None):
            attr = {
                k: pythreejs.InstancedBufferAttribute(v)
                for k, v in rawInstancedAttr.items()
            }
            attr.update(
                {k: pythreejs.BufferAttribute(v)
                 for k, v in rawAttr.items()})
            ibg = pythreejs.InstancedBufferGeometry(attributes=attr)
            arrowMesh = pythreejs.Mesh(
                geometry=ibg, material=material, frustumCulled=False
            )  # disable frustum culling since our vertex shader moves arrows around.
        else:
            for k, v in rawInstancedAttr.items(
            ):  # position/index/normal should be constant...
                existingMesh.geometry.attributes[k].array = v
            arrowMesh = existingMesh
            existingMesh.geometry.maxInstancedCount = pos.shape[
                0]  # threejs does not automatically update maxInstancedCount after it is initialized to the full count of the original arrays by the renderer

        return arrowMesh
Beispiel #20
0
def display_portal(th_scene, portal):
    """Display portal."""
    def portal_vertices(portal):
        p1 = np.array(portal[0])
        p2 = np.array(portal[1])
        p4 = np.array(portal[2])
        p3 = p1 + (p2 - p1) + (p4 - p1)
        return [p1, p2, p3, p1, p3, p4]

    ps_attr = three.BufferAttribute(array=portal_vertices(portal),
                                    normalized=False)
    geom = three.BufferGeometry(attributes={'position': ps_attr})
    mat = three.MeshBasicMaterial(color='#ff0000',
                                  transparent=True,
                                  opacity=0.1,
                                  side='DoubleSide')
    mesh = three.Mesh(geometry=geom, material=mat)
    th_scene.add(mesh)
Beispiel #21
0
 def _get_mesh(self, u):
     if self.codim == 2:
         u = u[self.entity_map]
     elif self.grid.reference_element == triangle:
         u = np.repeat(u, 3)
     else:
         u = np.tile(np.repeat(u, 3), 2)
     data = p3js.BufferAttribute(_normalize(u, self.vmin, self.vmax),
                                 normalized=True)
     geo = p3js.BufferGeometry(
         index=self.buffer_faces,
         attributes=dict(position=self.buffer_vertices, data=data))
     mesh = p3js.Mesh(geometry=geo, material=self.material)
     mesh.visible = False
     # translate to origin where the camera is looking by default, avoids camera not updating in nbconvert run
     mesh.position = tuple(p - i
                           for p, i in zip(mesh.position, self.mesh_center))
     return mesh
Beispiel #22
0
def axes_1d(x, y, color="#000000", linewidth=1.5):

    N = len(x)

    pts = np.zeros([5, 3])

    xmin = np.amin(x)
    xmax = np.amax(x)
    ymin = np.amin(y)
    ymax = np.amax(y)

    pts[:, 0] = x
    pts[:, 1] = y
    geometry = p3.BufferGeometry(attributes={
        'position': p3.BufferAttribute(array=pts),
    })
    material = p3.LineBasicMaterial(color=color, linewidth=linewidth)
    line = p3.Line(geometry=geometry, material=material)
    width = 800
    height = 500
Beispiel #23
0
        def allocateUpdateOrStashBufferAttribute(attr, key):
            # Verify invariant that attributes, if they exist, must either be
            # attached to the current geometry or in the stash (but not both)
            assert((key not in attr) or (key not in self.bufferAttributeStash))

            if key in attrRaw:
                if key in self.bufferAttributeStash:
                    # Reuse the stashed index buffer
                    attr[key] = self.bufferAttributeStash[key]
                    self.bufferAttributeStash.pop(key)

                # Update existing attribute or allocate it for the first time
                if key in attr:
                    attr[key].array = attrRaw[key]
                else:
                    attr[key] = pythreejs.BufferAttribute(attrRaw[key])
            else:
                if key in attr:
                    # Stash the existing, unneeded attribute
                    self.bufferAttributeStash[key] = attr[key]
                    attr.pop(key)
Beispiel #24
0
def plot_1d(x, y, color="blue", linewidth=2, background="#DDDDDD"):

    if len(x) != len(y):
        raise RuntimeError("bad shape")

    N = len(x)

    dx = config.figure["width"]
    dy = config.figure["height"]

    xmin = np.amin(x)
    ymin = np.amin(y)

    scale_x = dx / (np.amax(x) - xmin)
    scale_y = dy / (np.amax(y) - ymin)

    pts = np.zeros([N, 3], dtype=np.float32)
    pts[:, 0] = (x - xmin) * scale_x
    pts[:, 1] = (y - ymin) * scale_y
    # arr = p3.BufferAttribute(array=pts)
    geometry = p3.BufferGeometry(attributes={
        'position': p3.BufferAttribute(array=pts),
    })
    material = p3.LineBasicMaterial(color=color, linewidth=linewidth)
    line = p3.Line(geometry=geometry, material=material)
    # width = 800
    # height= 500

    # Create the threejs scene with ambient light and camera
    # camera = p3.PerspectiveCamera(position=[0.5*dx, 0.5*dy, 0],
    #                                         aspect=dx / dy)
    camera = p3.OrthographicCamera(0, dx, dy, 0, 0.5 * dx, -0.5 * dx)

    return render(objects=line,
                  camera=camera,
                  background=background,
                  enableRotate=False,
                  width=dx,
                  height=dy)
Beispiel #25
0
def mesh_animation(times, xt, faces):
    """ Animate a mesh from a sequence of mesh vertex positions

        Args:
        times   - a list of time values t_i at which the configuration x is specified
        xt      -   i.e., x(t). A list of arrays representing mesh vertex positions at times t_i.
                    Dimensions of each array should be the same as that of mesh.geometry.array
        TODO nt - n(t) vertex normals
        faces    - array of faces, with vertex loop for each face

        Side effects:
            displays rendering of mesh, with animation action

        Returns: None
        TODO renderer - THREE.Render to show the default scene
        TODO position_action - THREE.AnimationAction IPython widget
    """

    position_morph_attrs = []
    for pos in xt[
            1:]:  # xt[0] uses as the Mesh's default/initial vertex position
        position_morph_attrs.append(
            THREE.BufferAttribute(pos, normalized=False))

    # Testing mesh.geometry.morphAttributes = {'position': position_morph_attrs}
    geom = THREE.BufferGeometry(
        attributes={
            'position': THREE.BufferAttribute(xt[0], normalized=False),
            'index': THREE.BufferAttribute(faces.ravel())
        },
        morphAttributes={'position': position_morph_attrs})
    matl = THREE.MeshStandardMaterial(side='DoubleSide',
                                      color='red',
                                      wireframe=True,
                                      morphTargets=True)

    mesh = THREE.Mesh(geom, matl)

    # create key frames
    position_track = THREE.NumberKeyframeTrack(
        name='.morphTargetInfluences[0]',
        times=times,
        values=list(range(0, len(times))))
    # create animation clip from the morph targets
    position_clip = THREE.AnimationClip(tracks=[position_track])
    # create animation action
    position_action = THREE.AnimationAction(THREE.AnimationMixer(mesh),
                                            position_clip, mesh)

    # TESTING
    camera = THREE.PerspectiveCamera(position=[2, 1, 2], aspect=600 / 400)
    scene = THREE.Scene(children=[
        mesh, camera,
        THREE.AxesHelper(0.2),
        THREE.DirectionalLight(position=[3, 5, 1], intensity=0.6),
        THREE.AmbientLight(intensity=0.5)
    ])
    renderer = THREE.Renderer(
        camera=camera,
        scene=scene,
        controls=[THREE.OrbitControls(controlling=camera)],
        width=600,
        height=400)

    display(renderer, position_action)
Beispiel #26
0
    def _render_obj(self, rendered_obj, **kw):
        obj_geometry = pjs.BufferGeometry(attributes=dict(
            position=pjs.BufferAttribute(rendered_obj.plot_verts),
            color=pjs.BufferAttribute(rendered_obj.base_cols),
            normal=pjs.BufferAttribute(
                rendered_obj.face_normals.astype('float32'))))
        vertices = rendered_obj.vertices

        # Create a mesh. Note that the material need to be told to use the vertex colors.
        my_object_mesh = pjs.Mesh(
            geometry=obj_geometry,
            material=pjs.MeshLambertMaterial(vertexColors='VertexColors'),
            position=[0, 0, 0],
        )

        line_material = pjs.LineBasicMaterial(color='#ffffff',
                                              transparent=True,
                                              opacity=0.3,
                                              linewidth=1.0)
        my_object_wireframe_mesh = pjs.LineSegments(
            geometry=obj_geometry,
            material=line_material,
            position=[0, 0, 0],
        )

        n_vert = vertices.shape[0]
        center = vertices.mean(axis=0)

        extents = self._get_extents(vertices)
        max_delta = np.max(extents[:, 1] - extents[:, 0])
        camPos = [center[i] + 4 * max_delta for i in range(3)]
        light_pos = [center[i] + (i + 3) * max_delta for i in range(3)]

        # Set up a scene and render it:
        camera = pjs.PerspectiveCamera(position=camPos,
                                       fov=20,
                                       children=[
                                           pjs.DirectionalLight(
                                               color='#ffffff',
                                               position=light_pos,
                                               intensity=0.5)
                                       ])
        camera.up = (0, 0, 1)

        v = [0.0, 0.0, 0.0]
        if n_vert > 0: v = vertices[0].tolist()
        select_point_geom = pjs.SphereGeometry(radius=1.0)
        select_point_mesh = pjs.Mesh(
            select_point_geom,
            material=pjs.MeshBasicMaterial(color=SELECTED_VERTEX_COLOR),
            position=v,
            scale=(0.0, 0.0, 0.0))

        #select_edge_mesh = pjs.ArrowHelper(dir=pjs.Vector3(1.0, 0.0, 0.0), origin=pjs.Vector3(0.0, 0.0, 0.0), length=1.0,
        #                                  hex=SELECTED_EDGE_COLOR_INT, headLength=0.1, headWidth=0.05)

        arrow_cyl_mesh = pjs.Mesh(geometry=pjs.SphereGeometry(radius=0.01),
                                  material=pjs.MeshLambertMaterial())
        arrow_head_mesh = pjs.Mesh(geometry=pjs.SphereGeometry(radius=0.001),
                                   material=pjs.MeshLambertMaterial())

        scene_things = [
            my_object_mesh, my_object_wireframe_mesh, select_point_mesh,
            arrow_cyl_mesh, arrow_head_mesh, camera,
            pjs.AmbientLight(color='#888888')
        ]

        if self.draw_grids:
            grids, space = self._get_grids(vertices)
            scene_things.append(grids)

        scene = pjs.Scene(children=scene_things, background=BACKGROUND_COLOR)

        click_picker = pjs.Picker(controlling=my_object_mesh, event='dblclick')
        out = Output()
        top_msg = HTML()

        def on_dblclick(change):
            if change['name'] == 'point':
                try:
                    point = np.array(change['new'])
                    face = click_picker.faceIndex
                    face_points = rendered_obj.face_verts[face]
                    face_vecs = face_points - np.roll(face_points, 1, axis=0)
                    edge_lens = np.sqrt((face_vecs**2).sum(axis=1))
                    point_vecs = face_points - point[np.newaxis, :]
                    point_dists = (point_vecs**2).sum(axis=1)
                    min_point = np.argmin(point_dists)
                    v1s = point_vecs.copy()
                    v2s = np.roll(v1s, -1, axis=0)
                    edge_mids = 0.5 * (v2s + v1s)
                    edge_mid_dists = (edge_mids**2).sum(axis=1)
                    min_edge_point = np.argmin(edge_mid_dists)
                    edge_start = min_edge_point
                    edge = face * 3 + edge_start
                    close_vert = rendered_obj.face_verts[face, min_point]
                    edge_start_vert = rendered_obj.face_verts[face, edge_start]
                    edge_end_vert = rendered_obj.face_verts[face,
                                                            (edge_start + 1) %
                                                            3]

                    vertex = face * 3 + min_point
                    radius = min(
                        [edge_lens.max() * 0.02, 0.1 * edge_lens.min()])

                    edge_head_length = radius * 4
                    edge_head_width = radius * 2
                    select_point_mesh.scale = (radius, radius, radius)
                    top_msg.value = '<font color="{}">selected face: {}</font>, <font color="{}">edge: {}</font>, <font color="{}"> vertex: {}</font>'.format(
                        SELECTED_FACE_COLOR, face, SELECTED_EDGE_COLOR, edge,
                        SELECTED_VERTEX_COLOR, vertex)
                    newcols = rendered_obj.base_cols.copy()
                    newcols[face * 3:(face + 1) * 3] = np.array(
                        SELECTED_FACE_RGB, dtype='float32')
                    select_point_mesh.position = close_vert.tolist()
                    obj_geometry.attributes['color'].array = newcols

                    with out:
                        make_arrow(arrow_cyl_mesh, arrow_head_mesh,
                                   edge_start_vert, edge_end_vert, radius / 2,
                                   radius, radius * 3, SELECTED_EDGE_COLOR)

                except:
                    with out:
                        print(traceback.format_exc())

        click_picker.observe(on_dblclick, names=['point'])

        renderer_obj = pjs.Renderer(
            camera=camera,
            background='#cccc88',
            background_opacity=0,
            scene=scene,
            controls=[pjs.OrbitControls(controlling=camera), click_picker],
            width=self.width,
            height=self.height)

        display_things = [top_msg, renderer_obj, out]
        if self.draw_grids:
            s = """
<svg width="{}" height="30">
<rect width="20" height="20" x="{}" y="0" style="fill:none;stroke-width:1;stroke:rgb(0,255,0)" />
    <text x="{}" y="15">={:.1f}</text>
  Sorry, your browser does not support inline SVG.
</svg>""".format(self.width, self.width // 2, self.width // 2 + 25, space)
            display_things.append(HTML(s))

        display(VBox(display_things))
Beispiel #27
0
    def add_mesh(self, v, f, c=None, uv=None, shading={}, texture_data=None):
        sh = self.__get_shading(shading)
        mesh_obj = {}

        #it is a tet
        if v.shape[1] == 3 and f.shape[1] == 4:
            f_tmp = np.ndarray([f.shape[0]*4, 3], dtype=f.dtype)
            for i in range(f.shape[0]):
                f_tmp[i*4+0] = np.array([f[i][1], f[i][0], f[i][2]])
                f_tmp[i*4+1] = np.array([f[i][0], f[i][1], f[i][3]])
                f_tmp[i*4+2] = np.array([f[i][1], f[i][2], f[i][3]])
                f_tmp[i*4+3] = np.array([f[i][2], f[i][0], f[i][3]])
            f = f_tmp

        if v.shape[1] == 2:
            v = np.append(v, np.zeros([v.shape[0], 1]), 1)


        # Type adjustment vertices
        v = v.astype("float32", copy=False)

        # Color setup
        colors, coloring = self.__get_colors(v, f, c, sh)

        # Type adjustment faces and colors
        c = colors.astype("float32", copy=False)

        # Material and geometry setup
        ba_dict = {"color": p3s.BufferAttribute(c)}
        if coloring == "FaceColors":
            verts = np.zeros((f.shape[0]*3, 3), dtype="float32")
            for ii in range(f.shape[0]):
                #print(ii*3, f[ii])
                verts[ii*3] = v[f[ii,0]]
                verts[ii*3+1] = v[f[ii,1]]
                verts[ii*3+2] = v[f[ii,2]]
            v = verts
        else:
            f = f.astype("uint32", copy=False).ravel()
            ba_dict["index"] = p3s.BufferAttribute(f, normalized=False)

        ba_dict["position"] = p3s.BufferAttribute(v, normalized=False)

        if type(uv) != type(None):
            uv = (uv - np.min(uv)) / (np.max(uv) - np.min(uv))
            if texture_data is None:
                texture_data = gen_checkers(20, 20)
            tex = p3s.DataTexture(data=texture_data, format="RGBFormat", type="FloatType")
            material = p3s.MeshStandardMaterial(map=tex, reflectivity=sh["reflectivity"], side=sh["side"],
                    roughness=sh["roughness"], metalness=sh["metalness"], flatShading=sh["flat"],
                    polygonOffset=True, polygonOffsetFactor= 1, polygonOffsetUnits=5)
            ba_dict["uv"] = p3s.BufferAttribute(uv.astype("float32", copy=False))
        else:
            material = p3s.MeshStandardMaterial(vertexColors=coloring, reflectivity=sh["reflectivity"],
                    side=sh["side"], roughness=sh["roughness"], metalness=sh["metalness"],
                    flatShading=sh["flat"],
                    polygonOffset=True, polygonOffsetFactor= 1, polygonOffsetUnits=5)

        geometry = p3s.BufferGeometry(attributes=ba_dict)

        if coloring == "VertexColors":
            geometry.exec_three_obj_method('computeVertexNormals')
        else:
            geometry.exec_three_obj_method('computeFaceNormals')

        # Mesh setup
        mesh = p3s.Mesh(geometry=geometry, material=material)

        # Wireframe setup
        mesh_obj["wireframe"] = None
        if sh["wireframe"]:
            wf_geometry = p3s.WireframeGeometry(mesh.geometry) # WireframeGeometry
            wf_material = p3s.LineBasicMaterial(color=sh["wire_color"], linewidth=sh["wire_width"])
            wireframe = p3s.LineSegments(wf_geometry, wf_material)
            mesh.add(wireframe)
            mesh_obj["wireframe"] = wireframe

        # Bounding box setup
        if sh["bbox"]:
            v_box, f_box = self.__get_bbox(v)
            _, bbox = self.add_edges(v_box, f_box, sh, mesh)
            mesh_obj["bbox"] = [bbox, v_box, f_box]

        # Object setup
        mesh_obj["max"] = np.max(v, axis=0)
        mesh_obj["min"] = np.min(v, axis=0)
        mesh_obj["geometry"] = geometry
        mesh_obj["mesh"] = mesh
        mesh_obj["material"] = material
        mesh_obj["type"] = "Mesh"
        mesh_obj["shading"] = sh
        mesh_obj["coloring"] = coloring
        mesh_obj["arrays"] = [v, f, c] # TODO replays with proper storage or remove if not needed

        return self.__add_object(mesh_obj)
Beispiel #28
0
    def setGeometry(self, vertices, idxs, normals, preserveExisting=False, updateModelMatrix=False, textureMap=None, scalarField=None, vectorField=None):
        self.scalarField = scalarField
        self.vectorField = vectorField

        if (updateModelMatrix):
            translate = -np.mean(vertices, axis=0)
            self.bbSize = np.max(np.abs(vertices + translate))
            scaleFactor = 2.0 / self.bbSize
            self.objects.scale = [scaleFactor, scaleFactor, scaleFactor]
            self.objects.position = tuple(scaleFactor * translate)

        ########################################################################
        # Construct the raw attributes describing the new mesh.
        ########################################################################
        attrRaw = {'position': vertices,
                   'index':    idxs.ravel(),
                   'normal':   normals}

        if (textureMap is not None): attrRaw['uv'] = np.array(textureMap.uv, dtype=np.float32)

        useVertexColors = False
        if (self.scalarField is not None):
            # Construct scalar field from raw data array if necessary
            if (not isinstance(self.scalarField, ScalarField)):
                self.scalarField = ScalarField(self.mesh, self.scalarField)
            self.scalarField.validateSize(vertices.shape[0], idxs.shape[0])

            attrRaw['color'] = np.array(self.scalarField.colors(), dtype=np.float32)
            if (self.scalarField.domainType == DomainType.PER_TRI):
                # Replicate vertex data in the per-face case (positions, normal, uv) and remove index buffer; replicate colors x3
                # This is needed according to https://stackoverflow.com/questions/41670308/three-buffergeometry-how-do-i-manually-set-face-colors
                # since apparently indexed geometry doesn't support the 'FaceColors' option.
                replicateAttributesPerTriCorner(attrRaw)
            useVertexColors = True

        # Turn the current mesh into a ghost if preserveExisting
        if (preserveExisting and (self.currMesh is not None)):
            oldMesh = self.currMesh
            self.currMesh = None
            oldMesh.material = self.materialLibrary.ghostMaterial(oldMesh.material)
            self.meshes.remove(oldMesh)
            self.ghostMeshes.add(oldMesh)

            # Also convert the current vector field into a ghost (if one is displayed)
            if (self.vectorFieldMesh in self.meshes.children):
                oldVFMesh = self.vectorFieldMesh
                self.vectorFieldMesh = None
                oldVFMesh.material.transparent = True
                colors = oldVFMesh.geometry.attributes['arrowColor'].array
                colors[:, 3] = 0.25
                oldVFMesh.geometry.attributes['arrowColor'].array = colors
                self.meshes.remove(oldVFMesh)
                self.ghostMeshes.add(oldVFMesh)
        else:
            self.__cleanMeshes(self.ghostMeshes)

        material = self.materialLibrary.material(useVertexColors, None if textureMap is None else textureMap.dataTex)

        ########################################################################
        # Build or update mesh from the raw attributes.
        ########################################################################
        stashableKeys = ['index', 'color', 'uv']
        def allocateUpdateOrStashBufferAttribute(attr, key):
            # Verify invariant that attributes, if they exist, must either be
            # attached to the current geometry or in the stash (but not both)
            assert((key not in attr) or (key not in self.bufferAttributeStash))

            if key in attrRaw:
                if key in self.bufferAttributeStash:
                    # Reuse the stashed index buffer
                    attr[key] = self.bufferAttributeStash[key]
                    self.bufferAttributeStash.pop(key)

                # Update existing attribute or allocate it for the first time
                if key in attr:
                    attr[key].array = attrRaw[key]
                else:
                    attr[key] = pythreejs.BufferAttribute(attrRaw[key])
            else:
                if key in attr:
                    # Stash the existing, unneeded attribute
                    self.bufferAttributeStash[key] = attr[key]
                    attr.pop(key)

        # Avoid flicker/partial redraws during updates
        if self.avoidRedrawFlicker:
            self.renderer.pauseRendering()

        if (self.currMesh is None):
            attr = {}

            presentKeys = list(attrRaw.keys())
            for key in presentKeys:
                if key in stashableKeys:
                    allocateUpdateOrStashBufferAttribute(attr, key)
                    attrRaw.pop(key)
            attr.update({k: pythreejs.BufferAttribute(v) for k, v in attrRaw.items()})

            geom = pythreejs.BufferGeometry(attributes=attr)
            m = self.MeshConstructor(geometry=geom, material=material)
            self.currMesh = m
            self.meshes.add(m)
        else:
            # Update the current mesh...
            attr = self.currMesh.geometry.attributes.copy()
            attr['position'].array = attrRaw['position']
            attr['normal'  ].array = attrRaw['normal']

            for key in stashableKeys:
                allocateUpdateOrStashBufferAttribute(attr, key)

            self.currMesh.geometry.attributes = attr
            self.currMesh.material = material

        # If we reallocated the current mesh (preserveExisting), we need to point
        # the wireframe/points mesh at the new geometry.
        if self.wireframeMesh is not None:
            self.wireframeMesh.geometry = self.currMesh.geometry
        if self.pointsMesh is not None:
            self.pointsMesh.geometry = self.currMesh.geometry

        ########################################################################
        # Build/update the vector field mesh if requested (otherwise hide it).
        ########################################################################
        if (self.vectorField is not None):
            # Construct vector field from raw data array if necessary
            if (not isinstance(self.vectorField, VectorField)):
                self.vectorField = VectorField(self.mesh, self.vectorField)
            self.vectorField.validateSize(vertices.shape[0], idxs.shape[0])

            self.vectorFieldMesh = self.vectorField.getArrows(vertices, idxs, material=self.arrowMaterial, existingMesh=self.vectorFieldMesh)

            self.arrowMaterial = self.vectorFieldMesh.material
            self.arrowMaterial.updateUniforms(arrowSizePx_x  = self.arrowSize,
                                              rendererWidth  = self.renderer.width,
                                              targetDepth    = np.linalg.norm(np.array(self.cam.position) - np.array(self.controls.target)),
                                              arrowAlignment = self.vectorField.align.getRelativeOffset())
            self.controls.shaderMaterial = self.arrowMaterial
            if (self.vectorFieldMesh not in self.meshes.children):
                self.meshes.add(self.vectorFieldMesh)
        else:
            if (self.vectorFieldMesh in self.meshes.children):
                self.meshes.remove(self.vectorFieldMesh)

        if self.avoidRedrawFlicker:
            # The scene is now complete; reenable rendering and redraw immediatley.
            self.renderer.resumeRendering()
Beispiel #29
0
 def __as_buffer_attr(self, array):
     return three.BufferAttribute(array, normalized=False, dynamic=True)
Beispiel #30
0
 def __as_buffer_attr(self, array):
     #BufferAttribute stores data for an attribute (such as vertex positions, face indices etc) associated with a BufferGeometry,
     return three.BufferAttribute(array, normalized = False, dynamic = True)