1

I am applying fresnel effect to the SCNSphere to achieve a beautiful glow of the Earth

However, because I am doing model of the Earth, I want that illuminated part of sphere was with fresnel effect and dark side without

enter image description here

Maybe it can be possible to achieve that effect if dark side of sphere will transparent? Or maybe I just can use shader modifier property of Scenekit _surface.fresnel?

Richard
  • 97
  • 8

2 Answers2

0

For this you need to use an emission instance property that defines the color emitted by each point on a surface.

You can use an emissive map texture to simulate parts of a surface that glow with their own light. SceneKit does not treat the material as a light source—rather, the emission property determines colors for a material independent of lighting. (To create an object that appears to glow, you may wish to combine a geometry with an emissive map and additional SCNLight objects added to the scene.)

var emission: SCNMaterialProperty { get }

You can find emission property in any available SceneKit's shader Constant, Lambert, Blinn, Phong or Physically Based.

let earth = SCNNode(geometry: SCNSphere(radius: 5))
earth.geometry?.firstMaterial?.emission.contents = UIImage(named: "emissionMap.png")

enter image description here

And, of course, if you need to create a square emissionMap.png texture (a.k.a. UV Map) you should make it in Autodesk Maya or in Autodesk 3dsMax or in Maxon Cinema4D, etc. Such maps could be 512x512, 1024x1024, 2048x2048, etc.

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
0

I am no expert in Scenekit and shaders and maybe this solution is in no way optimal but one way to do it is to just use shader modifiers :

  1. First, I take the diffuse (=direct, in Scenekit) lighting litting the sphere and convert the red, green and blue values into luminance. Source can be found here.

    vec3 light = _lightingContribution.diffuse;
    float lum = 0.2126*light.r + 0.7152*light.g + 0.0722*light.b;
    
  2. I calculate a number based on the angle of the surface from the pov of the camera. surface entry point

    float factorOpacity = ( _surface.normal.x * _surface.normal.x + _surface.normal.y * _surface.normal.y );
    
  3. I set up a fresnel exponent which controls the thickness of the edge halo. Lower values mean the fresnel effect is more visible around the center and higher values mean that the fresnel effect appears more around the edges.

    float fresnelExponent = 1.0;
    
  4. I set up the red, green and blue values (0.0-1.0) for my atmosphere color.

    float red = 0.1;
    float green = 0.2;
    float blue = 0.4;
    
  5. I set up the Nadir(=looking straight down) transparency that I want. 0.0 means fully transparent and 1.0 means fully opaque.

    float nadirTransparency = 0.2;
    
  6. I set the edge transparency.

    float edgeTransparency = 1.0;
    
  7. I calculate the final fresnel factor taking into account the fresnel exponent.

    factorOpacity = pow(factorOpacity,fresnelExponent);
    
  8. Finally, I compute the final color of the geometry and multiply by the desired transparency depending on the input parameters and the fresnel factors.

    _output.color = vec4(red,green,blue,1.0) * min(lum,1.0) * (nadirTransparency + (edgeTransparency - nadirTransparency) * factorOpacity);
    

The Swift implementation looks like this :

    let sphere = SCNSphere(radius: radiusValue)

    self.geometry = sphere        
    
    let ShaderModifier =

    """
    #pragma transparent

    vec3 light = _lightingContribution.diffuse;

    float lum = 0.2126*light.r + 0.7152*light.g + 0.0722*light.b;
    
    float factorOpacity = ( _surface.normal.x * _surface.normal.x + _surface.normal.y * _surface.normal.y );

    float fresnelExponent = 1.0;

    float red = 0.1;
    float green = 0.2;
    float blue = 0.4;

    float nadirTransparency = 0.2;
    float edgeTransparency = 1.0;

    factorOpacity = pow(factorOpacity,fresnelExponent);

    _output.color = vec4(red,green,blue,1.0) * min(lum,1.0) * (nadirTransparency + (edgeTransparency - nadirTransparency) * factorOpacity);

    """

    self.geometry?.firstMaterial?.shaderModifiers = [.fragment: ShaderModifier]

Here is how it looks (cloud colors are from another shader)

atmosphere shader scenekit

And here is how it looks when setting the nadir transparency to 0, edge transparency to 1, a bright blue color and a high fresnel exponent

amplified fresnel effect