2015-12-05 7 views
11

Ich versuche in SceneKit herumzualbern und es mir beizubringen. Grundsätzlich erstelle ich ein Quad mit 3 rechteckigen Seiten und 1 Schrägrutsche.Benutzerdefinierte Shader SCNProgram iOS 9 Scenekit

Ich möchte meine Textur auf der Oberfläche dehnen und verformen/verformen.

Ich lese einige Sachen online, es scheint, dass ich einen SCNProgram mit benutzerdefinierten Vertex- und Fragment-Shadern machen muss, um den Effekt zu bekommen. Aber ich kann nicht scheinen, dass sich die Textur über die Oberfläche ausbreitet. Brauche Hilfe bitte. (Ich bin neu in der Grafikprogrammierung und versuche es mir selbst beizubringen).

Mein Swift Code, um die Geometrie und Textur zu erstellen, ist es wie folgt:

func geometryCreate() -> SCNNode { 

    let verticesPosition = [ 
     SCNVector3Make(0.0, 0.0, 0.0), 
     SCNVector3Make(5.0, 0.0, 0.0), 
     SCNVector3Make(5.0, 5.0, 0.0), 
     SCNVector3Make(0.0, 3.0, 0.0) 
    ] 
    let textureCord = [CGPoint (x: 0.0,y: 0.0), CGPoint(x: 1.0,y: 0.0), CGPoint(x: 1.0,y: 1.0), CGPoint(x: 0.0,y: 1.0)] 

    let indices: [CInt] = [ 
    0, 2, 3, 
    0, 1, 2 
    ] 

    let vertexSource = SCNGeometrySource(vertices: verticesPosition, count: 4) 
    let srcTex = SCNGeometrySource(textureCoordinates: textureCord, count: 4) 
    let date = NSData(bytes: indices, length: sizeof(CInt) * indices.count) 

    let scngeometry = SCNGeometryElement(data: date, primitiveType: SCNGeometryPrimitiveType.Triangles, primitiveCount: 2, bytesPerIndex: sizeof(CInt)) 

    let geometry = SCNGeometry(sources: [vertexSource,srcTex], elements: [scngeometry]) 
    let program = SCNProgram() 

    if let filepath = NSBundle.mainBundle().pathForResource("vertexshadertry", ofType: "vert") { 
     do { 
      let contents = try NSString(contentsOfFile: filepath, encoding: NSUTF8StringEncoding) as String 
      program.vertexShader = contents 
     } catch { 
      print("**** happened loading vertex shader") 
     } 
    } 


    if let fragmentShaderPath = NSBundle.mainBundle().pathForResource("fragshadertry", ofType:"frag") 
    { 
     do { 
     let fragmentShaderAsAString = try NSString(contentsOfFile: fragmentShaderPath, encoding: NSUTF8StringEncoding) 
     program.fragmentShader = fragmentShaderAsAString as String 
     } catch { 
      print("**** happened loading frag shader") 
     } 
    } 
    program.setSemantic(SCNGeometrySourceSemanticVertex, forSymbol: "position", options: nil) 
    program.setSemantic(SCNGeometrySourceSemanticTexcoord, forSymbol: "textureCoordinate", options: nil) 
    program.setSemantic(SCNModelViewProjectionTransform, forSymbol: "modelViewProjection", options: nil) 
    do { 
     let texture = try GLKTextureLoader.textureWithCGImage(UIImage(named: "stripes")!.CGImage!, options: nil) 

     geometry.firstMaterial?.handleBindingOfSymbol("yourTexture", usingBlock: { (programId:UInt32, location:UInt32, node:SCNNode!, renderer:SCNRenderer!) -> Void in 
       glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), Float(GL_CLAMP_TO_EDGE)) 
       glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), Float(GL_CLAMP_TO_EDGE)) 
       glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), Float(GL_LINEAR)) 
       glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), Float(GL_LINEAR)) 
       glBindTexture(GLenum(GL_TEXTURE_2D), texture.name) 
     }) 
    } catch { 
     print("Texture not loaded") 
    } 

    geometry.firstMaterial?.program = program 
    let scnnode = SCNNode(geometry: geometry) 
    return scnnode 

} 

Mein Vertex-Shader ist:

attribute vec4 position; 
attribute vec2 textureCoordinate; 
uniform mat4 modelViewProjection; 
varying highp vec2 pos; 
varying vec2 texCoord; 
void main() { 
    texCoord = vec2(textureCoordinate.s, 1.0 - textureCoordinate.t) ; 
    gl_Position = modelViewProjection * position; 
    pos = vec2(position.x, 1.0 - position.y); 
} 

Mein Fragment-Shader ist:

precision highp float; 
uniform sampler2D yourTexture; 
varying highp vec2 texCoord; 
varying highp vec2 pos; 
void main() { 
    gl_FragColor = texture2D(yourTexture, vec2(pos.x, pos.y)); 
} 

I Ich kann einfach nicht scheinen, dass die Textur unten links über die Oberfläche verteilt ist. Kannst du bitte helfen?

This is what is rendered when I run the code

einige manuelle Vertex und Shader-Splitter Jonglieren tun, kann ich das Ergebnis erhalten, aber es fühlt sich sehr unelegant, und ich bin ziemlich sicher, dass es keine spezifischen Code wie folgt schreiben sollte.

attribute vec4 position; 
attribute vec2 textureCoordinate; 
uniform mat4 modelViewProjection; 
varying highp vec2 pos; 

