2015-09-10 5 views
8

पर मैं एक .obj-file में लोड करने की कोशिश कर रहा हूं और glDrawElements की सहायता से इसे खींच रहा हूं।एकाधिक ओबीजे-इंडेक्स-बफर ओपनजीएल के 1 इंडेक्स बफर

अब glDrawArrays सबकुछ पूरी तरह से काम करता है, लेकिन यह निश्चित रूप से अक्षम है।

मेरे पास अभी समस्या है, कि एक .obj-file एकाधिक इंडेक्स-बफर (प्रत्येक विशेषता के लिए) का उपयोग करता है जबकि ओपनजीएल केवल एक का उपयोग कर सकता है। इसलिए मुझे उन्हें तदनुसार मानचित्र बनाना होगा।

वहां बहुत सारे छद्म-एल्गोरिदम हैं और मुझे सी ++ कार्यान्वयन भी मिला है। मुझे सी ++ का थोड़ा सा पता है लेकिन अजीब तरह से मुझे स्कैला में मेरे कार्यान्वयन में मदद नहीं मिली।

चलो देखते हैं:

private def parseObj(path: String): Model = 
{ 
    val objSource: List[String] = Source.fromFile(path).getLines.toList 

    val positions: List[Vector3] = objSource.filter(_.startsWith("v ")).map(_.split(" ")).map(v => new Vector3(v(1).toFloat,v(2).toFloat,v(3).toFloat))//, 1.0f)) 
    val normals: List[Vector4] = objSource.filter(_.startsWith("vn ")).map(_.split(" ")).map(v => new Vector4(v(1)toFloat,v(2).toFloat, v(3).toFloat, 0.0f)) 
    val textureCoordinates: List[Vector2] = objSource.filter(_.startsWith("vt ")).map(_.split(" ")).map(v => new Vector2(v(1).toFloat, 1-v(2).toFloat)) // TODO 1-y because of blender 
    val faces: List[(Int, Int, Int)] = objSource.filter(_.startsWith("f ")).map(_.split(" ")).flatten.filterNot(_ == "f").map(_.split("/")).map(a => ((a(0).toInt, a(1).toInt, a(2).toInt))) 

    val vertices: List[Vertex] = for(face <- faces) yield(new Vertex(positions(face._1-1), textureCoordinates(face._2-1))) 

    val f: List[(Vector3, Vector2, Vector4)] = for(face <- faces) yield((positions(face._1-1), textureCoordinates(face._2-1), normals(face._3-1))) 
    println(f.mkString("\n")) 

    val indices: List[Int] = faces.map(f => f._1-1) // Wrong! 

    new Model(vertices.toArray, indices.toArray) 
} 

val indices: List[Int] मेरी पहली अनुभवहीन दृष्टिकोण था और निश्चित रूप से गलत है। लेकिन चलिए शीर्ष पर शुरू करें:

मैं फ़ाइल में लोड करता हूं और इसके माध्यम से जाता हूं। (मुझे लगता है कि आप जानते हैं कि एक .obj-file कैसे बनाई गई है)

मैंने शिखर, बनावट-निर्देशांक और मानदंडों में पढ़ा है। तब मैं चेहरे पर आ गया।

अब, मेरे उदाहरण में प्रत्येक चेहरे में vertexAtIndexX, textureCoordAtIndexY, normalAtIndexZ परिभाषित 3 मान v_x, t_y, n_z है। इसलिए इनमें से प्रत्येक एक वर्टेक्स को परिभाषित करता है जबकि इनमें से एक तिहाई (या फ़ाइल में एक पंक्ति) फेस/पॉलीगॉन/त्रिकोण को परिभाषित करता है।

val indices: List[Int] = faces.map(f => f._1-1) // Wrong!

:

val vertices: List[Vertex] = for(face <- faces) yield(new Vertex(positions(face._1-1), textureCoordinates(face._2-1))) में मैं वास्तव में कोने (एक मामले वर्ग है कि वर्तमान में केवल पदों और बनावट निर्देशांक रखती है और अब के लिए normals neglects)

