关于opengl es:自定义着色器SCNProgram iOS 9 Scenekit

Custom Shader SCNProgram iOS 9 Scenekit

我想弄乱SceneKit并自学。基本上,我正在创建一个具有3个矩形边和1个倾斜幻灯片的四边形。

我希望我的纹理在整个表面上拉伸和变形/变形。

在线阅读一些内容,看来我需要使用自定义顶点和片段着色器制作一个SCNProgram以获得效果。但是,我似乎无法使纹理散布在整个表面上。请帮忙。 (我是图形编程的新手,因此尝试自学。)

我用来创建几何和纹理的Swift代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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  

}

我的顶点着色器是:

1
2
3
4
5
6
7
8
9
10
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);  
}

我的片段着色器是:

1
2
3
4
5
6
7
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));  
}

我似乎无法使左下角的纹理散布在整个表面上。您能帮忙吗?

This

做一些手动的顶点和碎片着色器,我可以得到结果,但是感觉很不雅致,我很确定它不应该编写像这样的特定代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}

更改为片段着色器(其中0.4是四边形顶部的斜率):

1
2
3
4
5
6
7
8
9
10
11
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);
}

这给了我我想要的东西,但感觉做事方式很错误。

enter

1
2
3
4
5
6
7
8
9
10
11
12
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);
}

我得到类似下面的图片:
enter

1
2
3
4
5
6
7
8
let uvSource = SCNGeometrySource(data: uvData,
            semantic: SCNGeometrySourceSemanticTexcoord,
            vectorCount: textureCord.count,
            floatComponents: true,
            componentsPerVector: 3,
            bytesPerComponent: sizeof(Float),
            dataOffset: 0,
            dataStride: sizeof(vector_float2))

现在,当我在片段着色器中使用texCoord时,它会给我这样的结果:

enter


在片段着色器中,您必须使用texCoord而不是pos来采样纹理。

还要注意,您不需要程序即可对任意几何图形进行纹理处理。您也可以将常规材料用于自定义几何。如果您想做普通材质无法做到的事情,还可以看一下着色器修改器,它们比程序更易于使用,例如,不需要您手动处理灯光。