Example #1
0
def raytrace_schedule(i,schedule,total_shared,q): # this is the function running on each thread
    #global schedules,itcounters,chnkcounters,killers

    if len(schedule) == 0:
        return

    total_colour_buffer_preproc = tonumpyarray(total_shared)

    #schedule = schedules[i]

    itcounters[i] = 0
    chnkcounters[i]= 0

    for chunk in schedule:
        #if killers[i]:
        #    break
        chnkcounters[i]+=1

        #number of chunk pixels
        numChunk = chunk.shape[0]

        #useful constant arrays 
        ones = np.ones((numChunk))
        ones3 = np.ones((numChunk,3))
        UPFIELD = np.outer(ones,np.array([0.,1.,0.]))
        BLACK = np.outer(ones,np.array([0.,0.,0.]))

        #arrays of integer pixel coordinates
        x = chunk % RESOLUTION[0]
        y = chunk / RESOLUTION[0]

        showprogress("Generating view vectors...",i,q)

        #the view vector in 3D space
        view = np.zeros((numChunk,3))

        view[:,0] = x.astype(float)/RESOLUTION[0] - .5
        view[:,1] = ((-y.astype(float)/RESOLUTION[1] + .5)*RESOLUTION[1])/RESOLUTION[0] #(inverting y coordinate)
        view[:,2] = 1.0

        view[:,0]*=TANFOV
        view[:,1]*=TANFOV

        #rotating through the view matrix

        view = np.einsum('jk,ik->ij',viewMatrix,view)

        #original position
        point = np.outer(ones, CAMERA_POS)

        normview = normalize(view)

        velocity = np.copy(normview)


        # initializing the colour buffer
        object_colour = np.zeros((numChunk,3))
        object_alpha = np.zeros(numChunk)

        #squared angular momentum per unit mass (in the "Newtonian fantasy")
        #h2 = np.outer(sqrnorm(np.cross(point,velocity)),np.array([1.,1.,1.]))
        h2 = sqrnorm(np.cross(point,velocity))[:,np.newaxis]

        pointsqr = np.copy(ones3)

        for it in range(NITER):
            itcounters[i]+=1

            if it%150 == 1:
                if killers[i]:
                    break
                showprogress("Raytracing...",i,q)

            # STEPPING
            oldpoint = np.copy(point) #not needed for tracing. Useful for intersections

            if METHOD == METH_LEAPFROG:
                #leapfrog method here feels good
                point += velocity * STEP

                if DISTORT:
                    #this is the magical - 3/2 r^(-5) potential...
                    accel = - 1.5 * h2 *  point / np.power(sqrnorm(point),2.5)[:,np.newaxis]
                    velocity += accel * STEP

            elif METHOD == METH_RK4:
                if DISTORT:
                    #simple step size control
                    rkstep = STEP

                    # standard Runge-Kutta
                    y = np.zeros((numChunk,6))
                    y[:,0:3] = point
                    y[:,3:6] = velocity
                    k1 = RK4f( y, h2)
                    k2 = RK4f( y + 0.5*rkstep*k1, h2)
                    k3 = RK4f( y + 0.5*rkstep*k2, h2)
                    k4 = RK4f( y +     rkstep*k3, h2)

                    increment = rkstep/6. * (k1 + 2*k2 + 2*k3 + k4)
                    
                    velocity += increment[:,3:6]

                point += increment[:,0:3]


            #useful precalcs
            pointsqr = sqrnorm(point)
            #phi = np.arctan2(point[:,0],point[:,2])    #too heavy. Better an instance wherever it's needed.
            #normvel = normalize(velocity)              #never used! BAD BAD BAD!!


            # FOG

            if FOGDO and (it%FOGSKIP == 0):
                phsphtaper = np.clip(0.8*(pointsqr - 1.0),0.,1.0)
                fogint = np.clip(FOGMULT * FOGSKIP * STEP / pointsqr,0.0,1.0) * phsphtaper
                fogcol = ones3

                object_colour = blendcolors(fogcol,fogint,object_colour,object_alpha)
                object_alpha = blendalpha(fogint, object_alpha)


            # CHECK COLLISIONS
            # accretion disk

            if DISK_TEXTURE_INT != DT_NONE:

                mask_crossing = np.logical_xor( oldpoint[:,1] > 0., point[:,1] > 0.) #whether it just crossed the horizontal plane
                mask_distance = np.logical_and((pointsqr < DISKOUTERSQR), (pointsqr > DISKINNERSQR))  #whether it's close enough

                diskmask = np.logical_and(mask_crossing,mask_distance)

                if (diskmask.any()):
                    
                    #actual collision point by intersection
                    lambdaa = - point[:,1]/velocity[:,1]
                    colpoint = point + lambdaa[:,np.newaxis] * velocity
                    colpointsqr = sqrnorm(colpoint)

                    if DISK_TEXTURE_INT == DT_GRID:
                        phi = np.arctan2(colpoint[:,0],point[:,2])
                        theta = np.arctan2(colpoint[:,1],norm(point[:,[0,2]]))
                        diskcolor =     np.outer(
                                np.mod(phi,0.52359) < 0.261799,
                                            np.array([1.,1.,0.])
                                                ) +  \
                                        np.outer(ones,np.array([0.,0.,1.]) )
                        diskalpha = diskmask

                    elif DISK_TEXTURE_INT == DT_SOLID:
                        diskcolor = np.array([1.,1.,.98])
                        diskalpha = diskmask

                    elif DISK_TEXTURE_INT == DT_TEXTURE:

                        phi = np.arctan2(colpoint[:,0],point[:,2])
                        
                        uv = np.zeros((numChunk,2))

                        uv[:,0] = ((phi+2*np.pi)%(2*np.pi))/(2*np.pi)
                        uv[:,1] = (np.sqrt(colpointsqr)-DISKINNER)/(DISKOUTER-DISKINNER)

                        diskcolor = lookup ( texarr_disk, np.clip(uv,0.,1.))
                        #alphamask = (2.0*ransample) < sqrnorm(diskcolor)
                        #diskmask = np.logical_and(diskmask, alphamask )
                        diskalpha = diskmask * np.clip(sqrnorm(diskcolor)/3.0,0.0,1.0)

                    elif DISK_TEXTURE_INT == DT_BLACKBODY:

                        temperature = np.exp(bb.disktemp(colpointsqr,9.2103))

                        if REDSHIFT:
                            R = np.sqrt(colpointsqr)

                            disc_velocity = 0.70710678 * \
                                        np.power((np.sqrt(colpointsqr)-1.).clip(0.1),-.5)[:,np.newaxis] * \
                                        np.cross(UPFIELD, normalize(colpoint))


                            gamma =  np.power( 1 - sqrnorm(disc_velocity).clip(max=.99), -.5)

                            # opz = 1 + z
                            opz_doppler = gamma * ( 1. + np.einsum('ij,ij->i',disc_velocity,normalize(velocity)))
                            opz_gravitational = np.power(1.- 1/R.clip(1),-.5)

                            # (1+z)-redshifted Planck spectrum is still Planckian at temperature T
                            temperature /= (opz_doppler*opz_gravitational).clip(0.1)

                        intensity = bb.intensity(temperature)
                        if DISK_INTENSITY_DO:
                            diskcolor = np.einsum('ij,i->ij', bb.colour(temperature),DISK_MULTIPLIER*intensity)#np.maximum(1.*ones,DISK_MULTIPLIER*intensity))
                        else:
                            diskcolor = bb.colour(temperature)

                        iscotaper = np.clip((colpointsqr-DISKINNERSQR)*0.3,0.,1.)
                        outertaper = np.clip(temperature/1000. ,0.,1.)

                        diskalpha = diskmask * iscotaper * outertaper#np.clip(diskmask * DISK_ALPHA_MULTIPLIER *intensity,0.,1.)


                    object_colour = blendcolors(diskcolor,diskalpha,object_colour,object_alpha)
                    object_alpha = blendalpha(diskalpha, object_alpha)



            # event horizon
            oldpointsqr = sqrnorm(oldpoint)

            mask_horizon = np.logical_and((pointsqr < 1),(sqrnorm(oldpoint) > 1) )

            if mask_horizon.any() :

                lambdaa =  1. - ((1.-oldpointsqr)/((pointsqr - oldpointsqr)))[:,np.newaxis]
                colpoint = lambdaa * point + (1-lambdaa)*oldpoint

                if HORIZON_GRID:
                    phi = np.arctan2(colpoint[:,0],point[:,2])
                    theta = np.arctan2(colpoint[:,1],norm(point[:,[0,2]]))
                    horizoncolour = np.outer( np.logical_xor(np.mod(phi,1.04719) < 0.52359,np.mod(theta,1.04719) < 0.52359), np.array([1.,0.,0.]))
                else:
                    horizoncolour = BLACK#np.zeros((numPixels,3))

                horizonalpha = mask_horizon

                object_colour = blendcolors(horizoncolour,horizonalpha,object_colour,object_alpha)
                object_alpha = blendalpha(horizonalpha, object_alpha)



        showprogress("generating sky layer...",i,q)

        vphi = np.arctan2(velocity[:,0],velocity[:,2])
        vtheta = np.arctan2(velocity[:,1],norm(velocity[:,[0,2]]) )

        vuv = np.zeros((numChunk,2))

        vuv[:,0] = np.mod(vphi+4.5,2*np.pi)/(2*np.pi)
        vuv[:,1] = (vtheta+np.pi/2)/(np.pi)

        if SKY_TEXTURE_INT == DT_TEXTURE:
            col_sky = lookup(texarr_sky,vuv)[:,0:3]

        showprogress("generating debug layers...",i,q)

        ##debug color: direction of view vector
        #dbg_viewvec = np.clip(view + vec3(.5,.5,0.0),0.0,1.0)
        ##debug color: direction of final ray
        ##debug color: grid
        #dbg_grid = np.abs(normalize(velocity)) < 0.1


        if SKY_TEXTURE_INT == ST_TEXTURE:
            col_bg = col_sky
        elif SKY_TEXTURE_INT == ST_NONE:
            col_bg = np.zeros((numChunk,3))
        elif SKY_TEXTURE_INT == ST_FINAL:
            dbg_finvec = np.clip(normalize(velocity) + np.array([.5,.5,0.0])[np.newaxis,:],0.0,1.0)
            col_bg = dbg_finvec
        else:
            col_bg = np.zeros((numChunk,3))


        showprogress("blending layers...",i,q)

        col_bg_and_obj = blendcolors(SKYDISK_RATIO*col_bg, ones ,object_colour,object_alpha)

        showprogress("beaming back to mothership.",i,q)
        # copy back in the buffer
        if not DISABLE_SHUFFLING:
            total_colour_buffer_preproc[chunk] = col_bg_and_obj
        else:
            total_colour_buffer_preproc[chunk[0]:(chunk[-1]+1)] = col_bg_and_obj


        #refresh display
        # NO: plt does not allow drawing outside main thread
        #if not DISABLE_DISPLAY:
        #    showprogress("updating display...")
        #    plt.imshow(total_colour_buffer_preproc.reshape((RESOLUTION[1],RESOLUTION[0],3)))
        #    plt.draw()

        showprogress("garbage collection...",i,q)
        gc.collect()

    showprogress("Done.",i,q)
