Skin a quadsphere with copies of 1 subdivided plane?

I need to Skin a quadsphere with copies of 1 subdivided plane,
then deform the vertex based on the texture color under each vertex

the issue is that the Quads of the quadsphere are not planes, they are oblique

  1. cut a oblique grid onto each face
  2. skin it with a grid of copies of the same subdivided plane
  3. deform the vertex height based on the texture at the UV of the vertex
  4. save the data in a world dictionary

later a KDTree will load the tiles in a radius.

(I have this part covered)

I need help with 1 and 2

got it!

import bge
import mathutils
import math

def main():

    cont = bge.logic.getCurrentController()
    own = cont.owner
    mesh = own.meshes[0]
    
    if 'kd' not in own:
        size = mesh.numPolygons
        plane = own.scene.objectsInactive['Plane']
        table = {}
        
        #build array of subdivided patch on layer 2
        for vertex in range(plane.meshes[0].getVertexArrayLength(0)):
            vert = plane.meshes[0].getVertex(0,vertex)
            value = math.ceil(vert.XYZ.x*16)/16
            Y_value = math.ceil(vert.XYZ.y*16)/16
            if value not in table:
                table.update({ value:[ [vertex,Y_value] ] } )
            else:
                print('adding')
                entry = table[value]
                entry.append([vertex,Y_value])
                table[value]=entry
                
        for entry in table:
            data = table[entry]
            data = sorted(data, key=lambda x: x[1])
            table[entry]=data
        l = []
        for entry in table:
           l.append( [table[entry],entry] )
        l = sorted(l, key=lambda x: x[1])   
        l2 = []
        for entry in l:
            l2.append(entry[0])
            
                     
        print(l2)    
        own['array']=l2
        
        print('-')
        #test row 1 of x
        print(l[0][0][0])
        print(l[0][0][1])
        print(l[0][0][2])
        print(l[0][0][3])
        print(l[0][0][4])
        print(l[0][0][5])    
        print(l[0][0][6])
        print(l[0][0][7])
        print(l[0][0][8])
       
        print('-')
        #test row 2
        print(l[1][0][0])
        print(l[1][0][1])
        print(l[1][0][2])
        print(l[1][0][3])
        print(l[1][0][4])
        print(l[1][0][5])
        print(l[1][0][6])
        print(l[1][0][7])
        print(l[1][0][8])
        print('-')
        
        #build kdtree of all cubesphere faces
        kd = mathutils.kdtree.KDTree(size)
        FaceDict = {} 
        for i in range(mesh.numPolygons):
            poly = mesh.getPolygon(i)
            v1 = mesh.getVertex(0,poly.v1)
            v2 = mesh.getVertex(0,poly.v2)
            v3 = mesh.getVertex(0,poly.v3)
            
            v4 = mesh.getVertex(0,poly.v4)
            
            
            v1p = v1.XYZ
            v1.color = [v1p.x,v1p.y,v1p.z,1]
            
            v2p = v2.XYZ
            v2.color = [v2p.x,v2p.y,v2p.z,1]
            
            v3p =  v3.XYZ
            v3.color = [v3p.x,v3p.y,v3p.z,1]
            
            v4p = v4.XYZ
            v4.color = [v4p.x,v4p.y,v4p.z,1]
            
            o = (v1p+v2p+v3p+v4p)/4
            
            origin = o
            FaceDict.update({ i:[origin,v1p,v2p,v3p,v4p] })
            kd.insert(origin,i)
            
            
        print('createdTree')
        kd.balance()    
        own['kd']=kd
        own['faceDict']=FaceDict
        own['patchesFree']=[]
        own['filledLocations']={}
        own['P_index']=0
        #own.localScale =[.95,.95,.95]
            
            
    #generate patches to use to skin cubesphere         
    elif len(own['patchesFree'])<=256-16:
        for i in range(16):
            #print('creating patch '+str(own['P_index']+1))
           
            I = own['P_index']
            own['P_index']+=1
            added = own.scene.addObject('Plane',own,0)
            name = 'meshCopy_'+str(I)
            libNew = bge.logic.LibNew(name, 'Mesh',[added.meshes[0].name] )
            added.replaceMesh(libNew[0],1,1)
            #added.name = name
            own['patchesFree'].append(added)
            #added.suspendPhysics()
            added.visible = False
            
    else:             
        
        location =  own.worldOrientation.inverted()* (own.scene.objects['skin_ob'].worldPosition-own.worldPosition)
        
        near = own['kd'].find_range(location, .25)
        '''
        #draw faces to be skinned using drawLine
        for entry in near:
            orig = own['faceDict'][entry[1]][0]
            v2 = own.getVectTo(orig)
            p2  = orig+(v2[1]*.25)
            bge.render.drawLine(orig,p2,[0,0,1])
        '''    
        #try and fill a face    
        for entry in near:
            if len(own['patchesFree'])>=1 and entry[1] not in own['filledLocations']:
                face = own['patchesFree'][0]
                own['patchesFree'].pop(0)
                face.visible = True
                own['filledLocations'].update({entry[1]:face})
                orig = own['faceDict'][entry[1]][0]
                v1 = own['faceDict'][entry[1]][1]
                
                #bge.render.drawLine(v1,own.worldPosition,(0,0,1))
                
                v2 = own['faceDict'][entry[1]][2]
                
                #bge.render.drawLine(v2,own.worldPosition,(0,0,1))
                v3 = own['faceDict'][entry[1]][3]
                #bge.render.drawLine(v3,own.worldPosition,(0,0,1))
                v4 = own['faceDict'][entry[1]][4]
                #bge.render.drawLine(v1,v2,(1,0,0))
                #bge.render.drawLine(v2,v3,(0,1,0))
               # bge.render.drawLine(v3,v4,(0,0,1))
               # bge.render.drawLine(v4,v1,(1,0,1))
                face.worldPosition = orig 
                for x in range(len(own['array'])):
                    p1 = v1.lerp(v2,x/8)
                    p2 = v4.lerp(v3,x/8)
                    #bge.render.drawLine(p1,p2,(1,1,1))
                    v2x = -(v2-v3).normalized()
                    v2x
                   # bge.render.drawLine(v2,p2,(1,1,1))
                    
                    
                    for y in range(len(own['array'][x])):
                        yWidth = ((v2-v3).magnitude) /8
                        p2 = p1+(v2x*(yWidth*y))   
                        #bge.render.drawLine(own.worldPosition,p2,(0,0,0))
                        data = own['array'][x][y]
                        print("X is "+str(x)+" and y is "+str(y)+" and v_index is "+str(data[0]))
                        vert = face.meshes[0].getVertex(0,data[0])
                        vert.XYZ = face.worldOrientation.inverted()*(p2-face.worldPosition)
                        
                        vect2 = own.getVectTo(p2)
                        vert.normal = -vect2[1]
                        
                        #here is the vertex and it's position in the array
                        #this is where I can use the array xy to set the vert location
                        #[0][0] should be v1
                        #[0][8] should be v2
                        #[8][0] should be v3
                        #[8][8] should be v4
                        
                         
                
                break
            
            
        #uncomment to draw all faces origin and normal    
        #for entry in own['faceDict']:
           # orig = own['faceDict'][entry][0]
           # v2 = own.getVectTo(orig)
           # p2  = orig+(-v2[1]*.125)
          #  bge.render.drawLine(orig,p2,[1,0,0])
            
                
