Esempio n. 1
0
def calculateFaceforwardNormal(geo_info, camera_location, obj_location):
    '''
    calculate the face normal forward to the camera
    returned data is [normal, face_center, cam_position] in world space
    '''
    if not geo_info:
        print 'Error, invalid geo_info'
        return []
    vertex_list_local = geo_info[geo_info.keys()[0]]['vertex']
    face_center_local = geo_info[geo_info.keys()[0]]['center']
    # get object matrix
    obj_matrix = kcf.getWorldXform(obj_location)
    if not obj_matrix:
        print 'Error, failed to get world matrix at location: '+obj_location
        return []
    # convert to world space
    vertex_list = []
    face_center = []
    obj_matrix = km.list_to_matrix(obj_matrix[0])
    if not km.is_same_matrix(obj_matrix, km.matrix_identity(4)):
        for v in vertex_list_local:
            vertex_list.append( list(km.matrix_mul(v+[1], obj_matrix)[0][:-1]) )
        face_center.extend( list(km.matrix_mul(face_center_local+[1], obj_matrix)[0][:-1]) )
    else:
        vertex_list = vertex_list_local
        face_center = face_center_local

    # get the normal
    if len(vertex_list)<3:
        print 'Error, need at least three vertices to calculate the face normal'
        return []
    v0 = km.subtract( vertex_list[0], vertex_list[1] )
    v1 = km.subtract( vertex_list[1], vertex_list[2] )
    normal = km.vector_unit( km.cross(v0, v1) )

    # get the camera matrix
    cam_matrix = kcf.getWorldXform(camera_location)
    if not cam_matrix or not cam_matrix[0]:
        print 'Error, failed to get camera matrix'
        return []
    cam_matrix = km.list_to_matrix(list(cam_matrix[0]))
    cam_position = [cam_matrix[3][0], cam_matrix[3][1], cam_matrix[3][2]]
    # get unit z from camera in world space
    cam_z = km.vector_unit( km.matrix_mul( km.list_to_matrix([0,0,1,0]), cam_matrix )[0][:-1] )
    # test face forward
    if km.dot(cam_z, normal)<0:
        normal = -normal
    return [list(normal), face_center, cam_position]
Esempio n. 2
0
def barndoorRmsToPxr(top=0.0, bottom=0.0, left=0.0, right=0.0, mode='expand', time=1.0):
    # this function convert barndoors attribute in RMS Light to parameters in Pxr light filter
    # note: the input angle should be greater than 0 and less than 90 degree
    # also, you should select the barn filter in scene graph of Katana to run this function
    # this function does changes the values of the selected nodes or scene graph location
    min_angle = 1.0
    top = min_angle if top<min_angle else (90.0-min_angle if top>(90.0-min_angle) else top)
    bottom = min_angle if bottom<min_angle else (90.0-min_angle if bottom>(90.0-min_angle) else bottom)
    left = min_angle if left<min_angle else (90.0-min_angle if left>(90.0-min_angle) else left)
    right = min_angle if right<min_angle else (90.0-min_angle if right>(90.0-min_angle) else right)
    max_angle = max([top, bottom, left, right])

    # get scene graph location of the selected light filters
    locations = kcf.getSelectedLocations()
    nodes = kcf.locationsToNodes(locations)

    for (l, n) in nodes.iteritems():
        if not n:
            continue
        # get parent light matrix
        light_location = os.path.dirname(l)
        lgt_matrix = tf.list_to_matrix(kcf.getWorldXform(light_location)[0])
        scale, shear, angles, trans, persp = tf.decompose_matrix(lgt_matrix)
        if scale[0]<=0 or scale[1]<=0 or scale[2]<=0:
            print 'Error: '+os.path.basename(light_location)+' has zero scale, ignored!'
            continue
        # calculate distance to the light, so that the angle between the light and filter meets the max angle
        dist_to_light_x = math.tan(max_angle/180.0*math.pi) * scale[0]
        dist_to_light_y = math.tan(max_angle/180.0*math.pi) * scale[1]
        dist_to_light = 0
        if mode=='expand':
            dist_to_light = max(dist_to_light_x, dist_to_light_y)
        else:
            dist_to_light = min(dist_to_light_x, dist_to_light_y)
        dist_to_light = 1
        # calculate refine shape of the barn door
        top_edge = (dist_to_light / math.tan(top/180.0*math.pi) - scale[1])/scale[1]
        bottom_edge = (dist_to_light / math.tan(bottom/180.0*math.pi) - scale[1])/scale[1]
        left_edge = (dist_to_light / math.tan(left/180.0*math.pi) - scale[0])/scale[0]
        right_edge = (dist_to_light / math.tan(right/180.0*math.pi) - scale[0])/scale[0]

        # let's set the parameters on the selected light filters
        # light filter is a group, so let's get their children and set the transform parameters
        light_create_nodes = [i for i in n.getChildren() if i.getType().lower()=='lightcreate']
        if not light_create_nodes:
            print 'Error: failed to find lightCreate node in '+os.path.basename(l)+"'s children, ignored!"
            continue
        param_value_dict = {'transform.translate.x':[0, time], \
                            'transform.translate.y':[0, time], \
                            'transform.translate.z':[-dist_to_light, time]}
        kcf.setParameters(param_value_dict, light_create_nodes[0])

        # set the refine edges of the barn door
        light_filter_nodes = [i for i in n.getChildren() if i.getType().lower()=='material']
        if not light_create_nodes:
            print 'Error: failed to find lightFilter material in '+os.path.basename(l)+"'s children, ignored!"
            continue
        param_value_dict = {'top.value':[top_edge, time], 'bottom.value':[bottom_edge, time], \
                            'left.value':[left_edge, time], 'right.value':[right_edge, time]}
        kcf.setParameters(param_value_dict, light_filter_nodes[0])