Example #2
0
def raytrace_schedule(i,schedule,total_shared,q,drag): # this is the function running on each thread
    #global schedules,itcounters,chnkcounters,killers

    if len(schedule) == 0:
        return

    total_colour_buffer_preproc = tonumpyarray(total_shared)

    #schedule = schedules[i]

    itcounters[i] = 0
    chnkcounters[i]= 0
    for chunk in schedule:
        #if killers[i]:
        #    break
        chnkcounters[i]+=1

        #number of chunk pixels
        numChunk = chunk.shape[0]

        #useful constant arrays 
        ones = np.ones((numChunk))
        ones3 = np.ones((numChunk,3))
        UPFIELD = np.outer(ones,np.array([0.,1.,0.]))
        BLACK = np.outer(ones,np.array([0.,0.,0.]))

        #arrays of integer pixel coordinates
        x = chunk % RESOLUTION[0]
        y = chunk / RESOLUTION[0]

        showprogress("Generating view vectors...",i,q)

        #the view vector in 3D space
        view = np.zeros((numChunk,3))

        view[:,0] = x.astype(float)/RESOLUTION[0] - .5
        view[:,1] = ((-y.astype(float)/RESOLUTION[1] + .5)*RESOLUTION[1])/RESOLUTION[0] #(inverting y coordinate)
        view[:,2] = 1.0

        view[:,0]*=TANFOV
        view[:,1]*=TANFOV

        #rotating through the view matrix

        view = np.einsum('jk,ik->ij',viewMatrix,view)

        #original position
        point = np.outer(ones, CAMERA_POS)

        normview = normalize(view)

        velocity = np.copy(normview)


        # initializing the colour buffer
        object_colour = np.zeros((numChunk,3))
        object_alpha = np.zeros(numChunk)

        # Drawing circle
        if DRAW_CIRCLE:
            t = -1 * np.einsum('ij,ij->i',point - OTHER_CENTER, velocity) / np.einsum('ij,ij->i',velocity,velocity)
            dist_vecs = point + np.einsum('ij,i->ij',velocity,t) - OTHER_CENTER
            squared_dists = np.einsum('ij,ij->i',dist_vecs,dist_vecs)
            theta = np.arctan2(dist_vecs[:,0], dist_vecs[:,1])
            width = 0.05
            dash_length = 1
            mask_circle = np.logical_and.reduce([(t > 0),(squared_dists < OTHER_RADIUS * OTHER_RADIUS * (1 + width)),
                                                (squared_dists > OTHER_RADIUS * OTHER_RADIUS * (1 - width)),
                                                np.mod(theta, dash_length) < dash_length / 2])
            circle_alpha = mask_circle * 0.3
            object_colour = blendcolors(np.outer(ones,np.array([0.24,0.59,0.89])), circle_alpha, object_colour, object_alpha)
            object_alpha = blendalpha(circle_alpha, object_alpha)
        #squared angular momentum per unit mass (in the "Newtonian fantasy")
        #h2 = np.outer(sqrnorm(np.cross(point,velocity)),np.array([1.,1.,1.]))


        pointsqr = np.copy(ones3)

        for it in range(NITER):
            itcounters[i]+=1

            if it%150 == 1:
                if killers[i]:
                    break
                showprogress("Raytracing...",i,q)

            # STEPPING
            oldpoint = np.copy(point) #not needed for tracing. Useful for intersections

            if METHOD == METH_LEAPFROG:
                # TODO Not updated for multiple bodies
                #leapfrog method here feels good
                point += velocity * STEP

                if DISTORT:
                    #this is the magical - 3/2 r^(-5) potential...
                    accel = - 1.5 * h2 *  point / np.power(sqrnorm(point),2.5)[:,np.newaxis]
                    velocity += accel * STEP

            elif METHOD == METH_RK4:
                if DISTORT:
                    #simple step size control
                    rkstep = STEP

                    # standard Runge-Kutta
                    y = np.zeros((numChunk,6))
                    y[:,0:3] = point
                    y[:,3:6] = velocity
                    k1 = RK4f( y, drag=drag)
                    k2 = RK4f( y + 0.5*rkstep*k1, drag=drag)
                    k3 = RK4f( y + 0.5*rkstep*k2, drag=drag)
                    k4 = RK4f( y +     rkstep*k3, drag=drag)

                    increment = rkstep/6. * (k1 + 2*k2 + 2*k3 + k4)
                    
                    velocity += increment[:,3:6]

                point += increment[:,0:3]

            for center, radius in zip(CENTERS,RADII):
                #useful precalcs
                pointsqr = sqrnorm(point - center)
                #phi = np.arctan2(point[:,0],point[:,2])    #too heavy. Better an instance wherever it's needed.
                #normvel = normalize(velocity)              #never used! BAD BAD BAD!!


                # FOG

                if FOGDO and (it%FOGSKIP == 0):
                    phsphtaper = np.clip(0.8*(pointsqr - 1.0),0.,1.0)
                    fogint = np.clip(FOGMULT * FOGSKIP * STEP / pointsqr,0.0,1.0) * phsphtaper
                    fogcol = ones3

                    object_colour = blendcolors(fogcol,fogint,object_colour,object_alpha)
                    object_alpha = blendalpha(fogint, object_alpha)


                # CHECK COLLISIONS
                # accretion disk
                # TODO not implemented for multiple objects

                if DISK_TEXTURE_INT != DT_NONE:

                    mask_crossing = np.logical_xor( oldpoint[:,1] > center[1], point[:,1] > center[1]) #whether it just crossed the horizontal plane
                    mask_distance = np.logical_and((pointsqr < DISKOUTERSQR), (pointsqr > DISKINNERSQR))  #whether it's close enough

                    diskmask = np.logical_and(mask_crossing,mask_distance)

                    if (diskmask.any()):

                        #actual collision point by intersection
                        lambdaa = - (point[:,1] - center[1])/velocity[:,1]
                        colpoint = point + lambdaa[:,np.newaxis] * velocity
                        colpointsqr = sqrnorm(colpoint - center)

                        if DISK_TEXTURE_INT == DT_GRID:
                            phi = np.arctan2(colpoint[:,0] - center[0],point[:,2] - center[2])
                            theta = np.arctan2(colpoint[:,1] - center[1],norm(point[:,[0,2]] - center[[0,2]]))
                            diskcolor =     np.outer(
                                    np.mod(phi,0.52359) < 0.261799,
                                                np.array([1.,1.,0.])
                                                    ) +  \
                                            np.outer(ones,np.array([0.,0.,1.]) )
                            diskalpha = diskmask

                        elif DISK_TEXTURE_INT == DT_SOLID:
                            diskcolor = np.array([1.,1.,.98])
                            diskalpha = diskmask

                        elif DISK_TEXTURE_INT == DT_TEXTURE:

                            phi = np.arctan2(colpoint[:,0] - center[0],point[:,2] - center[2])

                            uv = np.zeros((numChunk,2))

                            uv[:,0] = ((phi+2*np.pi)%(2*np.pi))/(2*np.pi)
                            uv[:,1] = (np.sqrt(colpointsqr)-DISKINNER)/(DISKOUTER-DISKINNER)

                            diskcolor = lookup ( texarr_disk, np.clip(uv,0.,1.))
                            #alphamask = (2.0*ransample) < sqrnorm(diskcolor)
                            #diskmask = np.logical_and(diskmask, alphamask )
                            diskalpha = diskmask * np.clip(sqrnorm(diskcolor)/3.0,0.0,1.0)

                        elif DISK_TEXTURE_INT == DT_BLACKBODY:

                            temperature = np.exp(bb.disktemp(colpointsqr,9.2103))

                            if REDSHIFT:
                                R = np.sqrt(colpointsqr)

                                disc_velocity = 0.70710678 * \
                                            np.power((np.sqrt(colpointsqr)-1.).clip(0.1),-.5)[:,np.newaxis] * \
                                            np.cross(UPFIELD, normalize(colpoint))


                                gamma =  np.power( 1 - sqrnorm(disc_velocity).clip(max=.99), -.5)

                                # opz = 1 + z
                                opz_doppler = gamma * ( 1. + np.einsum('ij,ij->i',disc_velocity,normalize(velocity)))
                                opz_gravitational = np.power(1.- 1/R.clip(1),-.5)

                                # (1+z)-redshifted Planck spectrum is still Planckian at temperature T
                                temperature /= (opz_doppler*opz_gravitational).clip(0.1)

                            intensity = bb.intensity(temperature)
                            if DISK_INTENSITY_DO:
                                diskcolor = np.einsum('ij,i->ij', bb.colour(temperature),DISK_MULTIPLIER*intensity)#np.maximum(1.*ones,DISK_MULTIPLIER*intensity))
                            else:
                                diskcolor = bb.colour(temperature)

                            iscotaper = np.clip((colpointsqr-DISKINNERSQR)*0.3,0.,1.)
                            outertaper = np.clip(temperature/1000. ,0.,1.)

                            diskalpha = diskmask * iscotaper * outertaper#np.clip(diskmask * DISK_ALPHA_MULTIPLIER *intensity,0.,1.)


                        object_colour = blendcolors(diskcolor,diskalpha,object_colour,object_alpha)
                        object_alpha = blendalpha(diskalpha, object_alpha)



                # event horizon
                oldpointsqr = sqrnorm(oldpoint - center)

                mask_horizon = np.logical_and((pointsqr < radius**2),(oldpointsqr > radius**2) )

                if mask_horizon.any() :
                    if HORIZON_GRID:
                        lambdaa = 1. - ((1. - oldpointsqr) / ((pointsqr - oldpointsqr)))[:, np.newaxis]
                        colpoint = lambdaa * point + (1 - lambdaa) * oldpoint
                        phi = np.arctan2(colpoint[:,0],point[:,2])
                        theta = np.arctan2(colpoint[:,1],norm(point[:,[0,2]]))
                        horizoncolour = np.outer( np.logical_xor(np.mod(phi,1.04719) < 0.52359,np.mod(theta,1.04719) < 0.52359), np.array([1.,0.,0.]))
                    else:
                        horizoncolour = BLACK#np.zeros((numPixels,3))

                    horizonalpha = mask_horizon

                    object_colour = blendcolors(horizoncolour,horizonalpha,object_colour,object_alpha)
                    object_alpha = blendalpha(horizonalpha, object_alpha)

            # Rendering other object
            if OTHER_TEXTURE_INT != OT_NONE:
                oldpointsqr = sqrnorm(oldpoint - OTHER_CENTER)
                pointsqr = sqrnorm(point - OTHER_CENTER)
                mask_other = np.logical_and((pointsqr < OTHER_RADIUS ** 2), (oldpointsqr > OTHER_RADIUS ** 2))
                if mask_other.any():
                    lambdaa = ((OTHER_RADIUS - np.sqrt(oldpointsqr)) / (np.sqrt(pointsqr) - np.sqrt(oldpointsqr)))[:, np.newaxis]
                    colpoint = lambdaa * point + (1 - lambdaa) * oldpoint
                    phi = np.arctan2(colpoint[:,0] - OTHER_CENTER[0],colpoint[:,2] - OTHER_CENTER[2])
                    theta = np.arctan2(colpoint[:,1] - OTHER_CENTER[1],norm(colpoint[:,[0,2]] - OTHER_CENTER[[0,2]]))

                    vuv = np.zeros((numChunk, 2))
                    vuv[:, 0] = np.mod(phi + 4.5, 2 * np.pi) / (2 * np.pi)
                    vuv[:, 1] = (-theta + np.pi / 2) / (np.pi)

                    other_colour = lookup(texarr_other, vuv)[:,0:3]

                    other_alpha = mask_other

                    object_colour = blendcolors(other_colour,other_alpha,object_colour,object_alpha)
                    object_alpha = blendalpha(other_alpha, object_alpha)
        if OTHER_TEXTURE_INT != OT_NONE:
            showprogress("computing final intersections...", i, q)

            # Creating intersection mask
            t = -1 * np.einsum('ij,ij->i',point - OTHER_CENTER, velocity) / multisqrnorm(velocity)
            dist_vecs = point + np.einsum('ij,i->ij',velocity,t) - OTHER_CENTER
            squared_dists = multisqrnorm(dist_vecs)
            mask_other_end = np.logical_and((t > 0),(squared_dists <= OTHER_RADIUS * OTHER_RADIUS))

            # Calculating actual intersection points
            a = multidot(velocity, velocity)
            b = 2 * multidot(point - OTHER_CENTER,velocity)
            c = multisqrnorm(point - OTHER_CENTER) - OTHER_RADIUS ** 2
            t = (-b - np.sqrt(b * b - 4 * a * c)) / (2 * a)
            mask_other_end = np.logical_and(mask_other_end, ~np.isnan(t))
            t[np.isnan(t)] = 0
            mask_other_end = np.logical_and(mask_other_end, t >= 0)
            intersections = point + np.einsum('ij,i->ij',velocity,t) - OTHER_CENTER

            phi = np.arctan2(intersections[:,0],intersections[:,2])
            theta = np.arctan2(intersections[:,1],norm(intersections[:,[0,2]]))
            vuv = np.zeros((numChunk, 2))
            vuv[:, 0] = np.mod(phi + 4.5, 2 * np.pi) / (2 * np.pi)
            vuv[:, 1] = (theta + np.pi / 2) / (np.pi)
            other_colour = lookup(texarr_other, vuv)[:, 0:3]

            other_alpha = mask_other_end

            object_colour = blendcolors(other_colour, other_alpha, object_colour, object_alpha)
            object_alpha = blendalpha(other_alpha, object_alpha)

        showprogress("generating sky layer...", i, q)

        vphi = np.arctan2(velocity[:,0],velocity[:,2])
        vtheta = np.arctan2(velocity[:,1],norm(velocity[:,[0,2]]) )

        vuv = np.zeros((numChunk,2))

        vuv[:,0] = np.mod(vphi+4.5,2*np.pi)/(2*np.pi)
        vuv[:,1] = (vtheta+np.pi/2)/(np.pi)

        if SKY_TEXTURE_INT == DT_TEXTURE:
            col_sky = lookup(texarr_sky,vuv)[:,0:3]

        showprogress("generating debug layers...",i,q)

        ##debug color: direction of view vector
        #dbg_viewvec = np.clip(view + vec3(.5,.5,0.0),0.0,1.0)
        ##debug color: direction of final ray
        ##debug color: grid
        #dbg_grid = np.abs(normalize(velocity)) < 0.1


        if SKY_TEXTURE_INT == ST_TEXTURE:
            col_bg = col_sky
        elif SKY_TEXTURE_INT == ST_NONE:
            col_bg = np.zeros((numChunk,3))
        elif SKY_TEXTURE_INT == ST_FINAL:
            dbg_finvec = np.clip(normalize(velocity) + np.array([.5,.5,0.0])[np.newaxis,:],0.0,1.0)
            col_bg = dbg_finvec
        else:
            col_bg = np.zeros((numChunk,3))


        showprogress("blending layers...",i,q)

        col_bg_and_obj = blendcolors(SKYDISK_RATIO*col_bg, ones ,object_colour,object_alpha)

        showprogress("beaming back to mothership.",i,q)
        # copy back in the buffer
        if not DISABLE_SHUFFLING:
            total_colour_buffer_preproc[chunk] = col_bg_and_obj
        else:
            total_colour_buffer_preproc[chunk[0]:(chunk[-1]+1)] = col_bg_and_obj


        #refresh display
        # NO: plt does not allow drawing outside main thread
        #if not DISABLE_DISPLAY:
        #    showprogress("updating display...")
        #    plt.imshow(total_colour_buffer_preproc.reshape((RESOLUTION[1],RESOLUTION[0],3)))
        #    plt.draw()

        showprogress("garbage collection...",i,q)
        gc.collect()

    showprogress("Done.",i,q)
