簡體   English   中英

用於幾何體入口點的SceneKit着色器修改器可在iOS中使用,但不適用於OS X

[英]SceneKit shader modifier for geometry entry points works in iOS but not OS X

我處於制作SceneKit着色器修改器(用於幾何學入口點)的早期階段,該修改器根據高度圖紋理來置換平面的幾何體。 計划將其用於創建地形。

在iOS中(編輯器:iOS Simulator),着色器可以正常工作,但會在控制台上顯示以下警告:

SceneKit:錯誤,沒有代碼的修飾符無效

在iOS上的外觀

但是,在為OS X構建時,着色器會出現致命錯誤,並且地形幾何圖形僅顯示為粉紅色矩形。

這是幾何着色器修改器:

uniform sampler2D displacementMap;
const float intensity = 7.5;

# pragma body

vec4 displace = texture2D(displacementMap, _geometry.texcoords[0]);

_geometry.position.z += displace.r * intensity;

這就是着色器與幾何體連接的方式。 terrainScene是高度圖,它同時位於漫反射內容和着色器修改器中的自定義displacementMap貼圖采樣器值中:

    //displacement shader

    let mat = SCNMaterial()
    mat.diffuse.contents = terrainScene

    var displacementShader: String?
    guard let path = NSBundle.mainBundle().pathForResource("DisplaceGeometry", ofType: "shader") else {return}

    do {
        displacementShader = try String(contentsOfFile: path,  encoding: NSUTF8StringEncoding)
    } catch {
        return
    }
    mat.shaderModifiers = [SCNShaderModifierEntryPointGeometry: displacementShader!]
    let noiseProperty = SCNMaterialProperty(contents: terrainScene!)
    mat.setValue(noiseProperty, forKey: "displacementMap")

    //geometry
    let plane = SCNPlane(width: 80, height: 80)
    plane.widthSegmentCount = 40
    plane.heightSegmentCount = 40
    plane.materials = [mat]

這是OS X錯誤消息的開頭:

SceneKit: error, modifier without code is invalid
2016-06-11 10:58:32.054 EndlessTerrainOSX[16923:5292387] SceneKit: error, Invalid shader modifier : no code provided
2016-06-11 10:58:32.640 EndlessTerrainOSX[16923:5292387] FATAL ERROR : failed loading compiling shader:

錯誤的結尾:

UserInfo={NSLocalizedDescription=Compilation failed: 
<program source>:343:8: error: global variables must have a constant address space qualifier
float4 displace = displacementMap.sample(displacementMapSampler, _geometry.texcoords[0]);
       ^
<program source>:343:19: error: use of undeclared identifier 'displacementMap'
float4 displace = displacementMap.sample(displacementMapSampler, _geometry.texcoords[0]);
                  ^
<program source>:343:42: error: use of undeclared identifier 'displacementMapSampler'
float4 displace = displacementMap.sample(displacementMapSampler, _geometry.texcoords[0]);
                                         ^
<program source>:344:1: error: unknown type name '_geometry'
_geometry.position.z += displace.r * intensity;
^
<program source>:344:10: error: cannot use dot operator on a type
_geometry.position.z += displace.r * intensity;
         ^
}
2016-06-11 10:58:32.646 EndlessTerrainOSX[16923:5292387] Shaders without a vertex function are not allowed

有誰知道為什么它在iOS上顯示但在OS X上失敗?

我建議這可能不是iOS與OSX的問題,而是與使用OpenGL的另一台設備以及另一台使用Metal的設備有關。

錯誤消息中的代碼是Metal,表明SceneKit已將您的代碼從GLSL轉換為Metal。 以我的經驗,這不可能100%地起作用。 在您的情況下,最簡單的解決方案可能是通過在創建 SCNView 時傳入選項來強制SCNView使用OpenGL。 我相信Interface Builder也為此提供了一個下拉菜單。

如果您希望繼續使用Metal,並且出於某些原因,請繼續閱讀。

當着色器修改器無法編譯着色器的全部內容時,會將其全部轉儲到stdout,這確實有助於調試過程。 如果您向上滾動到第343行,您會發現SceneKit包含了float4 displace = displacementMap.sample(...); Map.sample float4 displace = displacementMap.sample(...); 頂點着色器之前的方法。 在函數外部定義意味着它是一個全局變量,因此需要constant地址空間修飾符,但這根本不是您想要的...在這種情況下,從GLSL到Metal的翻譯沒有按預期工作。

我注意到您缺少#pragma arguments指令,該指令應包含在統一定義上方(請參閱“編寫着色器修改器代碼段” ),這可能會有所幫助。 根據我的經驗,我認為將紋理傳遞到基於金屬的着色器修改器中會很困難。 我嘗試了失敗,然后編寫了SCNProgram來代替它。 建議強制使用OpenGL。