Esempio n. 3
0
def frustumSelectionIterator(location=None, filter_type='component', fov_extend_h=0, fov_extend_v=0, \
        cam_location='', inverse_selection=True, animation=False, step=5, \
        nearD=0.1, farD=99999999, debug=False):
    ''' return the list of location within the frustum of camera. The filter_type
        should be component if the component represents the bounding box.
        
        we make this function iterator(generator), so the pyqt progress bar can benefit
        from the yield statment in order to know the progress of the running function.
    '''
    root_producer = kcf.getRootProducer()
    sgv = kcf.getSceneGraphView()
    if not location:
        location = kcf.getSelectedLocations()
        if not location:
            yield 'Error: Please select a location in the scene graph to proceed!'
            return
    if not isinstance(location, list):
        location = [location]
        
    filter_type = filterTypeMap(filter_type)
    
    locations_inside_list = []
    locations_outside_list = []
    
    current_frame = NodegraphAPI.NodegraphGlobals.GetCurrentTime()
    start_frame = NodegraphAPI.NodegraphGlobals.GetInTime()
    end_frame = NodegraphAPI.NodegraphGlobals.GetOutTime()
    frames = range(start_frame, end_frame+1, step)
    if end_frame not in frames:
        frames.append(end_frame)
    if not animation:
        frames = [current_frame]
    
    progress = 0
    progress_step = 100.0 / len(frames)
    
    for f in frames:
        yield 'frame' + str(f) + '\nGet camera matrix datas...'
        NodegraphAPI.NodegraphGlobals.SetCurrentTime(f)
        cam_data = getCameraDatas(cam_location)
        if fov_extend_h != 0 or fov_extend_v != 0:
            cam_data['fov_horizontal'] += fov_extend_h
            cam_data['fov_vertical'] += fov_extend_v
            cam_data['ratio'] = cam_data['fov_horizontal'] / cam_data['fov_vertical']
        frustum = km.Frustum()
        frustum.nearD = nearD
        frustum.farD = farD
        frustum.setCamInternals(cam_data['fov_vertical'], cam_data['ratio'])
        frustum.setCamDef(cam_data['position'], cam_data['forward'], cam_data['up'])
        if debug:
            # put the sphere in the corner of frustum to visually see if we get
            # the correct frustum shape
            print(cam_data['ratio'], cam_data['fov_horizontal'], cam_data['fov_vertical'])
            nodes = kcf.getSelectedNodes()
            corners = [frustum.ntl, frustum.ntr, frustum.nbl, frustum.nbr, \
                      frustum.nc, frustum.fc]
            for i in range(6):
                if i > len(nodes) - 1:
                    break
                kcf.setTransform(nodes[i], translate=list(corners[i]), scale=[10,10,10])
            return
        sub_process = 0
        sub_process_step = progress_step / 100.0
        yield 'start to iterate scene graph locations...'
        for l in location:
            location_producer = root_producer.getProducerByPath(l)
            for i in kcf.sg_iteratorByType(location_producer, type_=filter_type, to_leaf=False):
                bounds = getBound(i)
                if type_ == 'light':
                    bounds = []
                    # if the type is mesh light without bbox, or one of the rect, sphere,
                    # disk light, we use center of point to decide the visibility in frustum
                    # instead of bbox
                    light_shader = i.getAttribute('material.prmanLightShader').getData()
                    if not light_shader:
                        # light without valid light shader, skip
                        continue
                    light_shader = light_shader[0].lower()
                    if 'mesh' not in light_shader and 'rect' not in light_shader \
                        and 'sphere' not in light_shader and 'disk' not in light_shader:
                        continue
                    if 'mesh' in light_shader:
                        # if it's mesh light, let's check the source geometry
                        src = i.getAttribute('geometry.areaLightGeometrySource').getData()
                        if src:
                            bounds = getBound(root_producer.getProducerByPath(src[0]))
                isOutside = False
                if not bounds:
                    # if bounding box info is invalid, we try to use xform instead
                    world_xform = kcf.getWorldXform(i.getFullName())
                    if not world_xform:
                        continue
                    world_xform = world_xform[0]
                    center = world_xform[-4:-1]
                    if frustum.pointInFrustum(center) == frustum.status['outside']:
                        isOutside = True
                else:
                    aabox = km.AABox( bbox_list=bounds )
                    if frustum.boxInFrustum(aabox) == frustum.status['outside']:
                        isOutside = True
                    
                if isOutside:
                    locations_outside_list.append(i.getFullName())
                else:
                    locations_inside_list.append(i.getFullName())

                if sub_process < progress_step:
                    sub_process += sub_process_step
                    yield math.floor(progress + sub_process)
                    
        progress += progress_step
        yield math.floor(progress)
    
    locations_inside_list = list(set(locations_inside_list))
    locations_outside_list = list(set(locations_outside_list))
    locations_outside_list = list(set(locations_outside_list).difference(locations_inside_list))
    
    yield 'Completed!'
    if inverse_selection:
        yield locations_outside_list
        return
    yield locations_inside_list
