2014-11-02 17 views
7

Próbuję odtworzyć ten kształt obrazu kostki (za zgodą z original creator) przy użyciu zestawu scen.Szerokość obrysu z typem pierwotnym linii SceneKit

enter image description here

dotąd mam kodu do rysowania linii i wierzchołków. Nie mogę użyć obrazu, ponieważ tło musi być przezroczyste.

Specyfiką, którą próbuję rozwiązać, jest teraz edycja szerokości obrysu dla elementu SCNGeometryPrimitiveType.Line.

Podstawowym sposobem tworzę linii jest tak:

private func squareVertices(length: Float) -> [SCNVector3] { 
    let m = length/Float(2) 

    let topLeft =  SCNVector3Make(-m-q, m+q, m+q) 
    let topRight =  SCNVector3Make(m+q, m+q, m+q) 
    let bottomLeft = SCNVector3Make(-m-q, -m-q, m+q) 
    let bottomRight = SCNVector3Make(m+q, -m-q, m+q) 

    return [topLeft, topRight, bottomLeft, bottomRight] 
} 

private func cubeFace() -> SCNGeometry { 

    let vertices : [SCNVector3] = squareVertices(l) 
    let geoSrc = SCNGeometrySource(vertices: UnsafePointer<SCNVector3>(vertices), count: vertices.count) 

    // index buffer 
    let idx1 : [Int32] = [0, 3] 
    let data1 = NSData(bytes: idx1, length: (sizeof(Int32) * idx1.count)) 
    let geoElements1 = SCNGeometryElement(data: data1, primitiveType: SCNGeometryPrimitiveType.Line, primitiveCount: idx1.count, bytesPerIndex: sizeof(Int32)) 

    let idx2 : [Int32] = [1, 2] 
    let data2 = NSData(bytes: idx2, length: (sizeof(Int32) * idx2.count)) 
    let geoElements2 = SCNGeometryElement(data: data2, primitiveType: SCNGeometryPrimitiveType.Line, primitiveCount: idx2.count, bytesPerIndex: sizeof(Int32)) 

    let geo = SCNGeometry(sources: [geoSrc], elements: [geoElements1, geoElements2]) 

    return geo 
} 

    private func setupFaceNodes() { 
    // sides 
    for i in 0..<4 { 
     let face = SCNNode(geometry: cubeFace()) 
     face.rotation = SCNVector4Make(0, 1, 0, Float(i) * Float(M_PI_2)) 
     rootNode.addChildNode(face) 
    } 
    // top/bottom 
    for i in [1, 3] { 
     let face = SCNNode(geometry: cubeFace()) 
     face.rotation = SCNVector4Make(1, 0, 0, Float(i) * Float(M_PI_2)) 
     rootNode.addChildNode(face) 
    } 
} 

mam coś, co wygląda jak ten z prawidłowym ogólnym kształcie:

enter image description here

ale nie mogę zrozumieć jak zwiększyć szerokość rysowanych linii za pomocą SceneKit. Jak mogę to osiągnąć?

Dla zainteresowanych, here to przykładowy proj.

Odpowiedz

8

SceneKit nie przewiduje kontroli dla tego produktu. Jednak SceneKit rysuje przy użyciu OpenGL ES, co robi.

Podczas rysowania z GL w trybie GL_LINES, wywołanie glLineWidth zmienia szerokość linii. (Uwaga: argument jest w rzeczywistych pikselach, a nie w punktach układu interfejsu użytkownika, więc będziesz potrzebować większej szerokości niż myślisz, jeśli nie chcesz super cienkich linii na ekranie Retina.)

, gdzie nazywasz to w swojej aplikacji SceneKit? Masz tam kilka opcji. W prostej scenie podobnej do twojej, gdzie renderujesz tylko jedną rzecz, możesz ją ustawić przed renderowaniem sceny. Ustaw dla widoku widok delegate, a następnie zaimplementuj renderer:willRenderSceneAtTime: i zadzwoń pod numer glLineWidth.

Jednak renderowanie linii OpenGL jest dość ograniczone - jeśli chcesz dostosować renderowanie bardziej, potrzebujesz innego podejścia. Właśnie podejście, które działa najlepiej zależy od dokładnie to, co masz zamiar, więc oto kilka pomysłów dla Ciebie do badań:

  • Sprawdź swoje „linie” z wąskimi paskami trójkąta
  • uczynić je od pierwotnych geometrii SCN jak pudełka i cylindrów
  • zachować prostą geometrię kostki, ale stosowanie cieniującego fragment (lub cieniującego modyfikujący fragment), aby zwrócić uwagę jedynie w pobliżu brzegów każdego wieloboku
+0

„Keep prostą geometrię kostki, ale stosowanie cieniującego fragment (lub fragment kodu modyfikatora shadera), aby rysować tylko w pobliżu krawędzi każdego wielokąta "Jak byś to zrobił robisz to z shaderem fragmentów?Czy problem z rysowaniem szkieletów z modułami cieniującymi nie jest trudniejszy do rozwiązania? [Model szkieletowy] (http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/) – tsp

+0

Może być bardziej skomplikowany, ale pozwala także na większą elastyczność - np. rozmyte/świecące krawędzie. W zależności od potrzeb nie trzeba przesyłać kolejnego atrybutu (źródło geometrii w SceneKit) w dół do potoku dla barycentrycznych współrzędnych - jeśli chcesz podświetlić krawędzie kwadratu, zapomnij, że to w rzeczywistości dwa trójkąty i po prostu spójrz na texcoords. (Zakładając, że twoje texcoords są ustawione tak, by śledzić quad.) – rickster

+0

Próbowałem tego podejścia, dodając wywołanie glLineWidth w metodzie delegata i działa ono na symulatorze, ale nie ma wpływu na urządzenie. Czy widzieliście to samo zachowanie? Dziwne jest to, że jeśli użyję GLES bezpośrednio zamiast SceneKit, mogę zmusić glLineWidth do pracy nad urządzeniem z dość grubymi liniami. – eddy

3

Możesz użyć glLineWidth, aby ustawić szerokość linii.
Pamiętaj, aby dołączyć OpenGLES do projektu.

Line Width 8

Oto jak wygląda twoja kostka ze Szerokość linii ustawiony na 8.

Powiązane problemy