如何从Superbible Opengl中读取,解析SBM文件格式 [英] how to read, parse the SBM file format from Superbible Opengl

查看:140
本文介绍了如何从Superbible Opengl中读取,解析SBM文件格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请专家,专家和其他人来帮助阅读和解析python文件.

Calling on experts, gurus, and anybody to help read and parse a file in python.

在第6版的第751页上.或第7版第800页.关于Superbible OpenGL,请参见附录B.SBM文件格式在某种程度上似乎可以很好地解释该格式.

On page 751 of 6th ed. or page 800 of 7th ed. of Superbible OpenGL there is Appendix B. The SBM File Format that seems to explain well the format to some extent.

我试图用python实现这种文件格式的读取器.

I have tried to implement in python a reader of this file format.

好的,已经取得了进展.我已经将Rabbid76惊人的代码合并到提供的源代码中.尽管我正在尝试取得更多进展.

OK, progress has been made. I have merged Rabbid76 amazing code to the source provided. Though I am attempting to make additional headway.

2019年6月23日更新-重大进展,修复了有关glVertexAttribPointer(i,...错误的错误.

Update Jun 23, 2019 - major progress, fixed the error about glVertexAttribPointer(i, ... error.

当天,修复了Python无法找到变量 first 错误.

Same day, fixed the Python cannot find the variable first error.

同一天,成功!!!!我们有渲染的东西!这是读取的最终程序 sbmloader.py ,解析从此问题创建的SBM文件格式.

Same day, SUCCESS!!!! We have something that renders! Here is the final program sbmloader.py that reads, parses the SBM file format, created from this question.

尽管下一个问题.已在

Though the next question. Already answered, at part 2, creation of a ktxloader

  • How to get the rendered object to appear as the torus/donut it is supposed to be? Perhaps there is something to do with loading the file here pattern1.ktx How do I load this to the variable tex_object variable? Simply assigning it doesn't seem to do anything. Ok, that's because ktx files are a different file format left for another project.

更新:2019年6月24日 Rabbid76已使用完美代码修复了渲染问题.我很震惊,非常感谢你!

Update: June 24, 2019 The rendering issue has been fixed with perfect code by Rabbid76. I in wow shock, thank you very much!

要读取,解析的数据在此处 torus_nrms_tc .sbm

The data to read, parse is here torus_nrms_tc.sbm

任何帮助,评论或见解将不胜感激. 这是我到目前为止所拥有的.

Any assistance, comments, or insight would be greatly appreciated. Here is what I have so far.

import sys
import time 
import os
import time
import math
import ctypes

currentWDir = os.getcwd()
print( 'current working directory: {}'.format( str(currentWDir) ) )
fileDir = os.path.dirname(os.path.abspath(__file__)) # det the directory of this file
print( 'current location of self: {}'.format( str(fileDir) ) )
parentDir = os.path.abspath(os.path.join(fileDir, os.pardir)) # get the parent directory of this file
sys.path.insert(0, parentDir)
print( 'insert system directory: {}'.format( str(parentDir) ) )
os.chdir( fileDir )
baseWDir = os.getcwd()
print( 'changed current working directory: {}'.format( str(baseWDir) ) )
print ( '' )

fullscreen = True

import numpy.matlib 
import numpy as np 

try:
    from OpenGL.GLUT import *
    from OpenGL.GL import *
    from OpenGL.GLU import *
    #from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, glBindVertexArray
except:
    print ('''
    ERROR: PyOpenGL not installed properly.
        ''')
    sys.exit()

def SB6M_FOURCC(a,b,c,d):
    return ( (ord(a) << 0) | (ord(b) << 8) | (ord(c) << 16) | (ord(d) << 24) )

SB6M_MAGIC = SB6M_FOURCC('S','B','6','M')

SB6M_CHUNK_TYPE_INDEX_DATA      = SB6M_FOURCC('I','N','D','X')
SB6M_CHUNK_TYPE_VERTEX_DATA     = SB6M_FOURCC('V','R','T','X')
SB6M_CHUNK_TYPE_VERTEX_ATTRIBS  = SB6M_FOURCC('A','T','R','B')
SB6M_CHUNK_TYPE_SUB_OBJECT_LIST = SB6M_FOURCC('O','L','S','T')
SB6M_CHUNK_TYPE_COMMENT         = SB6M_FOURCC('C','M','N','T')
SB6M_CHUNK_TYPE_DATA            = SB6M_FOURCC('D','A','T','A')

class SB6M_HEADER:
    def __init__(self, data):
        int_data = np.frombuffer(np.array(data[:16], dtype=np.byte), dtype=np.uint32)
        self.magic, self.size, self.num_chunks, self.flags = int_data 
        print(self.magic, self.size, self.num_chunks, self.flags)

class SB6M_CHUNK_HEADER:
    def __init__(self, data, offset):
        int_data = np.frombuffer(np.array(data[offset:offset+8], dtype=np.byte), dtype=np.uint32)
        self.type, self.size = int_data

class SB6M_CHUNK_INDEX_DATA(SB6M_CHUNK_HEADER):
     def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.index_type, self.index_count, self.index_data_offset = int_data

class SB6M_CHUNK_VERTEX_DATA(SB6M_CHUNK_HEADER):
     def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.data_size, self.data_offset, self.total_vertices = int_data

class SB6M_CHUNK_VERTEX_DATA(SB6M_CHUNK_HEADER):
     def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.data_size, self.data_offset, self.total_vertices = int_data

SB6M_VERTEX_ATTRIB_FLAG_NORMALIZED = 0x00000001
SB6M_VERTEX_ATTRIB_FLAG_INTEGER    = 0x00000002

class SB6M_VERTEX_ATTRIB_DECL:
    def __init__(self, data, offset):
        self.name = ''.join([chr(n) for n in data[offset:offset+64] if n > 30])
        int_data = np.frombuffer(np.array(data[offset+64:offset+84], dtype=np.byte), dtype=np.uint32)
        self.size, self.type, self.stride, self.flags, self.data_offset = int_data

class SB6M_VERTEX_ATTRIB_CHUNK(SB6M_CHUNK_HEADER):
    def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+12], dtype=np.byte), dtype=np.uint32)
        self.attrib_count = int_data[0]
        self.attrib_data = []
        for i in range(self.attrib_count):
            self.attrib_data.append(SB6M_VERTEX_ATTRIB_DECL(data, offset+12+i*84))

