Blender to MAP exporter

Post anything to do with editing Nexuiz here. Whether its problems you've had, questions, or if you just want to show off your work.

Moderators: Nexuiz Moderators, Moderators

Sun Jul 26, 2009 7:54 pm

  • Hi, here are links for the latest content related to this thread.
    The exporter: http://www.box.net/shared/r5fqthmusy
    Example "how to" map: http://www.box.net/shared/u2zm53r7i4.


    Dear Sirs,
    I've tried to use common Blender plugin (export_map.py) to use with NetRadiant. I've found a few drawbacks.
    1) It export AS IS only cubes or cube like meshes. All other geometry is splitted into triangles and is extruded into prisms.
    2) In doesn't work with textures at all.
    3) It has no options concerning light properties Blender doesn't have but NetRadiant has.
    4) Sometimes exported meshes appear to have strange artifacts.
    5) It's impossible to see the result right in Blender. One is to open file in NetRadiant to check the export results.


    I've spent a week and designed my one exporter form Blender to MAP format. From my point of view it has several fixes of problems met in current one. And these are the following.


    1) It does check if mesh is convex or not and split it into triangles only if it doesn't And doesn't depend on mesh complexity.
    2) It uses Game Logic Blender menu for storing properties Blender object doesn't have. For example for light it's "sun" "target" and "radius" properties.
    3) It export textures and texture coordinates for each face in mesh!!!!!! (It was really hard to transform uv pairs into MAP formap).
    4) It shows the export result right in Blender. So it's possible to check it and to change slightly right in Blender.

    I would be very appreciate to everyone who test my plugin. It's code is the following:

    Code: Select all
    #!BPY

    """
    Name: 'Nexuiz (.map)'
    Blender: 243
    Group: 'Export'
    Tooltip: 'Export to Nexuiz map format'
    """

    __author__ = 'sergey bashkirov'
    __version__ = '0.1'
    __email__ = "bashkirov.sergey@gmail.com"
    __bpydoc__ = """\
    This script Exports a Nexuiz map format.
    Supports meshes, lights and nurbs patch surfaces
    """

    from Blender import *
    import BPyMesh
    import os
    import math
    import string
    from os import path

    # export options.
    opts = []
    g_nexuiz_path = "c:/programs/nexuiz"
    g_fname       = "mymap.map"
    g_scale = 32
    g_extrudeHeight = 0.3

    def nexifyVector( x, y, z ):
        global g_scale
        a = round( x * g_scale )
        b = round( y * g_scale )
        c = round( z * g_scale )
        return a, b, c

    def faceNormal( face, scaleVals=1, roundVals=1 ):
        # Calculating normal:
        x1, y1, z1 = face.v[0].co.x, \
                     face.v[0].co.y, \
                     face.v[0].co.z
        x2, y2, z2 = face.v[1].co.x, \
                     face.v[1].co.y, \
                     face.v[1].co.z
        x3, y3, z3 = face.v[2].co.x, \
                     face.v[2].co.y, \
                     face.v[2].co.z
        if scaleVals:
            global g_scale
            x1, y1, z1 = x1 * g_scale, y1 * g_scale, z1 * g_scale
            x2, y2, z2 = x2 * g_scale, y2 * g_scale, z2 * g_scale
            x3, y3, z3 = x3 * g_scale, y3 * g_scale, z3 * g_scale
        if roundVals:
            x1, y1, z1 = round( x1 ), round( y1 ), round( z1 )
            x2, y2, z2 = round( x2 ), round( y2 ), round( z2 )
            x3, y3, z3 = round( x3 ), round( y3 ), round( z3 )
        nx = (y2-y1)*(z3-z1)-(y3-y1)*(z2-z1)
        ny = (x3-x1)*(z2-z1)-(x2-x1)*(z3-z1)
        nz = (x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)
        l = math.sqrt( nx * nx + ny * ny + nz * nz )
        nx = nx / l
        ny = ny / l
        nz = nz / l
        return nx, ny, nz


    def main():
        if ( nexify() ):
            showGui()
            writeFile( g_nexuiz_path + "/data/maps/" + g_fname )
        else:
            warningGui()

    def showGui():
        global g_nexuiz_path
        global g_fname
        global g_scale
        global g_extrudeHeight

        path = Get( "datadir" )
        fname = path + "/nexify.txt"
        if ( os.path.exists( fname ) ):
            file = open( fname, 'r' )
            if ( file ):
                g_nexuiz_path = file.readline()
                if ( g_nexuiz_path[ len(g_nexuiz_path) - 1 ] == "\n" ):
                    g_nexuiz_path = g_nexuiz_path[ :(len(g_nexuiz_path) - 1) ]
                g_fname = file.readline()
                if ( g_fname[ len(g_fname) - 1 ] == "\n" ):
                    g_fname = g_fname[ :(len(g_fname) - 1) ]
                g_scale = int( file.readline() )
                g_extrudeHeight = float( file.readline() )
                file.close()
        guiNexuizPath          = Draw.Create( g_nexuiz_path )
        guiFileName            = Draw.Create( g_fname )
        guiNexuizScale         = Draw.Create( g_scale )
        guiNexuizExtrudeHeight = Draw.Create( g_extrudeHeight )
       
        pup_block = [\
                        ( 'Nexuiz path:',   guiNexuizPath,          1, 128, 'Path to nexuiz root directory.'),\
                        ( 'Map file:',      guiFileName,            1, 128, 'Map file name.'),\
                        ( 'Grid scale',     guiNexuizScale,         1, 128, 'Grid scale (32).'),\
                        ( 'Extrude height', guiNexuizExtrudeHeight, 1, 128, 'Extrude height'),\
                    ]
        if not Draw.PupBlock( 'Nexuiz map export', pup_block ):
            return
        Window.WaitCursor(1)
       
        g_nexuiz_path   = guiNexuizPath.val
        guiFileName     = guiFileName.val
        g_scale         = guiNexuizScale.val
        g_extrudeHeight = guiNexuizExtrudeHeight.val

        file = open( fname, 'w' )
        if ( file ):
            file.write( g_nexuiz_path + "\n" )
            file.write( g_fname + "\n" )
            file.write( str( g_scale ) + "\n" )
            file.write( str( g_extrudeHeight ) + "\n" )
            file.close()
           
    def warningGui():
        global g_nexuiz_path
        guiNexuizPath = Draw.Create( g_nexuiz_path )
        pup_block = [ ( 'Nexuiz path:',   guiNexuizPath,          1, 128, 'Path to nexuiz root directory.') ]
        if not Draw.PupBlock( 'Some concave meshes were modified, \ncheck changes and launch again!', pup_block ):
            return
        Window.WaitCursor(1)   

    def nexify():
        print( "*************************************************************" )
        print( "*************************************************************" )
        print( "*************************************************************" )
        res = 1
        # Disable edit mode!!!!
        if Window.EditMode():
            Window.EditMode( 0 )
        scene = Scene.GetCurrent()
        #List copy because I modify it inside the loop.
        objList = scene.objects
        for obj in objList:
            print( "\n____________________________________________" )
            print( "inspecting object: " )
            print( "        type = " + obj.getType() )
            print( "        name = " + obj.getName() )
            if ( obj.getType() == 'Mesh' ):
                propsList = obj.getAllProperties()
                print( "        object properties:" )
                for prop in propsList:
                    print( "        " + prop.getName() + " = " + str( prop.getData() ) )
                skipObject = 0
                for prop in propsList:
                    if prop.getName() == 'ignore':
                        if prop.getData():
                            skipObject = 1
                            break
                if ( skipObject ):
                    print( "skipping this object due to 'ignore' property" )
                    continue
                res = checkConvex( obj )
                obj.removeProperty( "convex" )
                if ( res ):
                    print( "        shape = convex" )
                    obj.addProperty( "convex", 1, 'BOOL' )
                else:
                    print( "        shape = concave" )
                    extrudeMesh( obj, g_extrudeHeight )
                    obj.addProperty( "convex", 0, 'BOOL' )
                    obj.addProperty( "ignore", 1, 'BOOL' )
                    res = 0
                obj.makeDisplayList()
            elif ( obj.getType() == "Lamp" ):
                setLightDefaultFlags( obj );
       
        Window.RedrawAll()
        Redraw()
        return res


    def checkConvex( obj ):
        mesh = NMesh.GetRawFromObject( obj.getName() )
        # First, check if each edge belongs to exactly two different faces.
        # Each edge belongs to exactly two different faces.
        for edge in mesh.edges:
            v1 = edge.v1
            v2 = edge.v2
            n = 0
            for face in mesh.faces:
                if ( ( face.v.count( v1 ) == 1 ) and ( face.v.count( v2 ) == 1 ) ):
                    n = n + 1
            if ( n != 2 ):
                print( "        faces cnt doesn't match, expected 2, appeared " + str( n ) )
                return 0

        for edge in mesh.edges:
            v1 = edge.v1
            v2 = edge.v2
            nextEdge = 0
            for face_t in mesh.faces:
                if ( face_t.v.count( v1 ) == 1 ) and ( face_t.v.count( v2 ) == 1 ):
                    # Looking for second face with
                    for face_n in mesh.faces:
                        if ( face_n.v.count( v1 ) == 1 ) and ( face_n.v.count( v2 ) == 1 ) and ( face_n != face_t ):
                            # *************************************************************************************
                            # Faces desc:
                            # print( "face_t %d\n" % ( len( face_t.v ) ) )
                            # for v in face_t.v:
                                # print( "v[%d] = %.4f, %.4f, %.4f\n" % (v.index, v.co.x, v.co.y, v.co.z) )
                            # print( "face_n %d\n" % ( len( face_n.v ) ) )
                            # for v in face_n.v:
                                # print( "v[%d] = %.4f, %.4f, %.4f\n" % (v.index, v.co.x, v.co.y, v.co.z) )
                            # print( "n = %.4f, %.4f, %.4f\n" % (n[0], n[1], n[2]) )
                            # *************************************************************************************
                           
                            # For all edges must not be positive!
                            d = normal_x_tangent( v1, v2, face_t, face_n )
                            # if ( d <= 0 ):
                                # print( "convex\n" )
                            if ( d > 0 ):
                                return 0
                            nextEdge = 1
                            break
                if ( nextEdge ):
                    break
           
        return 1
       
    def normal_x_tangent( v1, v2, face_t, face_n ):
        global g_scale
        # Calculating normal:
        nx, ny, nz = faceNormal( face_n )
       
        x1, y1, z1 = nexifyVector( v1.co.x, v1.co.y, v1.co.z * g_scale )
        # x2, y2, z2 = round( v2.co.x * g_scale ), \
                     # round( v2.co.y * g_scale ), \
                     # round( v2.co.z * g_scale )
        for v in face_t.v:
            if ( v != v1 ) and ( v != v2 ):
                x3, y3, z3 = nexifyVector( v.co.x, v.co.y, v.co.z )

        # Looking for tangent vector:
        # t = ((z2-z1)*z3-z1*z2+z1*z1+(y2-y1)*y3-y1*y2+y1*y1+(x2-x1)*x3-x1*x2+x1*x1)/(z2*z2-2*z1*z2+z1*z1+y2*y2-2*y1*y2+y1*y1+x2*x2-2*x1*x2+x1*x1)
       
        # x = ( x2 - x1 ) * t + x1
        # y = ( y2 - y1 ) * t + y1
        # z = ( z2 - z1 ) * t + z1
       
        # vx = x3 - x
        # vy = y3 - y
        # vz = z3 - z

        vx, vy, vz = x3 - x1, y3 - y1, z3 - z1
       
        d = vx * nx + vy * ny + vz * nz

        # print( "v1: %.4f, %.4f, %.4f\n" % ( x1, y1, z1 ) )
        # print( "v2: %.4f, %.4f, %.4f\n" % ( x2, y2, z2 ) )
        # print( "v3: %.4f, %.4f, %.4f\n" % ( x3, y3, z3 ) )
        # print( "v4: %.4f, %.4f, %.4f\n" % ( x4, y4, z4 ) )
        # print( "n2: %.4f, %.4f, %.4f\n" % ( nx, ny, nz ) )
        # print( "v:  %.4f, %.4f, %.4f\n" % ( vx, vy, vz ) )
       
        return d


    def checkConvexEx( obj ):
        global g_scale
        mesh = NMesh.GetRawFromObject( obj.getName() )
        # All points from one size of the mesh.
        for face in mesh.faces:
            nx, ny, nz = nexifyVector( face.no[0], face.no[1], face.no[2] )
            x0, y0, z0 = nexifyVector( face.v[0].co.x, face.v[0].co.y, face.v[0].co.z )
            for v in mesh.verts:
                x, y, z = nexifyVector( v.co.x, v.co.y, v.co.z )
                dot = nx * (x - x0) + ny * (y - y0) + nz * (z - z0)
                if ( dot > 0 ):
                    print( "        positive dot product means concave region, data is the following:" )
                    print( "            nx, ny, nz: %.4f, %.4f, %.4f\n" % ( nx, ny, nz ) )
                    print( "            dx, dy, dz:  %.4f, %.4f, %.4f\n" % ( x-x0, y-y0, z-z0 ) )
                    print( "            x0, y0, z0:  %.4f, %.4f, %.4f\n" % ( x0, y0, z0 ) )
                    print( "            x, y, z:  %.4f, %.4f, %.4f\n" % ( x, y, z ) )
                    return -1
        # Each edge belongs to exactly two different faces.
        for edge in mesh.edges:
            v1 = edge.v1
            v2 = edge.v2
            n = 0
            for face in mesh.faces:
                if ( ( face.v.count( v1 ) == 1 ) and ( face.v.count( v2 ) == 1 ) ):
                    n = n + 1
            if ( n != 2 ):
                print( "        faces cnt doesn't match, expected 2, appeared " + str( n ) )
                return 0
        return 1
       
    def extrudeMesh( obj, h ):
        global g_scale
        mesh = NMesh.GetRawFromObject( obj.getName() )
        name = mesh.name
        propsList = obj.getAllProperties()
        for prop in propsList:
            if ( prop.getName() == 'height' ):
                h_self = prop.getData()
                if ( h_self != 0 ):
                    h = h_self
        r0 = obj.getLocation( 'worldspace' )
        i = 0
        for face in mesh.faces:
            newname = name + "." + str( i )
            newmesh = Mesh.New( newname )
            scene = Scene.GetCurrent()
            newobject = scene.objects.new( newmesh, newname )
            # Fill newmesh with vertices and faces.
            # Calculating normal:
            nx, ny, nz = faceNormal( face )
            nx = nx * h
            ny = ny * h
            nz = nz * h
           
            verts = []
            for v in face.v:
                verts.append( [ v.co.x + r0[0], v.co.y + r0[1], v.co.z + r0[2] ] )
            for v in face.v:
                verts.append( [ v.co.x + r0[0] + nx, v.co.y + r0[1] + ny, v.co.z + r0[2] + nz ] )
            n = len( face.v )
            faces = []
            if ( h < 0 ):
                # Initial face.
                faces.append( range(n) )
                # New face
                faces.append( range(2*n)[ (2*n-1):(n-1):(-1) ] )
            else:
                # Initial face.
                faces.append( range(n)[n::-1] )
                # New face
                faces.append( range(2*n)[ n:(2*n) ] )           
            # walls depend on if h > 0 or not.
            if ( h > 0 ):
                for i in range(n):
                    faces.append( [ i, (i+1) % n, n + (i+1)%n, i+n ] )
            else:
                for i in range(n):
                    faces.append( [ i, i+n, n + (i+1)%n, (i+1) % n ] )
            # Extend new mesh with verts and faces.
            print( "verts: " + str( len(verts) ) )
            print( verts )
            print( "faces: " + str( len(faces) ) )
            print( faces )
            newmesh.verts.extend( verts )
            newmesh.faces.extend( faces )
            newmesh.calcNormals()
            newobject.addProperty( "convex", 1, 'BOOL' )
            # Updating properties and mesh data.
            newmesh.update()
            newobject.makeDisplayList()
            i = i + 1
           
    def setLightDefaultFlags( obj ):
        propsList = obj.getAllProperties()
        # Currently I add special props: sun, has_target, target_x, target_y, target_z, radius.
        propsToAdd = [ "sun", "has_target", "target_x", "target_y", "target_z", "radius" ]
        propsAlreadyExist = []
        for prop in propsList:
            if ( propsToAdd.count( prop.getName() ) > 0 ):
                propsAlreadyExist.append( prop.getName() )
        for prop in propsToAdd:
            # If not exist
            if ( propsAlreadyExist.count( prop ) == 0 ):
                if ( prop == "sun" ):
                    obj.addProperty( prop, 0, 'BOOL' )
                elif ( prop == "has_target" ):
                    obj.addProperty( prop, 0, 'BOOL' )
                elif ( prop == "target_x" ):
                    obj.addProperty( prop, 0.0, 'FLOAT' )
                elif ( prop == "target_y" ):
                    obj.addProperty( prop, 0.0, 'FLOAT' )
                elif ( prop == "target_z" ):
                    obj.addProperty( prop, 0.0, 'FLOAT' )
                elif ( prop == "radius" ):
                    obj.addProperty( prop, 0.0, 'FLOAT' )
        obj.makeDisplayList()

    def writeFile( fname ):
        print 'Exporting:'
        file = open( fname, 'w' )

        objList = Object.Get()
        # Writing meshes.
        file.write( "// entity 0\n" )
        file.write( "{\n" )
        file.write( '    "classname" "worldspawn"\n' )
        for obj in objList:
            if ( obj.getType() == 'Mesh' ):
                skipObject = 0
                propList = obj.getAllProperties()
                for prop in propList:
                    if prop.getName() == 'ignore':
                        if prop.getData():
                            skipObject = 1
                            break
                    elif prop.getName() == 'convex':
                        if not prop.getData():
                            skipObject = 1
                            break
                if ( skipObject ):
                    print( "skipping this object due to 'ignore' property" )
                    continue
                writeMesh( file, obj )
        file.write( '}\n' )
        # Writing lamps.
        for obj in objList:
            if ( obj.getType() == "Lamp" ):
                propsList = obj.getAllProperties()
                skipObject = 0
                for prop in propsList:
                    if prop.getName() == 'ignore':
                        if prop.getData():
                            skipObject = 1
                            break
                if ( skipObject ):
                    print( "skipping this object due to 'ignore' property" )
                    continue
                writeLamp( file, obj )
               
        file.close()
       
    def writeMesh( file, obj ):
        global g_scale
        mesh = NMesh.GetRawFromObject( obj.getName() )
        r0 = obj.getLocation( 'worldspace' )
        #Composing a unique planes list.
        planes = []
        faces = []
        for face in mesh.faces:
            nx, ny, nz = faceNormal( face )
            nx, ny, nz = nexifyVector( nx, ny, nz )
            r0x, r0y, r0z = nexifyVector( face.v[0].co.x + r0[0], face.v[0].co.y + r0[1], face.v[0].co.z + r0[2] )
            a, b, c = nx, ny, nz
            d = round( -( nx * r0x + ny * r0y + nz * r0z ) )
            pl = [ a, b, c, d ]
            if ( planes.count( pl ) == 0 ):
                planes.append( pl )
                faces.append( face )
        # Writing planes
        stri =        '    // mesh "' + mesh.name + '"\n'
        stri = stri + '    {\n'
        for face in faces:
            stri = stri + '        '
            for v in face.v[2::-1]:
                x, y, z = nexifyVector( v.co.x + r0[0], v.co.y + r0[1], v.co.z + r0[2] )
                stri = stri + ( '( %d %d %d ) ' % ( x, y, z ) )
            # Shift x, shift y, angle, scale x, scale y, ......
            texture, x, y, ang, w, h = calcFaceUv( face )
            stri = stri + ( '%s %.8f %.8f %.8f %.8f %.8f 0 0 0\n' % ( texture, x, y, ang, w, h ) )
        stri = stri + '    }\n'
        file.write( stri )
       
    def writeLamp( file, obj ):
        global g_scale
        lamp = obj.data
        stri = '{\n    "classname" "light"\n'
        stri = stri + '    "light" %.6f\n' % ( lamp.dist * g_scale )
        r = obj.getLocation( 'worldspace' )
        x, y, z = nexifyVector( r[0], r[1], r[2] )
        stri = stri + ( '    "origin" "%d %d %d"\n' % (x, y, z) )
        stri = stri + ( '    "_color" "%.6f %.6f %.6f"\n' % tuple(lamp.col) )
        stri = stri + ( '    "style" "0"\n' )
        propsList = obj.getAllProperties()
        has_target = 0
        for prop in propsList:
            name = prop.getName()
            if ( name == "sun" ):
                if ( prop.getData() ):
                    stri = stri + '    "sun" "1"\n'
            elif ( name == "has_target" ):
                if ( prop.getData() ):
                    has_target = 1
                    target_x, target_y, targer_z = 0, 0, 0
                    radius = 0
            elif ( name == "target_x" ):
                target_x = prop.getData()
            elif ( name == "target_y" ):
                target_y = prop.getData()
            elif ( name == "target_z" ):
                target_z = prop.getData()
            elif ( name == "radius" ):
                radius = prop.getData()
        if ( has_target ):
            stri = stri + ( '    "target" "%.8f %.8f %.8f"' % ( target_x, target_y, target_z ) )
            stri = stri + ( '    "radius" "%.8f"\n' % ( radius ) )

        stri = stri + "}\n"
        file.write( stri )
       
    def calcFaceUv( face ):
        if ( len(face.v) == len(face.uv) ):
            # I don't know how it works exactly. And the following code is just
            # my guess on this.
            # Find the most like plane by comparing dot product with face normal.
            # Calculating normal:
            nx, ny, nz = faceNormal( face )
            nxa, nya, nza = abs(nx), abs(ny), abs(nz)
            # (Oxy, Oxz, Oyz)
            ox0 = [ 1, 0, 0 ]
            n0 = [ 0, 0, 1 ]
            if ( nxa >= nya ) and ( nxa >= nza ):
                ox0 = [ 0, 1, 0 ]
                n0 = [ 1, 0, 0 ]
            elif ( nya >= nxa ) and ( nya >= nza ):
                ox0 = [ 1, 0, 0 ]
                n0 = [ 0, 1, 0 ]
            elif ( nza >= nxa ) and ( nza >= nya ):
                ox0 = [ 1, 0, 0 ]
                n0 = [ 0, 0, 1 ]
            # Looking for point 0 by intersecting face plane with n0.
            r0x, r0y, r0z = nexifyVector( face.v[0].co.x, face.v[0].co.y, face.v[0].co.z )
            t = ( r0x * nx + r0y * ny + r0z * nz ) / ( n0[0] * nx + n0[1] * ny + n0[2] * nz )
            Ox, Oy, Oz = n0[0] * t, n0[1] * t, n0[2] * t
            # Project ox0 on face plane to get ox using not face normal, but n0.
            ox = [ 0, 0, 0 ]
            d = 0
            for i in range(3):
                d = d + n0[i] * ox0[i]
            for i in range(3):
                ox[i] = ox0[i] - d * n0[i]
            # make ox unit length.
            l = math.sqrt( ox[0] * ox[0] + ox[1] * ox[1] + ox[2] * ox[2] )
            for i in range(3):
                ox[i] = ox[i] / l
            # Looking for oy as cross product (n x ox)
            oy = [ 0, 0, 0 ]
            oy[0], oy[1], oy[2] = cross( nx, ny, nz, ox[0], ox[1], ox[2] )
            # make oy unit length.
            l = math.sqrt( oy[0] * oy[0] + oy[1] * oy[1] + oy[2] * oy[2] )
            for i in range(3):
                oy[i] = oy[i] / l
           
            # Rename some variables to fit external soft output.
            oxx, oxy, oxz = ox[0], ox[1], ox[2]
            oyx, oyy, oyz = oy[0], oy[1], oy[2]
           
            # Matrix for transferring x,y,z to u0,v0.
            d = nx*(oxy*oyz-oxz*oyy)+oxx*(nz*oyy-ny*oyz)+(ny*oxz-nz*oxy)*oyx
            A = [ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]
            A[0][0] = (nz*oyy-ny*oyz) / d
            A[0][1] = (nx*oyz-nz*oyx) / d
            A[0][2] = (ny*oyx-nx*oyy) / d
            A[0][3] = (nx*(oyy*Oz-oyz*Oy)-oyx*(ny*Oz-nz*Oy)-(nz*oyy-ny*oyz)*Ox) / d
            A[1][0] = (ny*oxz-nz*oxy) / d
            A[1][1] = (nz*oxx-nx*oxz) / d
            A[1][2] = (nx*oxy-ny*oxx) / d
            A[1][3] = (-nx*(oxy*Oz-oxz*Oy)+oxx*(ny*Oz-nz*Oy)+(nz*oxy-ny*oxz)*Ox) / d
            A[2][0] = (oxy*oyz-oxz*oyy) / d
            A[2][1] = (oxz*oyx-oxx*oyz) / d
            A[2][2] = (oxx*oyy-oxy*oyx) / d
            A[2][3] = (-oxx*(oyy*Oz-oyz*Oy)+oyx*(oxy*Oz-oxz*Oy)-(oxy*oyz-oxz*oyy)*Ox) / d
            A[3][3] = (nx*(oxy*oyz-oxz*oyy)+oxx*(nz*oyy-ny*oyz)-(nz*oxy-ny*oxz)*oyx) / d
            # Calculating initial uv0
            xyz = []
            for i in range(3):
                x, y, z = nexifyVector( face.v[i].co.x, face.v[i].co.y, face.v[i].co.z )
                xyz.append( [ x, y, z, 1 ] )
            uv0 = [ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ]
            for i in range(3):         # Vector number
                for j in range(4):     # Coordinate number
                    for k in range(4): # Summing index
                        # print( "A[%d][%d] * xyz[%d][%d] = " % ( j, k, i, k ) )
                        # print( "                          %.8f   *   %.8f" % ( A[j][k], xyz[i][k] ) )
                        uv0[i][j] = uv0[i][j] + A[j][k] * xyz[i][k]
            # **********************************************
            print( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" )
            print( "    checking coordinates transformation:" )
            print( "ox: %.8f, %.8f, %.8f" % (ox[0], ox[1], ox[2]) )
            print( "oy: %.8f, %.8f, %.8f" % (oy[0], oy[1], oy[2]) )
            print( "O: %.8f, %.8f, %.8f" % (Ox, Oy, Oz) )
            print( "coordinates xyz:" )
            for i in range(3):
                print( "xyz[%d][:]: %.8f, %.8f, %.8f, %.8f" % ( i, xyz[i][0], xyz[i][1], xyz[i][2], xyz[i][3] ) )
            print( "coordinates uv:" )
            for i in range(3):
                print( "uv0[%d][:]: %.8f, %.8f, %.8f, %.8f" % ( i, uv0[i][0], uv0[i][1], uv0[i][2], uv0[i][3] ) )
            # it should be uv0[:][2] == 0 and uv0[:][3] == 1!!!!!
            # **********************************************
           
            # Initial UV coordinates after transferring xyz to uv according
            # to initial guess.
            u0, v0 = uv0[0][0], uv0[0][1]
            u1, v1 = uv0[1][0], uv0[1][1]
            u2, v2 = uv0[2][0], uv0[2][1]
            # Real uv coordinates (it's necessary to multiply them on image size, I suppose):
            w, h = 32, 32 # Now I take just some common texture resolution.
            if ( face.image ):
                sz = face.image.getSize()
                w = sz[0]
                h = sz[1]
            U0, V0 = face.uv[0][0] * w, face.uv[0][1] * h
            U1, V1 = face.uv[1][0] * w, face.uv[1][1] * h
            U2, V2 = face.uv[2][0] * w, face.uv[2][1] * h
            for i in range(3):
                print( "uv[%d][:]: %.8f, %.8f" % ( i, face.uv[i][0] * w, face.uv[i][1] * h ) )
            # matrix for transferring uv to UV.
            a = [ [0, 0, 0], [0, 0, 0], [0, 0, 1] ]
            d = (u1-u0)*v2+(u0-u2)*v1+(u2-u1)*v0
            a[0][0] = -((v1-v0)*U2+(v0-v2)*U1+(v2-v1)*U0) / d
            a[0][1] = ((u1-u0)*U2+(u0-u2)*U1+(u2-u1)*U0) / d
            a[0][2] = ((u0*v1-u1*v0)*U2+(u2*v0-u0*v2)*U1+(u1*v2-u2*v1)*U0) / d
            a[1][0] = -((v1-v0)*V2+(v0-v2)*V1+(v2-v1)*V0) / d
            a[1][1] = ((u1-u0)*V2+(u0-u2)*V1+(u2-u1)*V0) / d
            a[1][2] = ((u0*v1-u1*v0)*V2+(u2*v0-u0*v2)*V1+(u1*v2-u2*v1)*V0) / d
            print( "    matrix from uv0->uv:" )
            for i in range(2):
                print( "        a[%d][0], a[%d][1], a[%d][2] = %.8f, %.8f, %.8f" % ( i, i, i, a[i][0], a[i][1], a[i][2] ) )
           
            # To find scale, shift and rotation angle let's transform unit vectors.
            r00x, r00y = a[0][2], a[1][2]
            a10x, a10y = a[0][0], a[1][0]
            a01x, a01y = a[0][1], a[1][1]
            # New reference frame orientation. (It's cross product third component.)
            d = a10x * a01y - a10y * a01x
            if d > 0:
                signScaleY = 1
            else:
                signScaleY = -1
                a01x, a01y = -a01x, -a01y
            scaleX = math.sqrt( a10x * a10x + a10y * a10y )
            scaleY = signScaleY * math.sqrt( a01x * a01x + a01y * a01y )
            print( "scaleX, scaleY = %.8f, %.8f" % ( scaleX, scaleY ) )
            # Calculating angle.
            angle = math.acos( a10x / scaleX ) * 57.295779513082320876798154814105
            if ( a10y < 0 ):
                angle = 360 - angle
            print( "angle = %.8f" % ( angle ) )
            ang = angle / 57.295779513082320876798154814105
            c = math.cos( ang )
            s = math.sin( ang )
            inv_ang_sc = [ [c/scaleX, -s/scaleX, 0 ], [s/scaleY, c/scaleY, 0], [0, 0, 1] ]
            shift = [ [0, 0, 0], [0, 0, 0], [0, 0, 0] ]
            for i in range(3):
                for j in range(3):
                    for k in range(3):
                        shift[i][j] = shift[i][j] + inv_ang_sc[i][k] * a[k][j]
            shiftX, shiftY = shift[0][2], shift[1][2]
        else:
            shiftX, shiftY, angle, scaleX, scaleY = 0, 0, 0, 1, 1
        # Texture name
        if ( face.image ):
            texture = face.image.getFilename().lower()
            # I need to cut off file extension and the
            # beginning "c:\programs\nexuiz\data\textures\".
            global g_nexuiz_path
            tex_path = g_nexuiz_path.replace( '\\', '/' )
            if ( tex_path[ len(path)-1 ] == '/' ):
                tex_path = tex_path[:(len(tex_path)-1)]
            tex_path = ( tex_path + "/data/textures/" ).lower()
            os.path.relpath( tex_path, texture )
            # Texture in on correct path.
            if ( texture.find( tex_path ) == 0 ):
                texture = texture[ len(tex_path): ]
                texture, ext = os.path.splitext( texture )
                print( "texture is: '" + texture + "', file type is: " + ext[ 1: ] )
            else:
                print( "Some misterious texture file path: '" + texture + "'" )
                texture = 'common/caulk'
           
        else:
            texture = 'common/caulk'
        return texture, shiftX, shiftY, angle, scaleX, scaleY
       
    def cross( ax, ay, az, bx, by, bz ):
        cx = ay * bz - az * by
        cy = az * bx - ax * bz
        cz = ax * by - ay * bx
        return cx, cy, cz


    if __name__ == '__main__':
        main()



    It's necessary just to save the code to a file with "py" extension and copy to ".../blender/.blender/plugins" folder. It should appear as "Nexify" menu option in export file menu directory.
    Last edited by z80 on Mon Mar 29, 2010 3:45 pm, edited 1 time in total.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Sun Jul 26, 2009 10:51 pm

  • Hi, i have not tried this yet but if it works it will be very useful, i for one have spent a lot of time trying to get blender and radiant to be nice to each other, this could be a big step in improving their compatibility. I'll get back when i've tested it, thanks!
    fishsticks
    User avatar
    Rad Ished
    Keyboard killer
     
    Posts: 609
    Joined: Wed Jun 27, 2007 8:00 am
    Location: Not the Netherlands

Sun Jul 26, 2009 11:30 pm

  • ok, first of all a big thank you for having written a so important script! Imho one of the biggest improvements in Nexuiz development would be using Blender as level editor (like one of the best Fps ever for me, PainKiller; it used Maya but it's the same!!), so maps would be more organic and less schematic and orthogonal.

    I used your script and , after setting up my path( I use linux) it works perfectly! Only few question:
    1.When I didn't set up the path( it was c:\program files\Nexuix\) and I exported a simple extruded cube, it makes a beautiful thing: it hollow the cube automatically!Now, that I set up my path correctly, it doesn't compute this action anymore!Nevermind is not so important infact I made a hollow nexuiz-style cube and the problem is over!
    2.Which path I have to use in Blender material panel for object? Maybe /home/user/games/Nexuiz/data/textures or something else because I put the texture in the same folder of the .blend files, I used relative paths and , after exported it used caulk texture
    3.You said that the script name is Nexify but I see Nexuiz(.map),is it right?

    Some tricks for users
    1If you model your map and THEN resize select all obects 1 by 1 and press Ctrl + a and choose "Scale and Rotation to OBdata" other wise objects scaled are bigger than others
    2ALWAYS before exporting shift + c and restore cursor and then select objects 1 by 1 and press f9 and down in the Mesh tab select "center cursor" otherwise your obects will show "scattered" in the universe!

    So, great script, thank you. I'll try in the next days to "squeeze" it up to make more detailed maps! :P
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Mon Jul 27, 2009 7:30 am

  • Dear Rad Ished and toneddu2000,
    Thank you for testing my script. I'm very sory for little mistakes. Script may contain several bugs, it's inavoidable, because it performs very complex caclulations. Please inform me about bugs met and any suggestions. I'd like to make really usefull tool and try to fix bugs and take into account any ideas on how to improve this exporter.

    Concerning the questions.

    1) It's really necessary to set path to Nexuiz correctly. Export is performed into "nexuiz/data/maps" folder.

    2) Concerning textures I calculate relative path to texture by subtracting the prefix ".../nexuiz/data/textures". So if texture is on this path or in any subfolder of this path it should work. Id it isn't exporter substitutes it with "common/caulk" invisible object texture.

    3) Yes, you are right! My mistake. It's "Nexuiz(.MAP)" it's in the middle of the export formats list right under the MD2 format.

    Also I've forgotten to tell that after export each mesh get several properties in "game logic" blender section. If it wasn't convex, it gain "ignore" property. And it will be skipped next time. If one want to modify it and export again he is to remove "ignore" property.

    Please let me know about any problems met! I'll try to improve the script. I really want to make Blender usable for Nexuiz map creation.

    By the way, does anybody know what is texture reference frame in Nexuiz map format exactly? And what is the use in last 3 zeros in texture transformations. There are 8 numbers. By modifying them I've succeded to get that first two are shift, 3-d is rotation angle, 4-th and 5-th are scales. And transformations apply sequence is "rotation * scale * shift * (uv)". Am I right? What are 6-th, 7-th and 8-th numbers? I tried to modify them, but got no effect.
    Last edited by z80 on Mon Jul 27, 2009 7:39 am, edited 1 time in total.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Mon Jul 27, 2009 7:34 am

