【问题标题】:Why SceneKit on iOS 8 cannot compile my custom shaders?为什么 iOS 8 上的 SceneKit 无法编译我的自定义着色器?
【发布时间】:2014-10-20 00:02:38
【问题描述】:

我基于 Game 模板创建了一个新项目,其中 SceneKit 作为游戏技术,Swift 作为语言。我尝试使用自定义着色器。这是设置代码:

var material = SCNMaterial()
var program = SCNProgram()

// Read the vertex shader file and set its content as our vertex shader
if let vertexShaderPath = NSBundle.mainBundle().pathForResource("VertexShader", ofType:"vsh") {
    let vertexShaderAsAString = NSString(contentsOfFile: vertexShaderPath, encoding: NSUTF8StringEncoding, error: nil)
    program.vertexShader = vertexShaderAsAString
}

// Read the fragment shader file and set its content as our fragment shader
if let fragmentShaderPath = NSBundle.mainBundle().pathForResource("FragmentShader", ofType:"fsh") {
    let fragmentShaderAsAString = NSString(contentsOfFile: fragmentShaderPath, encoding: NSUTF8StringEncoding, error: nil)
    program.fragmentShader = fragmentShaderAsAString
}

// Give a meaning to variables used in the shaders
program.setSemantic(SCNGeometrySourceSemanticVertex, forSymbol: "a_position", options: nil)
program.setSemantic(SCNModelViewProjectionTransform, forSymbol: "u_viewProjectionTransformMatrix", options: nil)

material.program = program

// retrieve the ship node
let ship = scene.rootNode.childNodeWithName("shipMesh", recursively: true)
ship.geometry.firstMaterial = material

我的顶点着色器代码:

#version 300 es

uniform mat4 u_viewProjectionTransformMatrix;
in vec4 a_position;
out vec4 outPosition;

void main() {
   outPosition = u_viewProjectionTransformMatrix * a_position;
}

以及我的片段着色器的代码:

#version 300 es

out vec4 outColor;

void main() {
    outColor = vec4(1.0, 0.0, 0.0, 1.0)
}

很简单,对吧?但是当我执行这段代码时,我得到了以下错误:

SceneKit: error, failed to link program: ERROR: 0:1: '' :  version '300' is not supported
ERROR: 0:1: '' : syntax error: #version

我做错了什么?供您参考,#version 200 es 产生相同的结果,因此它似乎与 OpenGL 本身的版本无关。

【问题讨论】:

  • 将上下文分配给视图的 eaglContext 属性,为我修复了它(正如 rickster 所建议的那样)。 let scnView = self.view as SCNViewlet context = EAGLContext(API: .OpenGLES3)scnView.eaglContext = context

标签: ios swift opengl-es scenekit fragment-shader


【解决方案1】:

SceneKit 默认使用 OpenGL ES 2.0 上下文。

如果您想使用 ES3 功能(例如 #version 300 es 着色器),您可以创建一个 EAGLContext 对象,指定 OpenGL ES 3.0 作为 API 版本,然后将其分配给您视图的 eaglContext 属性。

但是,并非所有 SceneKit 的渲染器功能都支持 ES3,因此您必须进行试验以查看要渲染的内容是否有效。另外请记住,ES3 需要 A7 GPU——要支持 iPhone 4s/5/5c、iPad 4 和更早版本、iPad mini(非视网膜)和 iPod touch,您需要一个 ES2 渲染路径。

如果您坚持使用 ES2 着色器,您会看到一个错误,因为没有 #version 200 es。 ES2 着色器使用#version 100,或者根本不使用#version 指令(在这种情况下,100 是隐含的)。

【讨论】:

  • 对不起,我应该提到我使用let context = EAGLContext(API: .OpenGLES3)EAGLContext.setCurrentContext(context) 创建了一个上下文。我正在为 iPad Air 编译,所以它确实有一个 A7 GPU。 #version 100 es 给出了同样的错误。如果我删除了#version 指令,片段着色器会出现以下错误:error, failed to link program: ERROR: 0:1: Invalid storage qualifiers 'out' in global variable contextERROR: 0:5: Use of undeclared identifier 'outColor'。以及顶点着色器的类似错误。就好像它不知道 GLSL...
  • #version 100 是合法的 GLSL。 #version 100 es 不是。如果您在 GLSL ES 1.0 中(如果您没有 #version 指令,那么您隐含地是),语言是不同的——inout 是在 GLSL ES 3.0 中引入的。任何像样的 OpenGL ES 2.0 教程都可以告诉你在那里做什么。
  • 另外,您不应该这样做 EAGLContext.setCurrentContext - 将您的自定义上下文分配给您的 SCNVieweaglContext 属性。
猜你喜欢
  • 1970-01-01
  • 2018-03-03
  • 2016-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多