class SB6M_DATA_CHUNK(SB6M_CHUNK_HEADER):
    def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.encoding, self.data_offset, self.data_length = int_data

class SB6M_SUB_OBJECT_DECL:
    def __init__(self, data, offset):
        int_data = np.frombuffer(np.array(data[offset:offset+8], dtype=np.byte), dtype=np.uint32)
        self.first, self.count = int_data

class SB6M_CHUNK_SUB_OBJECT_LIST(SB6M_CHUNK_HEADER):
    def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+12], dtype=np.byte), dtype=np.uint32)
        self.count = int_data[0]
        self.sub_object = []
        for i in range(self.count):
            self.sub_object.append(SB6M_SUB_OBJECT_DECL(data, offset+12+i*8))

class SB6M_CHUNK_HEADER_:
    chunk_type = 0
    chunk_name = ''
    size = 0

class SB6M_DATA_ENCODING:
    SB6M_DATA_ENCODING_RAW  = 0


class SB6M_CHUNK_COMMENT:
    header = SB6M_CHUNK_HEADER_()
    comment = []
    comment.append('')
    comment.append('')


# data_buffer = GLuint(0)
# vao = GLuint(0)
# index_type = GLuint(0)
index_offset = GLuint(0)



def get_sub_object_info(index, first, count):
    if (index >= num_sub_objects):
        first = 0
        count = 0
    else:
        first = sub_object[index].first;
        count = sub_object[index].count;

def render(instance_count = 1, base_instance = 0):
    render_sub_object(0, instance_count, base_instance)


