2016-11-19 7 views
1

私はSceneKitを学び、GLSLを使っています。私はSceneKitでglslを使って理解するのが苦労しています。例えば、SceneKitでglslシェーダーを読み込んでジオメトリに適用する方法です。SceneKitとGLSL - ジオメトリにシェーダ(GLSL)を追加する方法

SCNBox *box = [SCNBox boxWithWidth:50 height:50 length:50 chamferRadius:0]; 
SCNNode *bNode = [SCNNode nodeWithGeometry:box]; 

SCNMaterial *redMaterial    = [SCNMaterial material]; 
redMaterial.diffuse.contents   = [UIColor redColor]; 
redMaterial.locksAmbientWithDiffuse  = YES; 
box.materials = @[redMaterial]; 

[scene.rootNode addChildNode:bNode]; 

using the glass glsl example codes by apple from year 2006 1は、ジオメトリにこの効果を追加する方法:

は、私たちが持って言うことができます。 Glass.vertからSceneKitのジオメトリにそれらのパラメータをバインドする必要がありますか?もともと、私はガラス効果と水効果を達成しようとしています。

ガラス効果は2つのファイルがあります。 1.ファイルGlass.vert

varying vec3 Normal; 
varying vec3 EyeDir; 
varying vec4 EyePos; 
varying float LightIntensity; 

uniform vec3 LightPos; 

void main(void) 
{ 
    gl_Position = ftransform(); 
    Normal   = normalize(gl_NormalMatrix * gl_Normal); 
    vec4 pos  = gl_ModelViewMatrix * gl_Vertex; 
    EyeDir   = pos.xyz; 
    EyePos   = gl_ModelViewProjectionMatrix * gl_Vertex; 
    LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0); 
} 

と第二のファイル:Glass.frag

const vec3 Xunitvec = vec3 (1.0, 0.0, 0.0); 
const vec3 Yunitvec = vec3 (0.0, 1.0, 0.0); 

uniform vec3 BaseColor; 
uniform float Depth; 
uniform float MixRatio; 

// need to scale our framebuffer - it has a fixed width/height of 2048 
uniform float FrameWidth; 
uniform float FrameHeight; 
uniform float textureWidth; 
uniform float textureHeight; 

uniform sampler2D EnvMap; 
uniform sampler2D RefractionMap; 

varying vec3 Normal; 
varying vec3 EyeDir; 
varying vec4 EyePos; 
varying float LightIntensity; 

void main (void) 
{ 
    // Compute reflection vector 
    vec3 reflectDir = reflect(EyeDir, Normal); 

    // Compute altitude and azimuth angles 

    vec2 index; 

    index.y = dot(normalize(reflectDir), Yunitvec); 
    reflectDir.y = 0.0; 
    index.x = dot(normalize(reflectDir), Xunitvec) * 0.5; 

    // Translate index values into proper range 

    if (reflectDir.z >= 0.0) 
     index = (index + 1.0) * 0.5; 
    else 
    { 
     index.t = (index.t + 1.0) * 0.5; 
     index.s = (-index.s) * 0.5 + 1.0; 
    } 

    // if reflectDir.z >= 0.0, s will go from 0.25 to 0.75 
    // if reflectDir.z < 0.0, s will go from 0.75 to 1.25, and 
    // that's OK, because we've set the texture to wrap. 

    // Do a lookup into the environment map. 

    vec3 envColor = vec3 (texture2D(EnvMap, index)); 

    // calc fresnels term. This allows a view dependant blend of reflection/refraction 
    float fresnel = abs(dot(normalize(EyeDir), Normal)); 
    fresnel *= MixRatio; 
    fresnel = clamp(fresnel, 0.1, 0.9); 

    // calc refraction 
    vec3 refractionDir = normalize(EyeDir) - normalize(Normal); 

    // Scale the refraction so the z element is equal to depth 
    float depthVal = Depth/-refractionDir.z; 

    // perform the div by w 
    float recipW = 1.0/EyePos.w; 
    vec2 eye = EyePos.xy * vec2(recipW); 

    // calc the refraction lookup 
    index.s = (eye.x + refractionDir.x * depthVal); 
    index.t = (eye.y + refractionDir.y * depthVal); 

    // scale and shift so we're in the range 0-1 
    index.s = index.s/2.0 + 0.5; 
    index.t = index.t/2.0 + 0.5; 

    // as we're looking at the framebuffer, we want it clamping at the edge of the rendered scene, not the edge of the texture, 
    // so we clamp before scaling to fit 
    float recipTextureWidth = 1.0/textureWidth; 
    float recipTextureHeight = 1.0/textureHeight; 
    index.s = clamp(index.s, 0.0, 1.0 - recipTextureWidth); 
    index.t = clamp(index.t, 0.0, 1.0 - recipTextureHeight); 

    // scale the texture so we just see the rendered framebuffer 
    index.s = index.s * FrameWidth * recipTextureWidth; 
    index.t = index.t * FrameHeight * recipTextureHeight; 

    vec3 RefractionColor = vec3 (texture2D(RefractionMap, index)); 

    // Add lighting to base color and mix 
    vec3 base = LightIntensity * BaseColor; 
    envColor = mix(envColor, RefractionColor, fresnel); 
    envColor = mix(envColor, base, 0.2); 

    gl_FragColor = vec4 (envColor, 1.0); 
} 