Esempio n. 4
0
def getBound(sg_location):
    ''' if there is no bound info on the current location,
        it will find recursivly the bound in the children location '''
    if not sg_location:
        return []
    location_producer = None
    if isinstance(sg_location, str):
        root_producer = kcf.getRootRroducer()
        location_producer = root_producer.getProducerByPath(sg_location)
    else:
        location_producer = sg_location
    bound_attr = location_producer.getAttribute('bound')
    if not bound_attr:
        # find the child bounds
        bounds_collect = []
        bounds = []
        for c in location_producer.iterChildren():
            tmp = getBound(c)
            if tmp:
                bounds_collect.append(tmp)
        # calculate the combined bounds
        if bounds_collect:
            bounds = range(6)
            for i in range(0, 6, 2):
                bounds[i] = min([b[i] for b in bounds_collect])
            for i in range(1, 6, 2):
                bounds[i] = max([b[i] for b in bounds_collect])
        return bounds
    local_bound = location_producer.getAttribute('bound').getData()
    parent_matrix = kcf.getWorldXform(location_producer.getFullName())
    if not parent_matrix:
        return local_bound
    parent_matrix = km.list_to_matrix(parent_matrix[0])
    if km.is_same_matrix(parent_matrix, km.matrix_identity()):
        return local_bound
    # convert local bound to world space
    # caculate 8 corners of bounding box
    bmin = [local_bound[0], local_bound[2], local_bound[4]]
    bmax = [local_bound[1], local_bound[3], local_bound[5]]
    ftr = [bmax[0], bmax[1], bmax[2]]
    fbr = [bmax[0], bmin[1], bmax[2]]
    fbl = [bmin[0], bmin[1], bmax[2]]
    ftl = [bmin[0], bmax[1], bmax[2]]
    btr = [bmax[0], bmax[1], bmin[2]]
    bbr = [bmax[0], bmin[1], bmin[2]]
    bbl = [bmin[0], bmin[1], bmin[2]]
    btl = [bmin[0], bmax[1], bmin[2]]
    # convert to world space
    ftr = km.matrix_mul( km.list_to_matrix(ftr+[1]), parent_matrix )[0][:-1]
    fbr = km.matrix_mul( km.list_to_matrix(fbr+[1]), parent_matrix )[0][:-1]
    fbl = km.matrix_mul( km.list_to_matrix(fbl+[1]), parent_matrix )[0][:-1]
    ftl = km.matrix_mul( km.list_to_matrix(ftl+[1]), parent_matrix )[0][:-1]
    btr = km.matrix_mul( km.list_to_matrix(btr+[1]), parent_matrix )[0][:-1]
    bbr = km.matrix_mul( km.list_to_matrix(bbr+[1]), parent_matrix )[0][:-1]
    bbl = km.matrix_mul( km.list_to_matrix(bbl+[1]), parent_matrix )[0][:-1]
    btl = km.matrix_mul( km.list_to_matrix(btl+[1]), parent_matrix )[0][:-1]
    # recaculate bounding box
    bmin[0] = min(ftr[0], fbr[0], fbl[0], ftl[0], btr[0], bbr[0], bbl[0], btl[0])
    bmin[1] = min(ftr[1], fbr[1], fbl[1], ftl[1], btr[1], bbr[1], bbl[1], btl[1])
    bmin[2] = min(ftr[2], fbr[2], fbl[2], ftl[2], btr[2], bbr[2], bbl[2], btl[2])
    bmax[0] = max(ftr[0], fbr[0], fbl[0], ftl[0], btr[0], bbr[0], bbl[0], btl[0])
    bmax[1] = max(ftr[1], fbr[1], fbl[1], ftl[1], btr[1], bbr[1], bbl[1], btl[1])
    bmax[2] = max(ftr[2], fbr[2], fbl[2], ftl[2], btr[2], bbr[2], bbl[2], btl[2])
    return [bmin[0], bmax[0], bmin[1], bmax[1], bmin[2], bmax[2]]