class SBMObject:

    def __init__(self):
        self.vao = GLuint(0)

    def load(self, filename):

        vertex_attrib_chunk = None
        vertex_data_chunk = None
        index_data_chunk = None
        sub_object_chunk = None
        data_chunk = None

        #try:
        data = numpy.fromfile(filename, dtype=np.byte)
        filesize = data.size

        header = SB6M_HEADER(data)
        offset = header.size

        for i in range(header.num_chunks):

            chunk = SB6M_CHUNK_HEADER(data, offset)
            if chunk.type == SB6M_CHUNK_TYPE_VERTEX_ATTRIBS:
                vertex_attrib_chunk = SB6M_VERTEX_ATTRIB_CHUNK(data, offset) 
            elif chunk.type == SB6M_CHUNK_TYPE_VERTEX_DATA:
                vertex_data_chunk = SB6M_CHUNK_VERTEX_DATA(data, offset)
            elif chunk.type == SB6M_CHUNK_TYPE_INDEX_DATA:
                index_data_chunk = SB6M_CHUNK_INDEX_DATA(data, offset) 
            elif chunk.type == SB6M_CHUNK_TYPE_SUB_OBJECT_LIST:
                sub_object_chunk = SB6M_CHUNK_SUB_OBJECT_LIST(data, offset)
            elif chunk.type == SB6M_CHUNK_TYPE_DATA:
                data_chunk = SB6M_DATA_CHUNK(data, offset) 
            else:
                raise

            offset += chunk.size

        #except:
        #    print("error reading file {}".format(filename))

        print("finished reading")

        if vertex_data_chunk and vertex_attrib_chunk:
            start = vertex_data_chunk.data_offset
            end = start + vertex_data_chunk.data_size
            vertex_data = np.frombuffer(np.array(data[start:end], dtype=np.byte), dtype=np.float)

            data_buffer = glGenBuffers(1)
            glBindBuffer(GL_ARRAY_BUFFER, data_buffer)
            glBufferData(GL_ARRAY_BUFFER, vertex_data, GL_STATIC_DRAW)

            self.vertexcount = vertex_data_chunk.total_vertices
            self.vao = glGenVertexArrays(1)
            glBindVertexArray(self.vao)

            for attrib_i, attrib in enumerate(vertex_attrib_chunk.attrib_data):
                if attrib.name=='position' or attrib.name=='map1': 
                    glVertexAttribPointer(attrib_i,
                        attrib.size, attrib.type,
                        GL_TRUE if (attrib.flags & SB6M_VERTEX_ATTRIB_FLAG_NORMALIZED) != 0 else GL_FALSE,
                        attrib.stride, ctypes.c_void_p(int(attrib.data_offset)))
                    glEnableVertexAttribArray(attrib_i)

    def render(self):

        glBindVertexArray(self.vao)
        glDrawArrays(GL_TRIANGLES, 0, self.vertexcount)

# Vertex program
vs_source = '''
#version 420 core
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (location = 0) in vec4 position;
layout (location = 4) in vec2 tc;
out VS_OUT
{
    vec2 tc;
} vs_out;
void main(void)
{
    vec4 pos_vs = mv_matrix * position;
    vs_out.tc = tc;
    gl_Position = proj_matrix * pos_vs;
}
'''

# Fragment program
fs_source = '''
#version 420 core
layout (binding = 0) uniform sampler2D tex_object;
in VS_OUT
{
    vec2 tc;
} fs_in;
out vec4 color;
void main(void)
{
    color = texture(tex_object, fs_in.tc * vec2(3.0, 1.0));
}
'''

identityMatrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]

render_prog = GLuint(0)

uniforms_mv_matrix = (GLfloat * 16)(*identityMatrix)
uniforms_proj_matrix = (GLfloat * 16)(*identityMatrix)

tex_index = 0
tex_object = []

M3D_PI = 3.14159265358979323846
M3D_PI_DIV_180 = M3D_PI / 180.0
M3D_INV_PI_DIV_180 = 57.2957795130823229

def m3dDegToRad(num):
    return (num * M3D_PI_DIV_180)

def m3dRadToDeg(num):
    return (num * M3D_INV_PI_DIV_180)

# Translate matrix. Only 4x4 matrices supported
def m3dTranslateMatrix44(m, x, y, z):
    m[12] += x
    m[13] += y
    m[14] += z