वास्तविक समस्या पैदा करने की कोशिश इस लाइन है

असली सूचकांक मैं मूल रूप से इस बजाय की क्या करने की जरूरत प्राप्त करने के लिए

val vertices: List[Vertex] = for(face <- faces) yield(new Vertex(positions(face._1-1), textureCoordinates(face._2-1))) और val indices: List[Int] = faces.map(f => f._1-1) // Wrong!

छद्म कोड:

Iterate over all faces 
    Iterate over all vertices in a face 
     Check if we already have that combination of(position, texturecoordinate, normal) in our newVertices 

     if(true) 
      indices.put(indexOfCurrentVertex) 
     else 
      create a new Vertex from the face 
      store the new vertex in the vertex list 
      indices.put(indexOfNewVertex) 

अभी तक मैं पूरी तरह से अटक कर रहा हूँ। मैंने अलग-अलग चीजों की कोशिश की है, लेकिन वास्तव में काम करने वाले एक अच्छे और साफ समाधान के साथ नहीं आ सकता है।

हालात की तरह:

val f: List[(Vector3, Vector2, Vector4)] = for(face <- faces) yield((positions(face._1-1), textureCoordinates(face._2-1), normals(face._3-1))) 

और f.distinct करने की कोशिश कर काम नहीं कर रहे हैं, जो पूरी तरह से समझ में आता है अगर मैं फ़ाइल को देखो और अभी तक वो क्या है अलग, सभी प्रविष्टियों अद्वितीय देखते हैं, कोई बात नहीं है क्योंकि वहाँ छद्म कोड मुझे जांचने के लिए कहता है।

बेशक

तो मैं तदनुसार (अधिमानतः एक एक लाइनर में और कार्यात्मक सुंदरता का एक बहुत कुछ के साथ)

लेकिन मैं डुप्लीकेट ढूंढना का प्रयास करना चाहिए सूचकांक को भरने के लिए की आवश्यकता होगी तो ... मैं तरह कर रहा हूँ परेशान मुझे लगता है कि मैं सभी संदर्भों के साथ, विभिन्न "कोष्ठक" और "पदों" को बहुत अधिक मिलाता हूं।

तो, क्या मैं गलत सोच रहा हूं, या एल्गोरिदम/सोच सही है और मुझे इसे अच्छे, साफ (और वास्तव में काम कर रहे) स्कैला कोड में लागू करने की आवश्यकता है?

कृपया मुझे प्रबुद्ध करें!

var index: Int = 0 
val map: mutable.HashMap[(Int, Int, Int), Int] = new mutable.HashMap[(Int, Int, Int), Int].empty 

val combinedIndices: ListBuffer[Int] = new ListBuffer[Int] 

for(face <- faces) 
{ 
    val vID: Int = face._1-1 
    val nID: Int = face._2-1 
    val tID: Int = face._3-1 

    var combinedIndex: Int = -1 

    if(map.contains((vID, nID, tID))) 
    { 
     println("We have a duplicate, wow!") 
     combinedIndex = map.get((vID, nID, tID)).get 
    } 
    else 
    { 
     combinedIndex = index 
     map.put((vID, nID, tID), combinedIndex) 
     index += 1 
    } 

    combinedIndices += combinedIndex 
} 

जहां अभी भी सामना करना पड़ता है है:

टिप्पणियों के अनुसार, मैं एक छोटे से अद्यतन किया जाता

val faces: List[(Int, Int, Int)] = objSource.filter(_.startsWith("f ")).map(_.split(" ")).flatten.filterNot(_ == "f").map(_.split("/")).map(a => ((a(0).toInt, a(1).toInt, a(2).toInt))) 

मज़ेदार तथ्य मैं अभी भी यह स्पष्ट रूप से समझ नहीं कर रहा हूँ, क्योंकि वह जिस तरह से मुझे कभी डुप्लिकेट नहीं मिलता!

मतलब है कि combinedIndices अंत में जैसे प्राकृतिक संख्या रखती है:

ListBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...) 
+1