編集:

私はそれを作ったしSceneKitでそれらのシェーダをロードするポイントまで:

NSURL *vertexShaderURL = [[NSBundle mainBundle] URLForResource:@"Glass" withExtension:@"vert"]; 
NSURL *fragmentShaderURL = [[NSBundle mainBundle] URLForResource:@"Glass" withExtension:@"frag"]; 
NSString *vertexShader = [[NSString alloc] initWithContentsOfURL:vertexShaderURL 
                 encoding:NSUTF8StringEncoding 
                  error:NULL]; 
NSString *fragmentShader = [[NSString alloc] initWithContentsOfURL:fragmentShaderURL 
                  encoding:NSUTF8StringEncoding 
                  error:NULL]; 
SCNProgram *program = [SCNProgram program]; 
program.delegate = self; 
program.vertexShader = vertexShader; 
program.fragmentShader = fragmentShader; 

SCNMaterial *redMaterial    = [SCNMaterial material]; 
redMaterial.diffuse.contents   = [UIColor redColor]; 
redMaterial.locksAmbientWithDiffuse  = YES; 

redMaterial.program = program; 
box.materials = @[redMaterial]; 

そしてさらに、私は、シェーダファイルでこれらを初期化しました:

//frag file 
BaseColor = vec3 (0.4, 0.4, 1.0) 
Depth = 0.1; 
MixRatio = 1; 
EnvMap = 0; 
RefractionMap = 1; 
//vert file 
LightPos = vec3 (0.0, 140.0, 0.0); 

ボックスは現在、ガラス効果なしピンク表示されます。 redMaterialからプログラムを削除すると、ボックスはガラス効果なしで期待どおりに赤く表示されます。私はまだ希望の効果を達成することができません。どんな助けでも大歓迎です。

編集2:

Xcodeのログ:

2016-11-21 08:08:26.758244 testGame[7837:3366037] [DYMTLInitPlatform] platform initialization successful 
2016-11-21 08:08:27.196142 testGame[7837:3365880] Metal GPU Frame Capture Enabled 
2016-11-21 08:08:27.196975 testGame[7837:3365880] Metal API Validation Enabled 

results on iPhone 6

+0

スクリーンショットは多分ですか? –

+0

キューブに赤色のスクリーンショットを追加し、vertとfragを追加した後、ガラス効果なしでピンクに変わります。 –

答えて

2

あなたはフォールバックシェーダを見ています。メタルではなくOpenGLを好む指定子でレンダラーを作成していることを確認してください。たとえば、SCNViewで:

_sceneView = [[SCNView alloc] initWithFrame:[UIScreen mainScreen].bounds 
            options:@{ SCNPreferredRenderingAPIKey: @(SCNRenderingAPIOpenGLES2) }]; 

また、シェーダーが表示されないというエラーが発生している可能性があります。これを実装して何かにプログラムのdelegateプロパティを設定します。

- (void)program:(SCNProgram *)program handleError:(NSError *)error 
{ 
    NSLog(@"SCNProgram error %@", error); 
} 

、あなたはシェーダがコンパイルされていない理由について、いくつかのデバッグ情報を取得します。

関連する問題