私は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
スクリーンショットは多分ですか? –
キューブに赤色のスクリーンショットを追加し、vertとfragを追加した後、ガラス効果なしでピンクに変わります。 –