Example #3
0
def raytrace_schedule(i, schedule, total_shared,
                      q):  # this is the function running on each thread
    #global schedules,itcounters,chnkcounters,killers

    if len(schedule) == 0:
        return

    total_colour_buffer_preproc = tonumpyarray(total_shared)

    #schedule = schedules[i]

    itcounters[i] = 0
    chnkcounters[i] = 0

    for chunk in schedule:
        #if killers[i]:
        #    break
        chnkcounters[i] += 1

        #number of chunk pixels
        numChunk = chunk.shape[0]

        #useful constant arrays
        ones = np.ones((numChunk))
        ones3 = np.ones((numChunk, 3))
        UPFIELD = np.outer(ones, np.array([0., 1., 0.]))
        BLACK = np.outer(ones, np.array([0., 0., 0.]))

        #arrays of integer pixel coordinates
        x = chunk % RESOLUTION[0]
        y = chunk / RESOLUTION[0]

        showprogress("Generating view vectors...", i, q)

        #the view vector in 3D space
        view = np.zeros((numChunk, 3))

        view[:, 0] = x.astype(float) / RESOLUTION[0] - .5
        view[:, 1] = ((-y.astype(float) / RESOLUTION[1] + .5) *
                      RESOLUTION[1]) / RESOLUTION[0]  #(inverting y coordinate)
        view[:, 2] = 1.0

        view[:, 0] *= TANFOV
        view[:, 1] *= TANFOV

        #rotating through the view matrix

        view = np.einsum('jk,ik->ij', viewMatrix, view)

        #original position
        point = np.outer(ones, CAMERA_POS)

        normview = normalize(view)

        velocity = np.copy(normview)

        # initializing the colour buffer
        object_colour = np.zeros((numChunk, 3))
        object_alpha = np.zeros(numChunk)

        #squared angular momentum per unit mass (in the "Newtonian fantasy")
        #h2 = np.outer(sqrnorm(np.cross(point,velocity)),np.array([1.,1.,1.]))
        h2 = sqrnorm(np.cross(point, velocity))[:, np.newaxis]

        pointsqr = np.copy(ones3)

        for it in range(NITER):
            itcounters[i] += 1

            if it % 150 == 1:
                if killers[i]:
                    break
                showprogress("Raytracing...", i, q)

            # STEPPING
            oldpoint = np.copy(
                point)  #not needed for tracing. Useful for intersections

            if METHOD == METH_LEAPFROG:
                #leapfrog method here feels good
                point += velocity * STEP

                if DISTORT:
                    #this is the magical - 3/2 r^(-5) potential...
                    accel = -1.5 * h2 * point / sixth(point)[:, np.newaxis]
                    velocity += accel * STEP

            elif METHOD == METH_RK4:
                #simple step size control
                rkstep = STEP

                # standard Runge-Kutta
                y = np.zeros((numChunk, 6))
                y[:, 0:3] = point
                y[:, 3:6] = velocity
                k1 = RK4f(y, h2)
                k2 = RK4f(y + 0.5 * rkstep * k1, h2)
                k3 = RK4f(y + 0.5 * rkstep * k2, h2)
                k4 = RK4f(y + rkstep * k3, h2)

                increment = rkstep / 6. * (k1 + 2 * k2 + 2 * k3 + k4)

                point += increment[:, 0:3]
                velocity += increment[:, 3:6]

            #useful precalcs
            pointsqr = sqrnorm(point)
            #phi = np.arctan2(point[:,0],point[:,2])    #too heavy. Better an instance wherever it's needed.
            #normvel = normalize(velocity)              #never used! BAD BAD BAD!!

            # FOG

            if FOGDO and (it % FOGSKIP == 0):
                fogint = np.clip(FOGMULT * FOGSKIP * STEP / sqrnorm(point),
                                 0.0, 1.0)
                fogcol = ones3

                object_colour = blendcolors(fogcol, fogint, object_colour,
                                            object_alpha)
                object_alpha = blendalpha(fogint, object_alpha)

            # CHECK COLLISIONS
            # accretion disk

            if DISK_TEXTURE != "none":

                mask_crossing = np.logical_xor(
                    oldpoint[:, 1] > 0., point[:, 1] >
                    0.)  #whether it just crossed the horizontal plane
                mask_distance = np.logical_and(
                    (pointsqr < DISKOUTERSQR),
                    (pointsqr > DISKINNERSQR))  #whether it's close enough

                diskmask = np.logical_and(mask_crossing, mask_distance)

                if (diskmask.any()):

                    #actual collision point by intersection
                    lambdaa = -point[:, 1] / velocity[:, 1]
                    colpoint = point + lambdaa[:, np.newaxis] * velocity
                    colpointsqr = sqrnorm(colpoint)

                    if DISK_TEXTURE == "grid":
                        phi = np.arctan2(colpoint[:, 0], point[:, 2])
                        theta = np.arctan2(colpoint[:, 1],
                                           norm(point[:, [0, 2]]))
                        diskcolor =     np.outer(
                                np.mod(phi,0.52359) < 0.261799,
                                            np.array([1.,1.,0.])
                                                ) +  \
                                        np.outer(ones,np.array([0.,0.,1.]) )
                        diskalpha = diskmask

                    elif DISK_TEXTURE == "solid":
                        diskcolor = np.array([1., 1., .98])
                        diskalpha = diskmask

                    elif DISK_TEXTURE == "texture":

                        phi = np.arctan2(colpoint[:, 0], point[:, 2])

                        uv = np.zeros((numChunk, 2))

                        uv[:,
                           0] = ((phi + 2 * np.pi) % (2 * np.pi)) / (2 * np.pi)
                        uv[:, 1] = (np.sqrt(colpointsqr) -
                                    DISKINNER) / (DISKOUTER - DISKINNER)

                        diskcolor = lookup(texarr_disk, np.clip(uv, 0., 1.))
                        #alphamask = (2.0*ransample) < sqrnorm(diskcolor)
                        #diskmask = np.logical_and(diskmask, alphamask )
                        diskalpha = diskmask * np.clip(
                            sqrnorm(diskcolor) / 3.0, 0.0, 1.0)

                    elif DISK_TEXTURE == "blackbody":

                        temperature = np.exp(bb.disktemp(colpointsqr, 9.2103))

                        if REDSHIFT:
                            R = np.sqrt(colpointsqr)

                            disc_velocity = 0.70710678 * \
                                        np.power((np.sqrt(colpointsqr)-1.).clip(0.1),-.5)[:,np.newaxis] * \
                                        np.cross(UPFIELD, normalize(colpoint))

                            gamma = np.power(
                                1 - sqrnorm(disc_velocity).clip(max=.99), -.5)

                            # opz = 1 + z
                            opz_doppler = gamma * (
                                1. + np.einsum('ij,ij->i', disc_velocity,
                                               normalize(velocity)))
                            opz_gravitational = np.power(
                                1. - 1 / R.clip(1), -.5)

                            # (1+z)-redshifted Planck spectrum is still Planckian at temperature T
                            temperature /= (opz_doppler *
                                            opz_gravitational).clip(0.1)

                        intensity = bb.intensity(temperature)
                        diskcolor = np.einsum(
                            'ij,i->ij', bb.colour(temperature),
                            np.maximum(1. * ones, DISK_MULTIPLIER * intensity))

                        iscotaper = np.clip((colpointsqr - DISKINNERSQR) * 0.5,
                                            0., 1.)

                        diskalpha = iscotaper * np.clip(
                            diskmask * DISK_ALPHA_MULTIPLIER * intensity, 0.,
                            1.)

                    object_colour = blendcolors(diskcolor, diskalpha,
                                                object_colour, object_alpha)
                    object_alpha = blendalpha(diskalpha, object_alpha)

            # event horizon
            oldpointsqr = sqrnorm(oldpoint)

            mask_horizon = np.logical_and((pointsqr < 1),
                                          (sqrnorm(oldpoint) > 1))

            if mask_horizon.any():

                lambdaa = ((1. - oldpointsqr) /
                           ((pointsqr - oldpointsqr)))[:, np.newaxis]
                colpoint = lambdaa * point + (1 - lambdaa) * oldpoint

                if HORIZON_GRID:
                    phi = np.arctan2(colpoint[:, 0], point[:, 2])
                    theta = np.arctan2(colpoint[:, 1], norm(point[:, [0, 2]]))
                    horizoncolour = np.outer(
                        np.logical_xor(
                            np.mod(phi, 1.04719) < 0.52359,
                            np.mod(theta, 1.04719) < 0.52359),
                        np.array([1., 0., 0.]))
                else:
                    horizoncolour = BLACK  #np.zeros((numPixels,3))

                horizonalpha = mask_horizon

                object_colour = blendcolors(horizoncolour, horizonalpha,
                                            object_colour, object_alpha)
                object_alpha = blendalpha(horizonalpha, object_alpha)

        showprogress("generating sky layer...", i, q)

        vphi = np.arctan2(velocity[:, 0], velocity[:, 2])
        vtheta = np.arctan2(velocity[:, 1], norm(velocity[:, [0, 2]]))

        vuv = np.zeros((numChunk, 2))

        vuv[:, 0] = np.mod(vphi + 4.5, 2 * np.pi) / (2 * np.pi)
        vuv[:, 1] = (vtheta + np.pi / 2) / (np.pi)

        if SKY_TEXTURE == 'texture':
            col_sky = lookup(texarr_sky, vuv)[:, 0:3]

        showprogress("generating debug layers...", i, q)

        ##debug color: direction of view vector
        #dbg_viewvec = np.clip(view + vec3(.5,.5,0.0),0.0,1.0)
        ##debug color: direction of final ray
        ##debug color: grid
        #dbg_grid = np.abs(normalize(velocity)) < 0.1

        if SKY_TEXTURE == 'texture':
            col_bg = col_sky
        elif SKY_TEXTURE == 'none':
            col_bg = np.zeros((numChunk, 3))
        elif SKY_TEXTURE == 'final':
            dbg_finvec = np.clip(
                normalize(velocity) + vec3(.5, .5, 0.0), 0.0, 1.0)
            col_bg = dbg_finvec
        else:
            col_bg = np.zeros((numChunk, 3))

        showprogress("blending layers...", i, q)

        col_bg_and_obj = blendcolors(SKYDISK_RATIO * col_bg, ones,
                                     object_colour, object_alpha)

        showprogress("beaming back to mothership.", i, q)
        # copy back in the buffer
        if not DISABLE_SHUFFLING:
            total_colour_buffer_preproc[chunk] = col_bg_and_obj
        else:
            total_colour_buffer_preproc[chunk[0]:(chunk[-1] +
                                                  1)] = col_bg_and_obj

        #refresh display
        # NO: plt does not allow drawing outside main thread
        #if not DISABLE_DISPLAY:
        #    showprogress("updating display...")
        #    plt.imshow(total_colour_buffer_preproc.reshape((RESOLUTION[1],RESOLUTION[0],3)))
        #    plt.draw()

        showprogress("garbage collection...", i, q)
        gc.collect()

    showprogress("Done.", i, q)