我已經弄清楚了為什么它在Metal中不起作用

以及為什么@lock非常有幫助地指出,即使將float4 displace = displacementMap.sample(...)映射.sample float4 displace = displacementMap.sample(...)放置在頂點着色器外部的全局空間中,即使它位於# pragma body行之下。

這是因為有額外的空間。

它應該是#pragma body (哈希后沒有空格)。

如果刪除該空間,那么它將在metal和GLES中正確編譯。 而且自定義紋理也起作用(我沒有提到的一件事是,該紋理實際上是SpriteKit場景,因為需要動態更改它)。

我不敢相信我已經花了將近24小時盯着這個應該起作用的代碼,這都是因為我寫了# pragma而不是#pragma 感謝@lock發現主體的行實際上是在全局范圍內聲明的。

編輯:

由於此問題的解決方案圍繞SceneKit將我的GLES着色器代碼片段轉換為Metal的能力,因此,我注意到了一些其他內容:

  • 將自定義紋理傳遞到着色器片段中可以很好地轉換為Metal。 我使用的Swift代碼:

     let terrainGenomes = SCNMaterialProperty(contents: "art.scnassets/TerrainGenomes.jpg") mat.setValue(terrainGenomes, forKey: "terrainGenomes") 

(其中mat是SCNMaterial)

  • 使用#pragma arguments會使GLES着色器失敗。 這似乎是可選的,因此我將其刪除。

  • 我無法獲得Metal翻譯來識別自定義全局函數

當我嘗試執行此操作時,Metal轉換總是​​失敗,並且no previous prototype for function ,即使SCNShadable類引用在其示例代碼段中具有自定義全局函數也是如此。 因此,為了保持兼容性,我不得不“放松”代碼段中的功能。 例如,這是一個用於計算法線的表面着色器修改器(點法線看起來不太好,因此我在表面着色器修改器中切換為像素法線)。 這在GLES中有效,但無法轉換為Metal:

uniform sampler2D displacementMap;
uniform float intensity;

vec3 getNewPos(vec2 tc) {
  vec4 displace = texture2D(displacementMap, tc);
  return vec3((tc.x - 0.5) * 80., (tc.y - 0.5) * -80., displace.r * intensity);
}

#pragma body

vec3 newPos = getNewPos(_surface.diffuseTexcoord);
vec3 neighbour1 = getNewPos(_surface.diffuseTexcoord + vec2(0.015, 0.));
vec3 neighbour2 = getNewPos(_surface.diffuseTexcoord + vec2(0., 0.015));

vec4 norm = u_modelViewTransform * vec4(normalize(cross(neighbour2 - newPos, neighbour1 - newPos)), 0.);
_surface.normal = norm.xyz;

在《金屬版》翻譯中,此操作失敗,原因是:

<program source>:344:8: warning: no previous prototype for function 'getNewPos'
float3 getNewPos(float2 tc) {
       ^

這是展開的版本。 刪除該函數會使代碼的DRY和漂亮程度大大降低,但它同時適用於GLES和Metal:

uniform sampler2D displacementMap;

uniform float intensity;

#pragma body

vec4 pixel = texture2D(displacementMap, _surface.diffuseTexcoord);
vec3 newPos = vec3((_surface.diffuseTexcoord.x - 0.5) * 80., (_surface.diffuseTexcoord.y - 0.5) * -80., pixel.r * intensity);
vec2 tc1 = _surface.diffuseTexcoord + vec2(0.015, 0.);
vec2 tc2 = _surface.diffuseTexcoord + vec2(0., 0.015);
vec3 neighbour1 = vec3((tc1.x - 0.5) * 80., (tc1.y - 0.5) * -80., texture2D(displacementMap, tc1).r * intensity);
vec3 neighbour2 = vec3((tc2.x - 0.5) * 80., (tc2.y - 0.5) * -80., texture2D(displacementMap, tc2).r * intensity);

vec4 norm = u_modelViewTransform * vec4(normalize(cross(neighbour2 - newPos, neighbour1 - newPos)), 0.);
_surface.normal = norm.xyz;
  • SceneKit提供的某些制服,例如u_diffuseTexture在着色器片段的Metal轉換中無法訪問

我想,最終,將GLES着色器修改器自動轉換為Metal只會使您受益匪淺,並且要使用自定義着色器修改器正確地進行多目標開發,除了GLES之外,還應提供完整的Metal着色器代碼段一個(並使用預編譯器#if塊在它們之間切換?)。 我非常了解GLSL,但我還沒有全面了解Metal SL的知識。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM