SceneKit and with GLSL - how to add a shader (GLSL) to geometry

I am learning SceneKit and using GLSL. I find it difficult to understand the use of glsl with SceneKit, for example, how to load glsl shaders into SceneKit and apply it to geometry.

let's say that we have:

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 gllsl example code for glass from the year 2006 , how can this effect be added to the geometry. need to bind these parameters from Glass.vert to SceneKit geometry? Initially, I am trying to achieve a glass effect and a water effect.

The glass effect has 2 files: 1. Glass.vert file

 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); } 

and second file: 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 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); } 

Edit:

I did this to load these shaders into 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]; 

And besides, I initialized them in the shader files:

 //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); 

The box now looks pink with no glass effect. Removing a program from redMaterial, the window appears red, as expected, without a glass effect. therefore, I still cannot achieve the desired effect. any help is much appreciated.

Edit 2:

xcode logs:

 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

+1
source share
1 answer

You see the backup shader. Make sure you create your own renderer with a specifier, preferring OpenGL over Metal. For example, using SCNView:

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

In addition, your shader may cause an error that you do not see. Set the program delegate property to the following:

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

and you will get some debugging information about why the shader does not compile.

+2
source

Source: https://habr.com/ru/post/1011946/


All Articles