मुझे स्कैला बिल्कुल नहीं पता, इसलिए मैं यह नहीं बता सकता कि यह वही है जो आप पहले से कर रहे हैं। लेकिन आपको आवश्यक महत्वपूर्ण डेटा संरचना एक नक्शा है जो स्थिति के ** इंडेक्स **, बनावट निर्देशांक और कुंजी के रूप में चेहरे रिकॉर्ड से सामान्य, और ओपनजीएल वर्टेक्स की अनुक्रमणिका के रूप में एक टुपल का उपयोग करता है। यहां मेरे पुराने जवाब में छद्म कोड है, यदि यह आपकी खोजों में पहले से मिली पोस्टों में से एक नहीं है: http://stackoverflow.com/questions/23349080/opengl-index-buffers-difficulties/23356738#23356738 । –

+0

@RetoKoradi: तो प्रत्येक चेहरे के लिए मुझे कुंजी [पदों (face._1-1), बनावट कोऑर्डिनेट्स (फेस ._2-1), मानक (चेहरा ._2-1) के साथ एक मानचित्र-प्रविष्टि बनाने की आवश्यकता है]) मैं कैसे करूँ फिर मूल्य के लिए ओपनजीएल वर्टेक्स की अनुक्रमणिका की गणना करें? – Sorona

+0

आप 0 से शुरू करते हैं, और प्रत्येक बार जब आपको एक नई कशेरुक की आवश्यकता होती है (यानी कुंजी पहले से ही मानचित्र में नहीं थी)। यह जुड़े छद्म कोड से काफी स्पष्ट होना चाहिए। –

उत्तर

1

यह जावास्क्रिप्ट (खेद नहीं स्केला) है, लेकिन यह टिप्पणी की है और कन्वर्ट करने के लिए काफी आसान हो shoul।

// bow-tie 
var objString = "v 0 0 0\nv 1 1 0\nv 1 -1 0\nv -1 1 0\nv -1 -1 0\n" + 
    "vt 0 .5\nvt 1 1\nvt 1 0\n" + 
    "vn 0 0 1\n" + 
    "f 1/1/1 2/2/1 3/3/1\nf 1/1/1 4/2/1 5/3/1"; 
// output indices should be [0, 1, 2, 0, 3, 4] 
// parse the file 
var lines = objString.split("\n"); 
var data = lines.map(function(line) { return line.split(" "); }); 
var v = []; 
var t = []; 
var n = []; 
var f = []; 
var indexMap = new Map(); // HashMap<face:string, index:integer> 
var nextIndex = 0; 
var vertices = []; 
var indices = []; 
// fill vertex, texture and normal arrays 
data.filter(function(d) { return d[0] == "v"; }).forEach(function(d) { v.push([parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]); }); 
data.filter(function(d) { return d[0] == "vt"; }).forEach(function(d) { t.push([parseFloat(d[1]), parseFloat(d[2])]); }); 
data.filter(function(d) { return d[0] == "vn"; }).forEach(function(d) { n.push([parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]); }); 
// 
console.log("V", v.toString()); 
console.log("T", t.toString()); 
console.log("N", n.toString()); 
// create vertices and indices arrays by parsing faces 
data.filter(function(d) { return d[0] == "f"; }).forEach(function(d) { 
    var f1 = d[1].split("/").map(function(d) { return parseInt(d)-1; }); 
    var f2 = d[2].split("/").map(function(d) { return parseInt(d)-1; }); 
    var f3 = d[3].split("/").map(function(d) { return parseInt(d)-1; }); 
    // 1 
    if(indexMap.has(d[1].toString())) { 
     indices.push(indexMap.get(d[1].toString())); 
    } else { 
     vertices = vertices.concat(v[f1[0]]).concat(t[f1[1]]).concat(n[f1[2]]); 
     indexMap.set(d[1].toString(), nextIndex); 
     indices.push(nextIndex++); 
    } 
    // 2 
    if(indexMap.has(d[2].toString())) { 
     indices.push(indexMap.get(d[2].toString())); 
    } else { 
     vertices = vertices.concat(v[f2[0]]).concat(t[f2[1]]).concat(n[f2[2]]); 
     indexMap.set(d[2].toString(), nextIndex); 
     indices.push(nextIndex++); 
    } 
    // 3 
    if(indexMap.has(d[3].toString())) { 
     indices.push(indexMap.get(d[3].toString())); 
    } else { 
     vertices = vertices.concat(v[f3[0]]).concat(t[f3[1]]).concat(n[f3[2]]); 
     indexMap.set(d[3].toString(), nextIndex); 
     indices.push(nextIndex++); 
    } 
}); 
// 
console.log("Vertices", vertices.toString()); 
console.log("Indices", indices.toString()); 