Mon Jul 27, 2009 7:59 am

  • morfar wrote:This is good news for Blender people I guess. But you still need a compiler of course :P


    Actually I don't understand exactly your suggestion. Do you mean it's necessary to compile map right in Blender? Could you please explain it in more detail?
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Mon Jul 27, 2009 10:40 am

  • I believe morfar meant that you still need to compile the .map file with q3map2 to be able to play it in the game (and thus, open up NetRadiant to compile it, unless you want to fiddle around on the command line). This sure isn't a problem (other than that q3map2 pretty much sucks) :P
    User avatar
    FruitieX
    Keyboard killer
     
    Posts: 588
    Joined: Mon Nov 13, 2006 4:47 pm
    Location: Finland

Mon Jul 27, 2009 12:13 pm

  • Well, I planned to just make a good one exporter to NetRadiant MAP file format (compared with "export_map.py") and do entities work and compilation in NetRadiant :)

    Because, as for me, Blender has very powerfull vertex editing abilities. By the way a lot of people know Blender very well. And it would be very convenient to do most part of the work concerning graphics in one and the same program.

    Anyway thanks for the explanation!
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Mon Jul 27, 2009 12:58 pm

  • Awesome effort and epic first post. Your work will help many modelers/mappers. Keep up the great work and welcome to the community.
    User avatar
    [-z-]
    Site Admin and Nexuiz Ninja
     
    Posts: 1794
    Joined: Mon Nov 13, 2006 12:20 am
    Location: Florida