# Creates a 4x4 rotation matrix, takes radians NOT degrees
def m3dRotationMatrix44(m, angle, x, y, z):
    s = math.sin(angle)
    c = math.cos(angle)
    mag = float((x * x + y * y + z * z) ** 0.5)

    if mag == 0.0:
        m3dLoadIdentity(m)
        return

    x /= mag
    y /= mag
    z /= mag

    xx = x * x
    yy = y * y
    zz = z * z
    xy = x * y
    yz = y * z
    zx = z * x
    xs = x * s
    ys = y * s
    zs = z * s
    one_c = 1.0 - c

    m[0] = (one_c * xx) + c
    m[1] = (one_c * xy) - zs
    m[2] = (one_c * zx) + ys
    m[3] = 0.0

    m[4] = (one_c * xy) + zs
    m[5] = (one_c * yy) + c
    m[6] = (one_c * yz) - xs
    m[7] = 0.0

    m[8] = (one_c * zx) - ys
    m[9] = (one_c * yz) + xs
    m[10] = (one_c * zz) + c
    m[11]  = 0.0

    m[12] = 0.0
    m[13] = 0.0
    m[14] = 0.0
    m[15] = 1.0

def m3dMultiply(A, B):
    C = (GLfloat * 16)(*identityMatrix)
    for k in range(0, 4):
        for j in range(0, 4):
            C[k*4+j] = A[0*4+j] * B[k*4+0] + A[1*4+j] * B[k*4+1] + \
                       A[2*4+j] * B[k*4+2] + A[3*4+j] * B[k*4+3]
    return C

def m3dOrtho(l, r, t, b, n, f):
    return (GLfloat * 16)(
        2/(r-l),      0,            0,            0,
        0,            2/(t-b),      0,            0,
        0,            0,            -2/(f-n),     0,
        -(r+l)/(r-l), -(t+b)/(t-b), -(f+n)/(f-n), 1)

def m3dPerspective(fov_y, aspect, n, f):
    a = aspect
    ta = math.tan( fov_y / 2 )
    return (GLfloat * 16)(
        1/(ta*a),  0,     0,              0,
        0,         1/ta,  0,              0,
        0,         0,    -(f+n)/(f-n),   -1,
        0,         0,    -2*f*n/(f-n),    0)

def rotation_matrix(axis, theta):
    """
    Return the rotation matrix associated with counterclockwise rotation about
    the given axis by theta radians.
    """
    axis = np.asarray(axis)
    axis = axis / math.sqrt(np.dot(axis, axis))
    a = math.cos(theta / 2.0)
    b, c, d = -axis * math.sin(theta / 2.0)
    aa, bb, cc, dd = a * a, b * b, c * c, d * d
    bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
    return np.array([[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac), 0],
                     [2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab), 0],
                     [2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc, 0],
                     [0,0,0,1]])

def translate(tx, ty, tz):
    """creates the matrix equivalent of glTranslate"""
    return np.array([1.0, 0.0, 0.0, 0.0, 
                     0.0, 1.0, 0.0, 0.0, 
                     0.0, 0.0, 1.0, 0.0, 
                        tx, ty, tz, 1.0], np.float32)


def load_shaders():
        global render_prog
        global uniforms_mv_matrix
        global uniforms_proj_matrix

        if (render_prog):
            glDeleteProgram(render_prog);

        fs = glCreateShader(GL_FRAGMENT_SHADER);

        glShaderSource(fs, fs_source);
        glCompileShader(fs);

        vs = glCreateShader(GL_VERTEX_SHADER);

        glShaderSource(vs, vs_source);
        glCompileShader(vs);

        render_prog = glCreateProgram();
        glAttachShader(render_prog, vs);
        glAttachShader(render_prog, fs);
        glLinkProgram(render_prog);

        glDeleteShader(vs);
        glDeleteShader(fs);

        uniforms_mv_matrix = glGetUniformLocation(render_prog, "mv_matrix");
        uniforms_proj_matrix = glGetUniformLocation(render_prog, "proj_matrix");