उत्पादन

V 0,0,0,1,1,0,1,-1,0,-1,1,0,-1,-1,0 
T 0,0.5,1,1,1,0 
N 0,0,1 
Vertices 0,0,0,0,0.5,0,0,1,1,1,0,1,1,0,0,1,1,-1,0,1,0,0,0,1,-1,1,0,1,1,0,0,1,-1,-1,0,1,0,0,0,1 
Indices 0,1,2,0,3,4 

JSFiddle http://jsfiddle.net/8q7jLvsq/2

केवल एक चीज मैं कर रहा हूँ ~ अलग ढंग से स्ट्रिंग टोपी उपयोग कर रहा है में कुंजी के रूप में एक चेहरे की भागों में से एक का प्रतिनिधित्व करता है मेरी indexMap (उदा: "25/32/5")।

EDIT JSFiddle http://jsfiddle.net/8q7jLvsq/2/ यह संस्करण वर्टेक्स, बनावट और सामान्य के लिए दोहराए गए मानों को जोड़ता है। यह ओबीजे फाइलों को अनुकूलित करता है जो प्रत्येक चेहरे को अद्वितीय बनाने वाले मान मूल्यों को दोहराते हैं।

// bow-tie 
var objString = "v 0 0 0\nv 1 1 0\nv 1 -1 0\nv 0 0 0\nv -1 1 0\nv -1 -1 0\n" + 
    "vt 0 .5\nvt 1 1\nvt 1 0\nvt 0 .5\nvt 1 1\nvt 1 0\n" + 
    "vn 0 0 1\nvn 0 0 1\nvn 0 0 1\nvn 0 0 1\nvn 0 0 1\nvn 0 0 1\n" + 
    "f 1/1/1 2/2/2 3/3/3\nf 4/4/4 5/5/5 6/6/6"; 
// output indices should be [0, 1, 2, 0, 3, 4] 
// parse the file 
var lines = objString.split("\n"); 
var data = lines.map(function(line) { return line.split(" "); }); 
var v = []; 
var t = []; 
var n = []; 
var f = []; 
var vIndexMap = new Map(); // map to earliest index in the list 
var vtIndexMap = new Map(); 
var vnIndexMap = new Map(); 
var indexMap = new Map(); // HashMap<face:string, index:integer> 
var nextIndex = 0; 
var vertices = []; 
var indices = []; 
// fill vertex, texture and normal arrays 
data.filter(function(d) { return d[0] == "v"; }).forEach(function(d, i) { 
    v[i] = [parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]; 
    var key = [d[1], d[2], d[3]].toString(); 
    if(!vIndexMap.has(key)) { 
     vIndexMap.set(key, i); 
    } 
}); 
data.filter(function(d) { return d[0] == "vt"; }).forEach(function(d, i) { 
    t[i] = [parseFloat(d[1]), parseFloat(d[2])]; 
    var key = [d[1], d[2]].toString(); 
    if(!vtIndexMap.has(key)) { 
     vtIndexMap.set(key, i); 
    } 
}); 
data.filter(function(d) { return d[0] == "vn"; }).forEach(function(d, i) { 
    n[i] = [parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]; 
    var key = [d[1], d[2], d[3]].toString(); 
    if(!vnIndexMap.has(key)) { 
     vnIndexMap.set(key, i); 
    } 
}); 
// 
console.log("V", v.toString()); 
console.log("T", t.toString()); 
console.log("N", n.toString()); 
// create vertices and indices arrays by parsing faces 
data.filter(function(d) { return d[0] == "f"; }).forEach(function(d) { 
    var f1 = d[1].split("/").map(function(d, i) { 
     var index = parseInt(d)-1; 
     if(i == 0) index = vIndexMap.get(v[index].toString()); 
     else if(i == 1) index = vtIndexMap.get(t[index].toString()); 
     else if(i == 2) index = vnIndexMap.get(n[index].toString()); 
     return index; 
    }); 
    var f2 = d[2].split("/").map(function(d, i) { 
     var index = parseInt(d)-1; 
     if(i == 0) index = vIndexMap.get(v[index].toString()); 
     else if(i == 1) index = vtIndexMap.get(t[index].toString()); 
     else if(i == 2) index = vnIndexMap.get(n[index].toString()); 
     return index; 
    }); 
    var f3 = d[3].split("/").map(function(d, i) { 
     var index = parseInt(d)-1; 
     if(i == 0) index = vIndexMap.get(v[index].toString()); 
     else if(i == 1) index = vtIndexMap.get(t[index].toString()); 
     else if(i == 2) index = vnIndexMap.get(n[index].toString()); 
     return index; 
    }); 
    // 1 
    if(indexMap.has(f1.toString())) { 
     indices.push(indexMap.get(f1.toString())); 
    } else { 
     vertices = vertices.concat(v[f1[0]]).concat(t[f1[1]]).concat(n[f1[2]]); 
     indexMap.set(f1.toString(), nextIndex); 
     indices.push(nextIndex++); 
    } 
    // 2 
    if(indexMap.has(f2.toString())) { 
     indices.push(indexMap.get(f2.toString())); 
    } else { 
     vertices = vertices.concat(v[f2[0]]).concat(t[f2[1]]).concat(n[f2[2]]); 
     indexMap.set(f2.toString(), nextIndex); 
     indices.push(nextIndex++); 
    } 
    // 3 
    if(indexMap.has(f3.toString())) { 
     indices.push(indexMap.get(f3.toString())); 
    } else { 
     vertices = vertices.concat(v[f3[0]]).concat(t[f3[1]]).concat(n[f3[2]]); 
     indexMap.set(f3.toString(), nextIndex); 
     indices.push(nextIndex++); 
    } 
}); 
// 
console.log("Vertices", vertices.toString()); 
console.log("Indices", indices.toString()); 
+0

आप वैसे ही करते हैं जैसा मैं करता हूं। आप जांचते हैं कि चेहरे के लिए डुप्लिकेट है या नहीं। अब मेरी .obj फ़ाइल में कोई डुप्लिकेट चेहरे नहीं हैं। यह मेरी समस्या बिल्कुल है! आपके उदाहरण के लिए मेरा कार्यान्वयन आपके जैसा ही परिणाम देता है। फिर भी यह वास्तविक .obj फ़ाइल के लिए सही नहीं है क्योंकि उनके पास डुप्लिकेट चेहरे नहीं हैं (उन्हें क्यों चाहिए?) – Sorona

+0

@Teolha - शायद आप ऑप्टिमाइज़ेशन विकल्प के साथ अपनी ओबीजे फ़ाइल निर्यात कर रहे हैं। यदि आपके ओबीजे में वी, वीटी या वीएन के लिए कई प्रविष्टियां हैं जिनमें समान सटीक मान होते हैं ~ "v 1 1 0 \ nv 1 1 0" तो यह आपके एल्गोरिदम तक पहुंचने से पहले थोड़ा सा दोषपूर्ण होता है।इसे एल्गोरिदम में मैप v, vt और vn के लिए मानचित्र बनाकर और फिर चेहरे से इंडेक्स को देखकर * first_appearing_indx = map [vert [face_index]] * को आपके सामने चेहरे इंडेक्स को सही करने के लिए सही किया जा सकता है। बफर में जोड़ने के लिए इंडेक्स की खोज करें। –

+0

@Teolha - मैंने एक और संस्करण जोड़ा जो दोहराए गए वर्टेक्स, बनावट और मानदंड मानों को ell के रूप में जोड़ देगा। –

संबंधित मुद्दे