Mon Jul 27, 2009 2:42 pm

  • Sorry z80 but I've to bother you again with 5 questions more!
    1 I'm trying to export textures but the exporter seems to ignore my directives. I used a blender material for all the objects named cement, then I created a texture named base with orco coordinates and I use the same path of the map exporter( and maps work !) ,/home/user/games/Nexuiz/trunk/data/textures/evil8_wall/e8crete03c.jpg for example but after exported it returns a caulk texture for all the map,why?
    2 what stand for grid scale and extrude height in the export window?
    3 I've noticed that if I name a map example.map or whatever.map the exporter doesn't write anything but, if I leave the default name, mymap.map the exporter works!
    4 Sadly, I tried to export a very high poligon map (about 70000 tris) but after 1 hour and half (!) it wass still crunching numbers in the terminal and I killed it. If I use a hierarchy structure do you think the exporter would be quicker?If I, for example create a plane, I delete all the vertices and I name "root", then i create a box named "house" and I parent it to root, then same way for windows parented to house and so on, do you think that this method could emulate OctTree technology and speed up exporting process?
    5Why often,but not always, when you click export for the first time doesn't appear the usual window, but split every object in planes?This is very annoying because you then have the double count of polygons and don't
    know if the map is exported!
    Thank you for your patience!
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Mon Jul 27, 2009 3:43 pm

  • Dear toneddu2000,

    thank you for testing the exporter! That's great job! Any bug reports let me to concentrate on improving script functionality. IMHO it's normal work process :)

    1) Concerning your first problem I designed exporter to look for texture file in ".../nexuiz/data/textures" subfolder. It is because it is the same in "pk3" package format. Actually you lead me to an idea to take texture name and it's folder as a material description if it isn't on a normal path (e.i. in subfolder of ".../nexuiz/data/textures")

    2) As for your second post these values meaning is the following. Because of floating point number format limited precission sometimes when I calculate if mesh is convex or not for faces lying in one and the same plane it might show anything (convex, concave or planar). Due to this problem I do the following. I scale all dimensions on scale supplied and round them to integers. Also it's good for me because I like meters but not units. I've decided that 32 is good approach, e.i. if edge size in Blender is 1 it would be 32 units in NetRadiant after export.

    Concerning extrude height it is a height of a prism when concave mesh is splitted into individual prisms. Look (5) for details.

    3) Yap, it's a bug! I'll fix it and submit with a fixed version as soon as I can!

    4) No hierarchy wouldn't help. The problem is in text terminal output. It's my drawback! I'll make text echo output optional. I expect it to work much faster after disabling it. I've already met such a problem in my previous works. I believe it's the same. I don't think that OctTree subdivisioning is the case.

    5) It might be because one or several meshes are not convex. It informs you about that, makes these meshes "ignored" (look at game logic section there would be such a property after export try) and creates as many prisms as faces number in each mesh.

    In other words exporter substitute convex meshes with their individual faces extruded on a "extrude height" distance.

    Thank you again for exporter testing. It's very useful! Please inform me about any bugs/ wishes/suggestions!!!
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Mon Jul 27, 2009 6:55 pm

  • I have one little question not in main stream of this section. I've fixed several bugs (with file name and with textures location) in the exporter. But if I submit it as first time by pasting text I afraid this branch might become unreadable.

    Is there any way to submit files and give only links to them in text?
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Mon Jul 27, 2009 7:50 pm

  • z80 wrote:I have one little question not in main stream of this section. I've fixed several bugs (with file name and with textures location) in the exporter. But if I submit it as first time by pasting text I afraid this branch might become unreadable.

    Is there any way to submit files and give only links to them in text?


    you mean something like this: http://paste2.org/new-paste ? :D
    btw, just curios, is this code GPL ? :)
    [Want to develop? Look HERE]. Image Image Gif sauce.
    paperclips
    Alien trapper
     
    Posts: 346
    Joined: Mon Jan 12, 2009 10:27 am
    Location: internets

