自定义着色器SCNProgram iOS 9 Scenekit [英] Custom Shader SCNProgram iOS 9 Scenekit
问题描述
我想在 SceneKit
中乱搞并自学它。基本上,我正在创建一个带有3个矩形边和1个倾斜滑块的四边形。
I am trying to mess around in SceneKit
and teach myself it. Basically, I am creating a quad with 3 rectangular sides and 1 sloping slide.
我希望我的纹理在表面上拉伸和变形/变形。
I want my texture on it to stretch and warp/deform across the surface.
在线阅读一些内容,似乎我需要使用自定义顶点和片段着色器制作 SCNProgram
效果。但是,我似乎无法让纹理在表面上传播。需要帮助。 (我是图形编程的新手,因此试图自己教它)。
Reading some stuff online, it seems that I need to make an SCNProgram
with custom vertex and fragment shaders to get the effect. But, I can't seem to get the texture to spread across the surface. Need help please. (I am new to graphics programming hence trying to teach it to myself).
我的Swift代码创建几何和纹理如下:
My Swift code to create the geometry and texture it is as follows:
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));
}
我似乎无法将左下角的纹理展开表面上。你能帮忙吗?
I just can't seem to get the texture at the bottom left spread out across the surface. Could you please help?
做一些手动顶点和碎片着色器杂耍,我可以得到结果,但感觉非常不优雅,我很确定它不应该写这样的特定代码。
Doing some manual vertex and frag shader juggling, I can get the result but it feels very inelegant and I am pretty sure it should not be writing specific code like this.
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是四边形顶部的斜率) ):
Changes to fragment shader (where 0.4 is the slope of the top of the 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);
}
这给了我正是我正在寻找的但是感觉非常错误的方式做事。
Which gives me exactly what I am looking for but it feels very wrong way of doing things.
编辑:我正在使用 pos
变量而不是texCoord,因为 texCoord
给了我奇怪的地狱结果,我无法理解:( 。
I am using the pos
variable instead of texCoord as the texCoord
is giving me weird as hell results which I can't really understand :(.
如果我要将片段着色器修改为:
If I was to modify my fragment shader as:
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);
}
我得到了一些东西如下图所示:
I get something like the pic below:
我告诉我纹理坐标定义有问题但我无法弄清楚是什么?
Which says to me that there is something wrong with my texture coordinates definition but I can't figure out what?
EDIT2:好的进展。根据Lock在相关主题上给出的答案,我使用以下方法重新定义了我的uv:
OK progress. Based on an answer that Lock gave on a related thread I redefined my uvs using the method below:
let uvSource = SCNGeometrySource(data: uvData,
semantic: SCNGeometrySourceSemanticTexcoord,
vectorCount: textureCord.count,
floatComponents: true,
componentsPerVector: 3,
bytesPerComponent: sizeof(Float),
dataOffset: 0,
dataStride: sizeof(vector_float2))
现在它给了我在我的frag shader中使用texCoord时的结果如下:
Now it gives me a result like this when I use texCoord in my frag shader:
它不如我在上面的纹理中得到的弯曲变形那么大。但它的进步。任何想法如何让我在这个Massive问题中像第2张一样平滑?
Its not as great as the curved deformities I get in the texture above. But its progress. Any ideas how can I get it to smooth out like pic 2 in this Massive question?
请帮助。
推荐答案
您必须使用 texCoord
而不是 pos
来对纹理进行采样。
in the fragment shader you have to use texCoord
instead of pos
to sample your texture.
另请注意,您不需要程序来纹理任意几何体。您也可以使用常规材质来定制几何图形。如果你想做一些普通材料无法做到的事情,你也可以看看着色器修改器,它们比程序更容易使用,并且不要求你手动处理灯光。
Also note that you don't need a program to texture an arbitrary geometry. You can use regular material for custom geometries too. If you want to do something that's not possible with a regular material, you can also have a look at shader modifiers, they are easier to use than programs and don't require you to manually handle lights for instance.
这篇关于自定义着色器SCNProgram iOS 9 Scenekit的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!