自定义着色器SCNProgram iOS 9 Scenekit

自定义着色器SCNProgram iOS 9 Scenekit,ios,opengl-es,ios9,scenekit,fragment-shader,Ios,Opengl Es,Ios9,Scenekit,Fragment Shader,我试图在SceneKit中混日子,并自学它。基本上,我正在创建一个四边形,有3个矩形边和1个倾斜的幻灯片 我希望它上的纹理在曲面上拉伸和扭曲/变形 在线阅读一些资料,我似乎需要使用自定义顶点和片段着色器制作一个SCNProgram,以获得效果。但是,我似乎无法使纹理在表面上扩散。我需要帮助。(我是图形编程新手,因此尝试自学) 创建几何体和纹理的Swift代码如下: func geometryCreate() -> SCNNode { let verticesPosition

我试图在
SceneKit
中混日子,并自学它。基本上,我正在创建一个四边形,有3个矩形边和1个倾斜的幻灯片

我希望它上的纹理在曲面上拉伸和扭曲/变形

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

创建几何体和纹理的Swift代码如下:

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  

}
我的顶点着色器是:

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);  
}  
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));  
} 
我的片段着色器是:

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);  
}  
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));  
} 
我似乎无法将左下角的纹理分布到整个曲面。你能帮忙吗

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

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是四边形顶部的坡度):

这正是我想要的,但我觉得这样做是非常错误的

编辑:我正在使用
pos
变量而不是texCoord,因为
texCoord
给我的结果非常奇怪,我真的无法理解:(

如果要将片段着色器修改为:

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);
}
我得到了如下图片:

这说明我的纹理坐标定义有问题,但我不知道是什么

EDIT2:好的。根据Lock在相关线程上给出的答案,我使用以下方法重新定义了UV:

let uvSource = SCNGeometrySource(data: uvData,
            semantic: SCNGeometrySourceSemanticTexcoord,
            vectorCount: textureCord.count,
            floatComponents: true,
            componentsPerVector: 3,
            bytesPerComponent: sizeof(Float),
            dataOffset: 0,
            dataStride: sizeof(vector_float2))
现在,当我在frag着色器中使用texCoord时,它会给出如下结果:

它没有我在上面的纹理中得到的弯曲变形那么大。但是它的进展。在这个巨大的问题中,我怎么能让它像图2一样平滑呢


请提供帮助。

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


还要注意的是,你不需要一个程序来对任意几何体进行纹理处理。你也可以对自定义几何体使用常规材质。如果你想做一些常规材质无法做到的事情,你也可以看看着色器修改器,它们比程序更容易使用,例如,不需要你手动处理灯光.

我使用了它,但它给了我奇怪的结果…pos变量似乎工作得更好。texCoord从我最初编写代码时就在那里,但失败了:(仍然坚持这一点:(干得好@AdiTheExplorer。你只需要调整左上角的纹理坐标,而不是0,1,它将是0,0.6(3/5)为了停止变形。FWIW,我不知道你生成纹理坐标的代码有什么问题,但显然有些地方不太对劲。谢谢@lock。但我确实希望它像图2中的一样在这个线程中变形,以得到纹理中的漂亮曲线?它在两个三角形上均匀变形。你知道吗“顺便说一句,我帮了大忙。没有它,我不可能做到:)很公平。在这种情况下,它可能是你想要调整的右上角坐标,将y坐标降低会使它向上拉伸。它可能仍然不会给你图2中所示的变形,这是一个计算纹理坐标的创造性方程式。你可能可以用uv复制它,现在它们是ok(
gl_FragColor=texture2D(你的纹理,vec2(texCoord.x,texCoord.y/(0.4*texCoord.x));
maybe…)。但是,通常你的纹理图像中已经存在变形,允许使用标准着色器。