Mon Jul 27, 2009 8:13 pm

  • Well, thanks to paperclips here is the corrected exporter "nexify.py" code: http://paste2.org/p/345104.

    I remind that correct texture path should be subpath of ".../nexuiz/data/textures/".

    But the question is still opened. Does anybody know what is texture reference frame in NetRadiant exactly?

    btw, just curios, is this code GPL ? Smile
    This question made me stuck. :) How can I determine wheter it is GPL or not if I've written that code when I had holidays? :)
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Mon Jul 27, 2009 9:56 pm

  • I downloaded the new version of the script and textures work perfectly and works also personal map names , thx!
    Now I used a texture (of course the color version) but I noticed that normal map is not visible and I thought: maybe because the shader is not loaded, so, imho the best way could be (but I don't know how to do :roll: ) use links to shaders instead of textures. So, for istance, if I link to /data/textures/evil8_wall/e8crete03b ( shader name file, and not e8crete03b.jpg) the exporter could use e8crete03b.jpg for color, e8crete03b_bump.jpg for bump, e8crete03b_gloss.jpg for gloss map and so on, plus all the properties set in the .shader file;
    I'll let you know if I find another problem!But I think that we can start to play with the exporter for now :D !

    I think it's better that every modification you make to the script is defined in the version number, like version n.0.01, n.0.02, etc, so we could tell you: " the version 0.01" had this problem but the "0.02" hasn't"
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Tue Jul 28, 2009 5:11 am

  • Dear toneddu2000,

    thank you for the exporter testing and useful suggestion on version numbering. I've taken that into account. And by now let's call the first one number 0.01 and the second let be 0.02.

    I've found a bug by myself. I've played with exporting simple textured cube and found that texture orientation sometimes doesn't coincide in Blender and NetRadiant after export.

    And (I know, I'm stupid for that :)) I did patches export but I've forgotten to put the code into the release.

    So there would be a few more versions with bug fixes and patches export included.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Tue Jul 28, 2009 7:22 am

  • Oh, when using a pastebin for such things, make sure that you checked the good option to keep it forever, instead of deleting it after a month or something :)

    EDIT: it seems paste2.org doesn't have such options...
    Try http://pastebin.com , you can also use a subdomain like http://blend2map.pastebin.com to keep things organized :)
    Meh.
    User avatar
    Mr. Bougo
    Keyboard killer
     
    Posts: 760
    Joined: Mon Sep 10, 2007 3:29 pm

Tue Jul 28, 2009 8:55 am

  • Mr. Bougo: all right, I'll use http://blend2map.pastebin.com/ for future file links. Thanks!

    toneddu2000: I'll think how it is possible to organaze work with shaders.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Tue Jul 28, 2009 8:30 pm

  • z80 wrote:toneddu2000: I'll think how it is possible to organaze work with shaders.


    Thanks z80! That would be (together with the capability of "eat" bigger scenes) the most important steps to realize a VERY IMPORTANT tool for Nexuiz!

    p.s: I'm real ingnorant in programming so don't kill me :wink: , but would be possible to "translate" python code in c++ to embed this function in blender? Maybe this method could speed up a lot exporting processor.Infact if could be possible to integrate in blender work flow and q3map2 compiler I think a lot of level designer would switch to Blender :D !
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Tue Jul 28, 2009 8:51 pm

  • Amazing, I will give this a try tonight. I too tried to export to .map in blender a few times in the past without success. Thank you for making this!
    <Ozomahtli> what?
    nifrek
    Alien
     
    Posts: 208
    Joined: Fri Sep 22, 2006 6:43 am

Wed Jul 29, 2009 4:32 am

  • Guys, hello again!

    I've done a few little improvements to the exporter. Now it has an appropriate GUI with an explanation of what it can do.

    But bad new is that now it consists of two files :) So now one file depends on another.

    nexuiz.py link is: http://blend2map.pastebin.com/f73f72004
    nexify.py link is: http://blend2map.pastebin.com/fbea5f0a

    To install one should but "nexuiz.py" to "blender/.blender/scripts" folder and "nexify.py" to "blender/.blender/scripts/bpymodules".

    It's version "0.03".
    Fixes list is the following:

    - textures can be overwritten with shader names using Blender object logic properties named "texture[i]" (i = material index - 1) with string value coinciding with shader name.

    - it has switchable console output.

    - good GUI concerning to previous one.

    And also I still think how to make patches export. The problem is NetRadiant understands only patches of 3, 5, 7, 9, 11, 13 resolution. Guys, how should I do? Is it enough to put it on a user to watch correct patch resolution or it's required to resize patches? Any ideas?

    toneddu2000: Concerning translating code to C++. Well ........ well ..... actually it's possible but in this case user of this code is to compile and install it. And it would take me months to do that :) :) :) So IMHO until exporter doesn't work good enough it would be better to concentrate on improving it's logic.

    For the beginning let's make exporter logic as good as we can and only after that ........ :wink:
    Last edited by z80 on Wed Jul 29, 2009 4:48 am, edited 1 time in total.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Wed Jul 29, 2009 4:47 am

  • In NetRadiant svn, patches are up to 31x31. q3map2 always allowed this size.
    1. Open Notepad
    2. Paste: ÿþMSMSMS
    3. Save
    4. Open the file in Notepad again

    You can vary the number of "MS", so you can clearly see it's MS which is causing it.
    User avatar
    divVerent
    Site admin and keyboard killer
     
    Posts: 3809
    Joined: Thu Mar 02, 2006 4:46 pm
    Location: BRLOGENSHFEGLE

Wed Jul 29, 2009 9:16 am

  • It doesn't work :cry: !
    I tried to put first the first file (the one with the nexuiz path) in scripts and the second (the one with all the callback strings) in bpymodules and then I switched them but in first case Blender Scripts window doesn't show the script and in the second case terminal returns me this error
    Code: Select all
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/nexify.py", line 25, in <module>
        from nexify import CNexify
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/nexify.py", line 25, in <module>
        from nexify import CNexify
    ImportError: cannot import name CNexify
    Saved session recovery to /tmp/quit.blend


    and creates a nexify.pyc file (i renamed nexify.py the one with callbacks)

    maybe I made a mistake renaming files, but I'll try this evening, however huge thing including shaders, Thx! :D
    for the c++ method, I know, it would be a huge work and, for that purpose, there still be Netradiant :wink: !
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Wed Jul 29, 2009 10:44 am

  • toneddu2000 from the code you've supplied I can see that you named files wrong :)

    To fix please change their names ( nexuiz -> nexify and nexify -> nexuiz ) and put "nexify.py" to "scripts/bpymodules" and "nexuiz.py" to "scripts". :)

    NEXIFY.PY is module and NEXUIZ.PY is exporter script!!!
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Wed Jul 29, 2009 6:46 pm

Wed Jul 29, 2009 10:45 pm

  • So, unfortunately it doesn't work! I used now correct names now and once loaded the script appear in its new body (very cool the prepare button and the brief, considering that you made it in only two days :D ), but when I leave objects with UV (with orco coordinates) it returns me this error:

    Code: Select all
    ________________________________________
    inspecting object:
            type = Mesh
            name = Cube.005
            object properties:
            convex = 1
            shape = convex

    ____________________________________________
    inspecting object:
            type = Mesh
            name = Cube.004
            object properties:
            convex = 1
            shape = convex

    ____________________________________________
    inspecting object:
            type = Mesh
            name = Cube.003
            object properties:
            convex = 1
            shape = convex

    ____________________________________________
    inspecting object:
            type = Mesh
            name = Cube.002
            object properties:
            convex = 1
            shape = convex

    ____________________________________________
    inspecting object:
            type = Mesh
            name = Cube.001
            object properties:
            convex = 1
            shape = convex

    ____________________________________________
    inspecting object:
            type = Mesh
            name = Cube
            object properties:
            convex = 1
            shape = convex
    Exporting:
    Traceback (most recent call last):
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/nexuiz.py", line 277, in b_event
        gui_export_Callback()
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/nexuiz.py", line 355, in gui_export_Callback
        nexify.writeFile()
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/bpymodules/nexify.py", line 427, in writeFile
        self.writeMesh( file, obj )
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/bpymodules/nexify.py", line 508, in writeMesh
        texture, x, y, ang, w, h = self.calcFaceUv( face, materialsList, textureOverDict )
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/bpymodules/nexify.py", line 731, in calcFaceUv
        tex_path = g_nexuiz_path.replace( '\\', '/' )
    NameError: global name 'g_nexuiz_path' is not defined


    if I unwrap all the meshes it gives to me this error:

    Code: Select all
    Traceback (most recent call last):
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/nexuiz.py", line 277, in b_event
        gui_export_Callback()
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/nexuiz.py", line 355, in gui_export_Callback
        nexify.writeFile()
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/bpymodules/nexify.py", line 427, in writeFile
        self.writeMesh( file, obj )
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/bpymodules/nexify.py", line 508, in writeMesh
        texture, x, y, ang, w, h = self.calcFaceUv( face, materialsList, textureOverDict )
      File "/home/toneddu/progs/grafica/blender/.blender/scripts/bpymodules/nexify.py", line 574, in calcFaceUv
        matr = obj.matrixWorld
    NameError: global name 'obj' is not defined


    I tried everything, I changed path to nexuiz, cause I've svn version and my path was /home/user/games/Nexuiz/trunk to /home/user/games/Nexuiz and I copied everything there, but nothing :cry: ! I really don't have idea, my objects are all center cursor,are resized to 1,1,1 and have a name!I use ubuntu 9.04.Could be a system bug?Maybe are you using Vista or Xp?
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Thu Jul 30, 2009 5:01 am

  • I see, it appears, I've repaired one thing but broken another :) Good work, thanks! Console output immediately tells me what's wrong.

    Obvious mistakes, I'm very sorry. It will take me an hour to fix it.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Thu Jul 30, 2009 6:55 am

  • Here it is.

    nexify.py: http://blend2map.pastebin.com/f24c85d48
    nexuiz.py: http://blend2map.pastebin.com/f569f80a2

    Version 0.05. Fixed problems:

    - with exporting textured objects.

    - for surface to be textured "texture" property must exist.


    By the way, toneddu2000, IMHO it is worth to use UV instead of ORCO for texture to match in NetRadiant.

    And one more thing. As far ar in blender texture is mapped using UV but in NetRadiant using X,Y,ANG,SZ_X,SZ_Y not any UV set could be transformed into appropriate NetRadiant coordinates set. Make sure you texture your face in such a way that uv geometry transformation is a combination of shift, scale and rotation transformation of initial face shape!!! It means it should be NO TANGENT SHIFTS!!!
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Thu Jul 30, 2009 10:52 am

  • AWESOME! :D It works flawless! It shows shaders(color,bump,normal and gloss),uv texture and all the meshes!
    Thanks a lot!
    Ok, I think it's benchmark time :wink: ! If I have to be honest I didn't understand the NO TANGENT SHIFTS argoments for textures. Could you please explain it and the light parameters (how can I set a sun in blender, where I found Blender object logic) argument. Because, if you want, I'll make a pdf manual with a short export tutorial which I'll be able to upgrade every time you upgrade the script! If you want, of course!
    User avatar
    toneddu2000
    Alien trapper
     
    Posts: 251
    Joined: Mon Mar 09, 2009 7:56 pm
    Location: Italy

Thu Jul 30, 2009 1:07 pm

  • toneddu2000: in other words it would be better to

    1) unwrap each face UV set along this face normal
    and
    2) move, scale and rotate all UV vertices but NOT drag them one by one.

    If there two conditions are met there shouldn't be problems.

    Blender logic section appeares in Buttons window if one presses F4 (or click the first button with magenta smile face on it). In Logic window press ADD PROPERTY choose type BOOL/INT/FLOAT/STRING according to a property type wanted, name it sun/target/....

    Sure it would be nice if you make some document.

    At this moment objects of "Mesh", "Surf" and "Lamp" are supported by exporter.

    All 3 object types can have BOOL property "ignore", if it's true, object is ignored when exporting. This property is assigned to convex meshes during PREPARE procedure when prisms are added for each face of that concave mesh.

    "Mesh" could have the following properties:

    - "height" (float) - if mesh is concave this value overwrites the "extrude height parameter".

    - "texture[i]" (string), i = 0, 1, 2, ... - overwrites texture name of faces material with index (i+1). (+1 is because in GUI materials numbering starts form 1, but in script form 0)

    - "convex" (bool) - just informational property. It's set automaticaly when PREPARE button is pressed. It tells to a user if this is an appropriate mesh geometry or not.


    "Lamp" may have properties:

    - "sun" (bool) - is it a sunlight without attenuation or not.
    - "has_target" (bool) - is it a directional light.
    - "target_x", "target_y", "target_z" (float) - where is target point for directional light.
    - "radius" (float) - directional light spot radius.


    "Surf" now can have only one property

    - "texture" (string) - it's material name.
    User avatar
    z80
    Advanced member
     
    Posts: 92
    Joined: Sun Jul 26, 2009 7:35 pm
    Location: Russia

Next


Return to Nexuiz - Editing




Information
  • Who is online
  • Users browsing this forum: No registered users and 1 guest