4

私は何か間違ったことをしていると確信しています.OBJ形式の3Dモデルを解析し、jsonオブジェクトを出力するGoプログラムを持っています. ゴルーチンを追加せずに実行すると、次の出力が得られます。

$ go run objParser.go ak47.obj extincteur_obj.obj 
--Creating ak47.json3d from ak47.obj
--Exported 85772 faces with 89088 verticies
--Creating extincteur_obj.json3d from extincteur_obj.obj
--Exported 150316 faces with 151425 verticies
Parsed 2 files in 8.4963s

次に、ゴルーチンを追加すると、次の出力が得られます。

$ go run objParser.go ak47.obj extincteur_obj.obj 
--Creating ak47.json3d from ak47.obj
--Creating extincteur_obj.json3d from extincteur_obj.obj
--Exported 85772 faces with 89088 verticies
--Exported 150316 faces with 151425 verticies
Parsed 2 files in 10.23137s

印刷される順序は、解析のインターレースを考慮して予想したものですが、実際に時間がかかる理由はわかりません! コードはかなり長いです。可能な限り省略しましたが、それでもかなり長いです。申し訳ありません!

package main

func parseFile(name string, finished chan int) {
    var Verts []*Vertex
    var Texs []*TexCoord
    var Faces []*Face

    var objFile, mtlFile, jsonFile *os.File
    var parseMaterial bool

    // Set up files and i/o
    inName := name
    outName := strings.Replace(inName, ".obj", ".json3d", -1)
    parseMaterial = false

    fmt.Printf("--"+FgGreen+"Creating"+Reset+" %s from %s\n", outName, inName)

    var err error
    var part []byte
    var prefix bool

    if objFile, err = os.Open(inName); err != nil {
        fmt.Println(FgRed+"!!Failed to open input file!!"+Reset)
        return
    }

    if jsonFile, err = os.Create(outName); err != nil {
        fmt.Println(FgRed+"!!Failed to create output file!!"+Reset)
        return
    }

    reader := bufio.NewReader(objFile)
    writer := bufio.NewWriter(jsonFile)
    buffer := bytes.NewBuffer(make([]byte, 1024))

    // Read the file in and parse out what we need
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }

        buffer.Write(part)
        if !prefix {
            line := buffer.String()
            if(strings.Contains(line, "v ")) {
                Verts = append(Verts, parseVertex(line))
            } else if(strings.Contains(line, "vt ")) {
                Texs = append(Texs, parseTexCoord(line))
            } else if(strings.Contains(line, "f ")) {
                Faces = append(Faces, parseFace(line, Verts, Texs))
            } else if(strings.Contains(line, "mtllib ")) {
                mtlName := strings.Split(line, " ")[1]
                if mtlFile, err = os.Open(mtlName); err != nil {
                    fmt.Printf("--"+FgRed+"Failed to find material file: %s\n"+Reset, mtlName)
                    parseMaterial = false
                } else {
                    parseMaterial = true
                }
            }
            buffer.Reset()
        }
    }

    if err == io.EOF {
        err = nil
    }

    objFile.Close()

    // Write out the data
    writer.WriteString("{\"obj\":[\n");

    // Write out the verts
    writer.WriteString("{\"vrt\":[\n");
    for i, vert := range Verts {
        writer.WriteString(vert.String())
        if i < len(Verts) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Write out the faces
    writer.WriteString("],\"fac\":[\n")
    for i, face := range Faces {
        writer.WriteString(face.String(true))
        if i < len(Faces) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Write out the normals
    writer.WriteString("],\"nrm\":[")
    for i, face := range Faces {


        writer.WriteString("[")
        for j, vert := range face.verts {
            length := math.Sqrt((vert.X * vert.X) + (vert.Y * vert.Y) + (vert.Z * vert.Z))
            x := vert.X / length
            y := vert.Y / length
            z := vert.Z / length
            normal := fmt.Sprintf("[%f,%f,%f]", x, y, z)
            writer.WriteString(normal)
            if(j < len(face.verts)-1) { writer.WriteString(",") }
        }
        writer.WriteString("]")




        //writer.WriteString("[0, 1, 0]")
        if i < len(Faces) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Write out the tex coords
    writer.WriteString("],\"tex\":[")
    for i, face := range Faces {
        writer.WriteString("[")
        writer.WriteString(face.tex[0].String())
        writer.WriteString(",")
        writer.WriteString(face.tex[1].String())
        writer.WriteString(",")
        writer.WriteString(face.tex[2].String())
        writer.WriteString("]")
        if i < len(Faces) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Close obj block
    writer.WriteString("]}]");

    if parseMaterial {
        writer.WriteString(",mat:[{");
        reader := bufio.NewReader(mtlFile)

        // Read the file in and parse out what we need
        for {
            if part, prefix, err = reader.ReadLine(); err != nil {
                break
            }

            buffer.Write(part)
            if !prefix {
                line := buffer.String()
                if(strings.Contains(line, "map_Kd ")) {
                    parts := strings.Split(line, " ")
                    entry := fmt.Sprintf("\"t\":\"%s\",", parts[1])
                    writer.WriteString(entry)

                    width, height := 256, 256
                    var imageFile *os.File
                    if imageFile, err = os.Open(parts[1]); err != nil {
                        fmt.Printf("--"+FgRed+"Failed to find %s, defaulting to 256x256"+Reset+"\n", parts[1])
                        return
                    } else {
                        var config image.Config
                        imageReader := bufio.NewReader(imageFile)
                        config, err = jpeg.DecodeConfig(imageReader)
                        width, height = config.Width, config.Height
                        fmt.Printf("--"+FgGreen+"Verifing"+Reset+" that %s is %dpx x %dpx\n", parts[1], width, height)
                    }

                    size := fmt.Sprintf("\"w\":%d,\"h\":%d,", width, height)
                    writer.WriteString(size)

                } else if(strings.Contains(line, "Kd ")) {
                    parts := strings.Split(line, " ")
                    entry := fmt.Sprintf("\"r\":%s, \"g\":%s, \"b\":%s,", parts[1], parts[2], parts[3])
                    writer.WriteString(entry)
                }
                buffer.Reset()
            }
        }

        if err == io.EOF {
            err = nil
        }

        writer.WriteString("\"res\":100,\"uv\":true}]");
    }

    // Close json
    writer.WriteString("}");
    writer.Flush()
    jsonFile.Close()

    fmt.Printf("--"+FgGreen+"Exported"+Reset+" %d faces with %d verticies\n", len(Faces), len(Verts))

    finished <- -1
}

func main(){
    // Verify we were called correctly
    if len(os.Args) < 2 {
        fmt.Println("Usage: go run objParser.go <OBJ File>");
        return
    }

    files := len(os.Args)
    finished := make(chan int)

    now := time.Now()

    for i := 1; i < files; i++ {
        go parseFile(os.Args[i], finished)
    }

    for i := 1; i < files; i++ {
        <- finished
    }

    fmt.Printf("Parsed %d files in %s\n", files-1, time.Since(now))
}
4

1 に答える 1

6

GOMAXPROCS 環境変数を使用可能なプロセッサの最大数に設定する必要があります。または、実行時に関数GOMAXPROCSを使用します。

于 2012-09-18T18:47:55.037 に答える