class Scene:
    def __init__(self, width, height):

        self.width = width
        self.height = height

        B = (0x00, 0x00, 0x00, 0x00)
        W = (0xFF, 0xFF, 0xFF, 0xFF)
        tex_data = [
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
            B, W, B, W, B, W, B, W, B, W, B, W, B, W, B, W,
            W, B, W, B, W, B, W, B, W, B, W, B, W, B, W, B,
        ]

        tex_object.append( glGenTextures(1) )

        #glGenTextures(1, tex_object[0]);
        glBindTexture(GL_TEXTURE_2D, tex_object[0]);
        glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, tex_data);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        tex_object.append (  glGenTextures(1) )

        #tex_object[1] = sb7::ktx::file::load("pattern1.ktx");

        myobject.load("torus_nrms_tc.sbm");

        load_shaders();

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);


    def display(self):

        global uniforms_mv_matrix
        global uniforms_proj_matrix

        currentTime = time.time()

        gray = [ 0.2, 0.2, 0.2, 1.0 ];
        ones = [ 1.0 ];

        glClearBufferfv(GL_COLOR, 0, gray);
        glClearBufferfv(GL_DEPTH, 0, ones);

        glViewport(0, 0, self.width, self.height);

        glBindTexture(GL_TEXTURE_2D, tex_object[tex_index]);

        glUseProgram(render_prog);


        T = (GLfloat * 16)(*identityMatrix)
        RX = (GLfloat * 16)(*identityMatrix)
        RY = (GLfloat * 16)(*identityMatrix)
        R = (GLfloat * 16)(*identityMatrix)


        # way # 1 - works
        # T = translate(0.0, 0.0, -4.0).reshape(4,4)
        # RX = np.array(rotation_matrix( [1.0, 0.0, 0.0], currentTime * m3dDegToRad(17.0)))
        # RY = np.array(rotation_matrix( [0.0, 1.0, 0.0], currentTime * m3dDegToRad(13.0)))
        # mv_matrix = np.matmul(np.matmul(RY, RX), T)


        # way # 2 - works !!
        m3dTranslateMatrix44(T, 0, 0, -4)
        m3dRotationMatrix44(RX, currentTime * m3dDegToRad(17.0), 1.0, 0.0, 0.0)
        m3dRotationMatrix44(RY, currentTime * m3dDegToRad(13.0), 0.0, 1.0, 0.0)

        # way # 2 - option A   works!
        # Matrix multiplication is not commutative, order matters when multiplying matrices
        R = m3dMultiply(RY, RX) 
        mv_matrix = m3dMultiply(T, R)

        # way # 2 - option B    works!
        # T = np.matrix(T).reshape(4,4)
        # mv_matrix = np.matmul(np.matmul(np.matrix(RY).reshape(4,4), np.matrix(RX).reshape(4,4)).reshape(4,4), T)


        # way # 3 - works also
        # T  = np.matrix(translate(0.0, 0.0, -4.0)).reshape(4,4)
        # RX = np.matrix(rotation_matrix( [1.0, 0.0, 0.0], currentTime * m3dDegToRad(17.0)))
        # RY = np.matrix(rotation_matrix( [0.0, 1.0, 0.0], currentTime * m3dDegToRad(13.0)))
        # mv_matrix = RX * RY * T


        proj_matrix = (GLfloat * 16)(*identityMatrix)
        proj_matrix = m3dPerspective(m3dDegToRad(60.0), float(self.width) / float(self.height), 0.1, 100.0);    

        glUniformMatrix4fv(uniforms_mv_matrix, 1, GL_FALSE, mv_matrix);
        glUniformMatrix4fv(uniforms_proj_matrix, 1, GL_FALSE, proj_matrix);

        myobject.render()
        #gltDrawTorus(0.35, 0.15, 40, 20)

        glutSwapBuffers()

    def reshape(self, width, height):
        self.width = width
        self.height = height

    def keyboard(self, key, x, y ):
        global fullscreen
        global tex_index

        print ('key:' , key)
        if key == b'\x1b': # ESC
            sys.exit()

        elif key == b'f' or key == b'F': #fullscreen toggle

            if (fullscreen == True):
                glutReshapeWindow(self.width, self.height)
                glutPositionWindow(int((1360/2)-(512/2)), int((768/2)-(512/2)))
                fullscreen = False
            else:
                glutFullScreen()
                fullscreen = True

        elif key == b'r' or key == b'R': 
            load_shaders()

        elif key == b't' or key == b'T': 
            tex_index+=1
            if (tex_index > 1):
                tex_index = 0

        print('done')

    def init(self):
        pass

    def timer(self, blah):

        glutPostRedisplay()
        glutTimerFunc( int(1/60), self.timer, 0)
        time.sleep(1/20.0)

