Custom Shader SCNProgram iOS 9 Scenekit
我想弄乱
我希望我的纹理在整个表面上拉伸和变形/变形。
在线阅读一些内容,看来我需要使用自定义顶点和片段着色器制作一个
我用来创建几何和纹理的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)); } |
我似乎无法使左下角的纹理散布在整个表面上。您能帮忙吗?
做一些手动的顶点和碎片着色器,我可以得到结果,但是感觉很不雅致,我很确定它不应该编写像这样的特定代码。
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); } |
这给了我我想要的东西,但感觉做事方式很错误。
编辑:我使用的是
如果我要将片段着色器修改为:
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); } |
我得到类似下面的图片:
哪个对我说我的纹理坐标定义有问题,但是我不知道是什么?
EDIT2:确定进度。根据Lock在相关线程上给出的答案,我使用以下方法重新定义了uvs:
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时,它会给我这样的结果:
它不如我在上面的纹理中得到的弯曲变形那么大。但是它的进步。有什么想法可以解决这个Massive问题中的图2这样的问题吗?
请帮助。
在片段着色器中,您必须使用
还要注意,您不需要程序即可对任意几何图形进行纹理处理。您也可以将常规材料用于自定义几何。如果您想做普通材质无法做到的事情,还可以看一下着色器修改器,它们比程序更易于使用,例如,不需要您手动处理灯光。