Esempio n. 5
0
def getDistance(a, b):
    # a and b should be the location string
    xforms = kcf.getWorldXform([a,b])
    a_position = (xforms[0][-4], xforms[0][-3], xforms[0][-2])
    b_position = (xforms[1][-4], xforms[1][-3], xforms[1][-2])
    return math.sqrt(sum( (a_position - b_position)**2 for a_position, b_position in zip(a_position, b_position)))
Esempio n. 6
0
def setSelectedLightAtReflectedPosition(normal, face_center, cam_position, \
                                        invert_normal=False, time=0.0, print_log=False):
    '''
    the normal should be the returned data from getSelectedFaceNormal
    '''
    normal = np.array(normal)
    if invert_normal:
        normal = -normal
    face_center = np.array(face_center)
    cam_position = np.array(cam_position)
    cam_to_face_vector = face_center - cam_position
    reflect = km.vector_unit( km.vector_reflect(cam_to_face_vector, normal) )
    if print_log:
        print 'reflect vector'
        print reflect

    root_producer = kcf.getRootProducer()
    # get selected light
    light_locations = kcf.getSelectedLocations()
    for l in light_locations:
        # if the selected item is light?
        location_producer = root_producer.getProducerByPath(l)
        if location_producer.getType().lower() != 'light':
            continue
        light_Node = kcf.locationsToNodes(l)[l]
        # get light world matrix
        matrix_world_light = kcf.getWorldXform(l)
        if not matrix_world_light:
            print light_Node.getName()+": Failed to get light's world matrix, ignored."
            continue
        matrix_world_light = km.list_to_matrix( matrix_world_light[0] )
        if print_log:
            print 'light world matrix'
            print matrix_world_light
        # get light local matrix
        transform = kcf.getTransform(light_Node)
        if print_log:
            print 'light transform'
            print transform
        matrix_local_light = km.list_to_matrix( transform[light_Node]['matrix'] )
        if print_log:
            print 'light local matrix'
            print matrix_local_light
        # get the intermediate matrix: M_i = M_light_local_inverse * M_world
        matrix_intermediate = km.matrix_mul( km.matrix_inverse(matrix_local_light), matrix_world_light )
        if print_log:
            print 'intermediate matrix'
            print matrix_intermediate
        # compose the reflect world matrix
        distance_light_to_face = float( km.vector_norm(matrix_world_light[3][:-1] - face_center) )
        if print_log:
            print 'light to face distance'
            print distance_light_to_face
        position = reflect * distance_light_to_face + face_center
        rotation = km.vector_to_rotation(-reflect)
        if print_log:
            print 'light new position'
            print position
            print 'light new rotation'
            print rotation
            print km.rad_to_deg(rotation)
        matrix_reflect = km.matrix_compose(scale=np.array([1,1,1]), angles=rotation, translate=position)
        if print_log:
            print 'world reflect matrix'
            print matrix_reflect
        # compute the new light local matrix: M_light = M_reflect * M_intermediate_inverse
        new_matrix_light = km.matrix_mul(matrix_reflect, km.matrix_inverse(matrix_intermediate))
        if print_log:
            print 'new light local matrix'
            print new_matrix_light
        # then get the translate, rotation and scale components
        scale, shear, angles, translate, perspective = km.matrix_decompose(new_matrix_light)
        angles = km.rad_to_deg(angles)
        print (light_Node.getName()+', target transform: \ntranslate: [%f, %f, %f]\n'+\
            'rotate: [%f, %f, %f]\nscale: [%f, %f, %f]')%(translate[0], translate[1], translate[2],\
            angles[0], angles[1], angles[2], scale[0], scale[1], scale[2])
        # let's move the light!
        kcf.setTransform(light_Node, translate=list(translate), rotate=list(angles), \
                            scale=list(scale), rotation_order='XYZ')
        # change the center of interest at the face center
        kcf.setParameters({'centerOfInterest':distance_light_to_face}, light_Node)