myobject = SBMObject()
if __name__ == '__main__':
    start = time.time()

    glutInit()
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
    glutInitWindowSize(512, 512)
    w1 = glutCreateWindow('OpenGL SuperBible - Texture Coordinates')

    fullscreen = False
    #glutFullScreen()

    scene = Scene(512, 512)
    glutReshapeFunc(scene.reshape)
    glutDisplayFunc(scene.display)
    glutKeyboardFunc(scene.keyboard)

    glutIdleFunc(scene.display)
    #glutTimerFunc( int(1/60), scene.timer, 0)

    scene.init()

    glutMainLoop()

纹理文件的数据结构示例-p.757 OpenGL Superbible第6版.或第807页第7版.

Example of data structure of texture file - p.757 OpenGL Superbible 6th ed. or p.807 7th ed.

推荐答案

由于您已经在使用 NumPy ,我将给yuo一个答案,该答案使用NumPy读取二进制文件. NumPy具有一些功能,可以按不同的数据类型重新解释缓冲区数据,而这正是解释二进制文件所需要的.

Since you are already using NumPy, i'll give yuo an answer which uses NumPy to read the binary file. NumPy has some had functionality to reinterpret buffer data by different data type and that is exactly what is needed to interpret a binary file.

可以将二进制文件读取为字节数组. numpy.fromfile .例如:

data = numpy.fromfile(filename, dtype=np.byte)

unit32) ="nofollow noreferrer"> numpy.frombuffer .例如:

Some bytes of the array can be interpreted as unsigned integer (unit32) by numpy.frombuffer. e.g.:

class SB6M_HEADER:
    def __init__(self, data):
        int_data = np.frombuffer(np.array(data[:16], dtype=np.byte), dtype=np.uint32)
        self.magic, self.size, self.num_chunks, self.flags = int_data 
        print(self.magic, self.size, self.num_chunks, self.flags)

分别从 sb6mfile.h 移植源代码 sb7object.cpp 对python和"* .sbm"文件:

Porting the source code from sb6mfile.h respectively sb7object.cpp to python and reading and "*.sbm" file:

def SB6M_FOURCC(a,b,c,d):
    return ( (ord(a) << 0) | (ord(b) << 8) | (ord(c) << 16) | (ord(d) << 24) )

SB6M_MAGIC = SB6M_FOURCC('S','B','6','M')

SB6M_CHUNK_TYPE_INDEX_DATA      = SB6M_FOURCC('I','N','D','X')
SB6M_CHUNK_TYPE_VERTEX_DATA     = SB6M_FOURCC('V','R','T','X')
SB6M_CHUNK_TYPE_VERTEX_ATTRIBS  = SB6M_FOURCC('A','T','R','B')
SB6M_CHUNK_TYPE_SUB_OBJECT_LIST = SB6M_FOURCC('O','L','S','T')
SB6M_CHUNK_TYPE_COMMENT         = SB6M_FOURCC('C','M','N','T')
SB6M_CHUNK_TYPE_DATA            = SB6M_FOURCC('D','A','T','A')

class SB6M_HEADER:
    def __init__(self, data):
        int_data = np.frombuffer(np.array(data[:16], dtype=np.byte), dtype=np.uint32)
        self.magic, self.size, self.num_chunks, self.flags = int_data 
        print(self.magic, self.size, self.num_chunks, self.flags)

class SB6M_CHUNK_HEADER:
    def __init__(self, data, offset):
        int_data = np.frombuffer(np.array(data[offset:offset+8], dtype=np.byte), dtype=np.uint32)
        self.type, self.size = int_data

class SB6M_CHUNK_INDEX_DATA(SB6M_CHUNK_HEADER):
     def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.index_type, self.index_count, self.index_data_offset = int_data

class SB6M_CHUNK_VERTEX_DATA(SB6M_CHUNK_HEADER):
     def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.data_size, self.data_offset, self.total_vertices = int_data

class SB6M_CHUNK_VERTEX_DATA(SB6M_CHUNK_HEADER):
     def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.data_size, self.data_offset, self.total_vertices = int_data

SB6M_VERTEX_ATTRIB_FLAG_NORMALIZED = 0x00000001
SB6M_VERTEX_ATTRIB_FLAG_INTEGER    = 0x00000002