varying vec2 texCoord; 

void main() { 
    // Pass along to the fragment shader 
    texCoord = vec2(textureCoordinate.s, 1.0 - textureCoordinate.t) ; 

    // output the projected position 
    gl_Position = modelViewProjection * position; 
    pos = vec2(position.x, position.y); 
} 

Änderungen an Fragment-Shader (wobei 0,4 die Neigung der Oberseite des Quad):

precision highp float; 
uniform sampler2D yourTexture; 
varying highp vec2 texCoord; 
varying highp vec2 pos; 


void main() { 

    gl_FragColor = texture2D(yourTexture, vec2(pos.x/5.0, 1.0 - pos.y/(3.0+0.4*pos.x))); 
// gl_FragColor = vec4 (0.0, pos.y/5.0, 0.0, 1.0); 
} 

Was mir genau das gibt, was ich suche, aber es fühlt sich sehr falschen Weg, Dinge zu tun .

enter image description here

EDIT: Ich bin mit dem pos Variable statt texCoord als texCoord gibt mir höllisch Ergebnisse seltsam, die ich nicht wirklich verstehen kann :(

Wenn ich zu ändern war meiner. Fragment-Shader als:

precision highp float; 
uniform sampler2D yourTexture; 
varying highp vec2 texCoord; 
varying highp vec2 pos; 

void main() { 

// gl_FragColor = texture2D(yourTexture, vec2(pos.x/5.0, 1.0 - pos.y/(3.0+0.4*pos.x))); 
    gl_FragColor = texture2D(yourTexture, texCoord); 

// gl_FragColor = vec4 (0.0, pos.y/5.0, 0.0, 1.0); 
} 

ich so etwas wie das Bild unten: enter image description here

Was sagt mir, dass etwas mit meiner Definition der Texturkoordinaten nicht stimmt, aber ich kann nicht herausfinden, was?

EDIT2: OK Fortschritt. Basierend auf einer Antwort, die Sperre auf einem verwandten Thread habe ich meine UVS mit der Methode unten neu definiert:

let uvSource = SCNGeometrySource(data: uvData, 
      semantic: SCNGeometrySourceSemanticTexcoord, 
      vectorCount: textureCord.count, 
      floatComponents: true, 
      componentsPerVector: 3, 
      bytesPerComponent: sizeof(Float), 
      dataOffset: 0, 
      dataStride: sizeof(vector_float2)) 

Jetzt gibt es mir ein Ergebnis wie dieses, als ich texCoord in meinem frag Shader verwenden:

enter image description here

Es ist nicht so groß wie die gekrümmten Deformitäten, die ich in der Textur oben bekomme. Aber sein Fortschritt.Irgendwelche Ideen wie kann ich es glattstellen wie Bild 2 in dieser Massive Frage?

Bitte helfen.

+1

Gute Arbeit @AdiTheExplorer. Sie müssen nur die obere linke Texturkoordinate anpassen, statt 0,1 wird es bei 0,0,6 (3/5) sein, um die Verformung zu stoppen. FWIW, ich sehe nicht, was mit dem Code, den Sie zum Erzeugen der Texturkoordinaten hatten, nicht stimmt, aber offensichtlich stimmte etwas nicht damit. – lock

+1

Danke @lock. Aber ich möchte eigentlich, dass es sich wie in Bild 2 in diesem Thread verformt, um eine schöne Kurve in der Textur zu bekommen? Wo es sich gleichmäßig über die 2 Dreiecke verformt. Sie waren übrigens eine große Hilfe. Konnte es ohne es nicht geschafft haben :) – AdiTheExplorer

+1

Fair genug. In diesem Fall ist es wahrscheinlich die obere rechte Koordinate, die Sie optimieren möchten. Wenn Sie diese y-Koordinate verringern, wird sie gestreckt. Es wird wahrscheinlich immer noch nicht die Verformung geben, die Sie in Abbildung 2 sehen, das ist eine kreative Gleichung, die Sie für die Berechnung der Texturkoordinaten haben. Sie können dies wahrscheinlich mit den uvs replizieren, jetzt da sie in Ordnung sind ('gl_FragColor = texture2D (IhreTextur, vec2 (texCoord.x, texCoord.y/(0.4 * texCoord.x)));' vielleicht ...). ABER, im Allgemeinen hat Ihr Texturbild bereits die Deformation, die die Verwendung von Standard-Shadern ermöglicht. – lock

Antwort

7

im Fragment-Shader müssen Sie texCoord anstelle von pos verwenden, um Ihre Textur zu testen.

Beachten Sie auch, dass Sie kein Programm benötigen, um eine beliebige Geometrie zu texturieren. Sie können auch normales Material für benutzerdefinierte Geometrien verwenden. Wenn Sie etwas tun möchten, das mit einem normalen Material nicht möglich ist, können Sie sich auch Shader-Modifikatoren ansehen, die einfacher zu verwenden sind als Programme und es nicht erforderlich machen, dass Sie beispielsweise manuell mit Lichtern umgehen.

+1

Ich habe das benutzt, aber es gibt mir seltsame Ergebnisse ... die Pos-Variable scheint besser zu funktionieren. Das texCoord ist da, als ich anfänglich den Code geschrieben habe und gescheitert ist :( – AdiTheExplorer

+2

Bin immer noch dabei :( – AdiTheExplorer