main()

working_skin_cube_sphere.blend (2.1 MB)

LOL, riddled with draw line :blush: I am guilty of this as well…hey, it’s useful…and it’s just kinda neat.

how are you getting the hit.UV color?..this is something I attempted before(getting the pixel color at the hit point from a raycast)…but I don’t think I ever got it working…

when you can get the vertex you can just use vertex.uv
:smiley:

https://docs.blender.org/api/blender_python_api_2_67_1/bge.types.KX_VertexProxy.html#bge.types.KX_VertexProxy.UV

I’m sorry for taking this off topic…but I already know I can get the color at the vertex point in UV space.

I was trying to get raycasting to read the pixel color regardless of vertexes…the hit position color…I don’t remember how I was trying to do it…maybe I also tried with a camera??? no idea…meh…it’s definitely something I want to play with when I get the time.

use math or triangle mesh and get the hit poly and then use mathutils barycentric transform and the uv to get the pixel to sample.

I convert the image buffer into a 2d array of vector from the 1d image buffer list thing.

pixel = array[x][y]

1 Like


1 Like

update -


now I doubled the density and used rounded vertex position to average normal and color at edges

now loading bubble installed.

1 Like

i’m impressed by the fact that you can keep it at 60 fps, really nice work! Keep on amazing us :slight_smile:
(yeah i know its UPbge and their new toys, but still)

2 Likes