class SB6M_VERTEX_ATTRIB_DECL:
    def __init__(self, data, offset):
        self.name = ''.join([chr(n) for n in data[offset:offset+64] if n > 30])
        int_data = np.frombuffer(np.array(data[offset+64:offset+84], dtype=np.byte), dtype=np.uint32)
        self.size, self.type, self.stride, self.flags, self.data_offset = int_data

class SB6M_VERTEX_ATTRIB_CHUNK(SB6M_CHUNK_HEADER):
    def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+12], dtype=np.byte), dtype=np.uint32)
        self.attrib_count = int_data[0]
        self.attrib_data = []
        for i in range(self.attrib_count):
            self.attrib_data.append(SB6M_VERTEX_ATTRIB_DECL(data, offset+12+i*84))

class SB6M_DATA_CHUNK(SB6M_CHUNK_HEADER):
    def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+20], dtype=np.byte), dtype=np.uint32)
        self.encoding, self.data_offset, self.data_length = int_data

class SB6M_SUB_OBJECT_DECL:
    def __init__(self, data, offset):
        int_data = np.frombuffer(np.array(data[offset:offset+8], dtype=np.byte), dtype=np.uint32)
        self.first, self.count = int_data

class SB6M_CHUNK_SUB_OBJECT_LIST(SB6M_CHUNK_HEADER):
    def __init__(self, data, offset):
        super().__init__(data, offset)
        int_data = np.frombuffer(np.array(data[offset+8:offset+12], dtype=np.byte), dtype=np.uint32)
        self.count = int_data[0]
        self.sub_object = []
        for i in range(self.count):
            self.sub_object.append(SB6M_SUB_OBJECT_DECL(data, offset+12+i*8))

 def load(filename):

    vertex_attrib_chunk = None
    vertex_data_chunk = None
    index_data_chunk = None
    sub_object_chunk = None
    data_chunk = None

    try:
        data = numpy.fromfile(filename, dtype=np.byte)
        filesize = data.size

        header = SB6M_HEADER(data)
        offset = header.size

        for i in range(header.num_chunks):

            chunk = SB6M_CHUNK_HEADER(data, offset)
            if chunk.type == SB6M_CHUNK_TYPE_VERTEX_ATTRIBS:
                vertex_attrib_chunk = SB6M_VERTEX_ATTRIB_CHUNK(data, offset) 
            elif chunk.type == SB6M_CHUNK_TYPE_VERTEX_DATA:
                vertex_data_chunk = SB6M_CHUNK_VERTEX_DATA(data, offset)
            elif chunk.type == SB6M_CHUNK_TYPE_INDEX_DATA:
                index_data_chunk = SB6M_CHUNK_INDEX_DATA(data, offset) 
            elif chunk.type == SB6M_CHUNK_TYPE_SUB_OBJECT_LIST:
                sub_object_chunk = SB6M_CHUNK_SUB_OBJECT_LIST(data, offset)
            elif chunk.type == SB6M_CHUNK_TYPE_DATA:
                data_chunk = SB6M_DATA_CHUNK(data, offset) 
            else:
                raise

            offset += chunk.size

    except:
        print("error reading file {}".format(filename))

最后可以读取浮点顶点数据:

Finally the floating point vertex data can be read:

if vertex_data_chunk and vertex_attrib_chunk:
    start = vertex_data_chunk.data_offset
    end = start + vertex_data_chunk.data_size
    vertex_data = np.frombuffer(np.array(data[start:end], dtype=np.byte), dtype=np.float)

    data_buffer = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, data_buffer)
    glBufferData(GL_ARRAY_BUFFER, vertex_data, GL_STATIC_DRAW)

    vertexcount = vertex_data_chunk.total_vertices
    vao = glGenVertexArrays(1)
    glBindVertexArray(self.vao)

    for attrib_i, attrib in enumerate(vertex_attrib_chunk.attrib_data):
        if attrib.name=='position' or attrib.name=='map1':  
            glVertexAttribPointer(attrib_i,
                attrib.size, attrib.type,
                GL_TRUE if (attrib.flags & SB6M_VERTEX_ATTRIB_FLAG_NORMALIZED) != 0 else GL_FALSE,
                attrib.stride, ctypes.c_void_p(int(attrib.data_offset)))
            glEnableVertexAttribArray(attrib_i)

最后绘制网格:

glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, vertexcount)

这篇关于如何从Superbible Opengl中读取,解析SBM文件格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