[ SHADER SHARING ] - The SKYSHOP CUSTOM SHADERS Thread.

HI EVERYONE .

Iv Been trying to Make SkyShop Based / Powered Custom Shaders .
I referenced myself on the Available Documentation. And its Seams Quite easy …
( DeskTop Only of course )

And here is a Custom Merge of SkyShop SHader With Base Difuse , Specular Over Transparency
This way we can Make Dirt and Oclusion Efects Over SkyShop Base shader.

Here you got the Mixed Shader Code For you To use it :

Please, Use, Improve, And make your own And Share Variants Using Same technique in this Thread.

PS: Would reaaly love to see Marmoset Funcionality in Strumphy Shader Editor …
Would make Building and sharing of custom shaders More easy!

PS.PS: There is not even need to say that you must own Marmoset for this Code to work : )
… as it needs the MarmosetCore.cginc’s For it to work .

Knoledge is power …

Share your Custom Marmoset SHaders With us !

More to come from me…

CHEERS !

KYO

Nice, great work. May I use exr format image or it support full float 32bit images?

Thanks for your Reply.

  • The SHader is just a Mixture of a base Shader Used as layer of the Skyshop: Self illumination Ibl.

You got here the Exerp of the Full code :

Shader "Unity3DLabs/Marmoset/Bumped Specular IBL - 01 - ALPHA BUMP SPEC BLEND" { 
 Properties {
 
 
      _Color ("----------  0º LAYER - 00 - SKYSHOP SELF ILLUMINATED -------------", Range(0,0)) = 0.0
          
 
   _Color   ("Diffuse Color", Color) = (1,1,1,1)
  _SpecColor ("Specular Color", Color) = (1,1,1,1)
  
  _SpecInt ("Specular Intensity", Range(-5.0,5.0)) = 1.0
  _SpecInt (" ", Float) = 1.0
  
  _Shininess ("Specular Sharpness", Range(2.0,8.0)) = 4.0
  _Shininess (" ", Float) = 4.0
  
  _Fresnel ("Fresnel Strength", Range(0.0,1.0)) = 0.0
  _Fresnel (" ", Float) = 0.0
  
  _MainTex ("Diffuse(RGB) Alpha(A)", 2D) = "white" {}
  _SpecTex ("Specular(RGB) Gloss(A)", 2D) = "white" {}
  _BumpMap ("Normalmap", 2D)  = "bump" {}
 
  
  //slots for Emissive lighting   
     _GlowColor ("Glow Color", Color) = (1,1,1,1)
  _GlowStrength("Glow Strength", Float) = 1.0
  _EmissionLM ("Diffuse Emission Strength", Float) = 0.0
  _Illum ("Glow(RGB) Diffuse Emission(A)", 2D) = "white" {}
  
  //slots for custom lighting cubemaps
  _DiffCubeIBL ("Custom Diffuse Cube", Cube) = "black" {}
  _SpecCubeIBL ("Custom Specular Cube", Cube) = "black" {}
  
  
  //slots for custom OVERLAY
  

         _Color1 ("----------  1º LAYER - 01 - BASE DIFUSE SPECULAR -------------", Range(0,0)) = 0.0 
  _Color1 ("Main Color", Color) = (1,1,1,1)
  _SpecColor1 ("Specular Color", Color) = (0.5, 0.5, 0.5, 0)


      _Shininess1 ("Shininess", Range(-0.1,0.1)) = 0.05
     _Shininess1 (" ", Float) = 0.0001
     
  _MainTex1 ("Base (RGB) TransGloss (A)", 2D) = "white" {}
  _BumpMap1 ("Normalmap", 2D) = "bump" {} 
  
 }

 
 SubShader {
  Tags {
   "Queue"="Geometry"
   "RenderType"="Opaque"
  }
  
  LOD 400
  //diffuse LOD 200
  //diffuse-spec LOD 250
  //bumped-diffuse, spec 350
  //bumped-spec 400
  
  //mac stuff
  CGPROGRAM
  #ifdef SHADER_API_OPENGL 
   #pragma glsl
  #endif
    
  #pragma target 3.0
  #pragma surface MarmosetSurf MarmosetDirect
  //gamma-correct sampling permutations
  #pragma multi_compile MARMO_LINEAR MARMO_GAMMA
  
  #define MARMO_HQ
  #define MARMO_SKY_ROTATION
  #define MARMO_DIFFUSE_IBL
  #define MARMO_SPECULAR_IBL
  #define MARMO_DIFFUSE_DIRECT
  #define MARMO_SPECULAR_DIRECT
  #define MARMO_NORMALMAP
  #define MARMO_MIP_GLOSS
  #define MARMO_GLOW
  #define MARMO_PREMULT_ALPHA
  
  #include "MarmosetMobile.cginc"
  #include "MarmosetCore.cginc"
  
  #include "MarmosetInput.cginc"
  #include "MarmosetDirect.cginc"
  #include "MarmosetSurf.cginc"

   ENDCG
  
  
  Blend SrcAlpha OneMinusSrcAlpha

                ZWrite Off
  
  
   
  CGPROGRAM
  #pragma surface surf BlinnPhong alpha
  
  sampler2D _MainTex1;
  sampler2D _BumpMap1;
  fixed4 _Color1;
  half _Shininess1;
  
  struct Input {
   float2 uv_MainTex1;
   float2 uv_BumpMap1;
  };
  
  void surf (Input IN, inout SurfaceOutput o) {
   fixed4 tex = tex2D(_MainTex1, IN.uv_MainTex1);
   o.Albedo = tex.rgb * _Color1.rgb;
   o.Gloss = tex.a;
   o.Alpha = tex.a * _Color1.a;
   o.Specular = _Shininess1;
   o.Normal = UnpackNormal(tex2D(_BumpMap1, IN.uv_BumpMap1));
  }
  ENDCG
  
  
  
  
  
 }
 
 FallBack "Diffuse"
}

Its nothing fancy as you see …

The Real trick is inside the

#include “MarmosetMobile.cginc”
#include “MarmosetCore.cginc”
#include “MarmosetInput.cginc”
#include “MarmosetDirect.cginc”
#include “MarmosetSurf.cginc”

Wich ( If you own Marmoset ) You can Include in Any Shader Those lines within the CGPROGRAM
And it will pull All the SkyShop magic Into the Shader …

Whatever shader you got …

But Things Start to Become A litle More dificult if You Want to make Complete Custom SHaders …

Its not So dificult to do it on Desktop / you just use extra Passes.

Mobile is Quite Complicated other thing …
Even out of my league / not going even to mention here : )


ANYWAY ! As far as i Availed :

    • One of the Big Things that lacks in Skyshop is the “dirt” and “oclusion” and Overlayering.
      • Therefore i just added a secound CgProgram Base Shader as Overlay to the Base Skyshop cgprogram …
        • Its reaaly Extremly Basic stuff, what i did, but using the same technique you can overlay Whatever Custom shader to Skyshop Ones.
  • Therefore is why this Thread Exists.

    • Everyone is invited to do its own Custom Shaders as i did Over Skyshop Shaders Programing And share Around !
      • So we get a Cool SkyShop Shaders Library …
  • We Already Asked Skyshop Developer top Integrate it with Strumphy SHader Editor …

    • But iN Anyway a CUSTOM SKYSHOPS SHADERs Library is very needed around .

Anyway there are somethings i should point.

  • We all can do Custom SHader Programing / OVER SkyShop Shaders .
    • Its Niçe and NEAT and not everyone knows how to do it … Therefore this New Thread Existance And need …

BUT This SHaders Overlays Only Work for SKYSHOP users .

  • They Integrate The Need of a Custom MarmosetCore.cginc / that to Have it you must buy Skyshop .
    • Without Those extra libraries the shader doesnt work / so you must Own Skyshop For this Custom Shaders to work .

IF YOU THINK ABOUT IT !

  • SKYSHOP Usage With IBL Lightning is simply aplying a CUBEMAP To the Shader …

    • The SkyShop Shader trick is ( how the core MarmosetCore.cginc ) Reads That Custom IBL Cubemap Information
      • And outputs into the Surface Shader …
  • SO answering to your Question

    • / If you OWN Skyshop / You can use Exr or Hdr to ( With skyshop ) Convert those to “Proper Cubemaps”…
      • BUT Actualy any Cubemaps Work with SkyShop Shaders …

BUT Basicaly this IBL tricks Dont Even Need / the SkyShop Shader at all ( in Case you Dont Own Skyshop )

CUBEMAP Refletions is Actualy very Easy code :

Shader "Cg shader with reflection map" {
   Properties {
      _Cube("Reflection Map", Cube) = "" {}
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         // User-specified uniforms
         uniform samplerCUBE _Cube;   
 
         // The following built-in uniforms are also
         // defined in "UnityCG.cginc", which could be #included 
         uniform float4 unity_Scale; // w = 1/scale; see _World2Object
         uniform float3 _WorldSpaceCameraPos;
         uniform float4x4 _Object2World; // model matrix
         uniform float4x4 _World2Object; // inverse model matrix 
 
         struct vertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float3 normalDir : TEXCOORD0;
            float3 viewDir : TEXCOORD1;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrix = _Object2World;
            float4x4 modelMatrixInverse = _World2Object; 
               // multiplication with unity_Scale.w is unnecessary 
               // because we normalize transformed vectors
 
            output.viewDir = float3(mul(modelMatrix, input.vertex) 
               - float4(_WorldSpaceCameraPos, 1.0));
            output.normalDir = normalize(float3(
               mul(float4(input.normal, 0.0), modelMatrixInverse)));
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            float3 reflectedDir = 
               reflect(input.viewDir, normalize(input.normalDir));
            return texCUBE(_Cube, reflectedDir);
         }
 
         ENDCG
      }
   }
}

THE DIFICULT STUFF IS TO ADD “IMAGE BASED LIGHTNING”

  • That more than simple “refletion” but cast lightsourçes from the skydome …

SKYSHOP MAKES THINGS EASY/BREEZY and FAST FOR YOU :

  • Getting proper High Quality Enviroment Image Based Light casting …
    • Make Proper Ibl Cubemaps ( a very hard task )
    • Have Proper Shaders that capture the Light Transmitance …

  • But even if you Dont own SKYSHOP / And you are Short on money : You Can ACtualy Code your own IBL Shader …

THE RESULTS WILL NEVER BE AS 10% GOOD as SKYSHOP …

    • But just For example , if you Want to Add Many light Sourçes Refleting over with image-based lighting, in particular diffuse (irradiance) environment mapping and its implementation with cube maps
    • This is Codewise very Simple :

As a Example in the code below :

Shader "Cg shader with image-based diffuse lighting" {
   Properties {
      _OriginalCube ("Environment Map", Cube) = "" {}
      _Cube ("Diffuse Environment Map", Cube) = "" {}
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         // User-specified uniforms
         uniform samplerCUBE _Cube;   
 
         // The following built-in uniform is also 
         // defined in "UnityCG.cginc", which could be #included 
         uniform float4x4 _World2Object; // inverse model matrix 
 
         struct vertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float3 normalDir : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrixInverse = _World2Object; 
               // multiplication with unity_Scale.w is unnecessary 
               // because we normalize transformed vectors
 
            output.normalDir = normalize(float3(
               mul(float4(input.normal, 0.0), modelMatrixInverse)));
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return texCUBE(_Cube, input.normalDir);
         }
 
         ENDCG
      }
   }
}

But you need Aditional COmputation For the Cubemap Generation and Computation of Diffuse Environment Maps
That in c# Script this would be :

using UnityEngine;
using UnityEditor;
using System.Collections;
 
[ExecuteInEditMode]
public class ComputeDiffuseEnvironmentMap : MonoBehaviour
{
    public Cubemap originalCubeMap; 
       // environment map specified in the shader by the user
    //[System.Serializable] 
       // avoid being deleted by the garbage collector, 
       // and thus leaking
    private Cubemap filteredCubeMap; 
       // the computed diffuse irradience environment map 
 
    private void Update()
    {
        Cubemap originalTexture = null;
        try
        {
            originalTexture = renderer.sharedMaterial.GetTexture(
               "_OriginalCube") as Cubemap;
        }
        catch (System.Exception)
        {
            Debug.LogError("'_OriginalCube' not found on shader. " 
            + "Are you using the wrong shader?");
            return;
        }
 
        if (originalTexture == null) 
           // did the user set "none" for the map?
        {
            if (originalCubeMap != null)
            {
                renderer.sharedMaterial.SetTexture("_Cube", null);
                originalCubeMap = null;
                filteredCubeMap = null;
                return;
            }
        }
        else if (originalTexture == originalCubeMap 
            filteredCubeMap != null 
            renderer.sharedMaterial.GetTexture("_Cube") == null)
        {
            renderer.sharedMaterial.SetTexture("_Cube", 
               filteredCubeMap); // set the computed 
               // diffuse environment map in the shader
        }
        else if (originalTexture != originalCubeMap 
           || filteredCubeMap  
           != renderer.sharedMaterial.GetTexture("_Cube")) 
        {
            if (EditorUtility.DisplayDialog(
                "Processing of Environment Map",
                "Do you want to process the cube map of face size " 
                + originalTexture.width + "x" + originalTexture.width 
                + "? (This will take some time.)", 
                "OK", "Cancel"))
            {
                if (filteredCubeMap 
                   != renderer.sharedMaterial.GetTexture("_Cube"))
                {
                    if (renderer.sharedMaterial.GetTexture("_Cube") 
                       != null)
                    {
                        DestroyImmediate(
                           renderer.sharedMaterial.GetTexture(
                           "_Cube")); // clean up
                    }
                }
                if (filteredCubeMap != null)
                {
                    DestroyImmediate(filteredCubeMap); // clean up
                }
                originalCubeMap = originalTexture;
                filteredCubeMap = computeFilteredCubeMap(); 
                   //computes the diffuse environment map
                renderer.sharedMaterial.SetTexture("_Cube", 
                   filteredCubeMap); // set the computed 
                   // diffuse environment map in the shader
                return;
            }
            else
            {
                originalCubeMap = null;
                filteredCubeMap = null;
                renderer.sharedMaterial.SetTexture("_Cube", null);
                renderer.sharedMaterial.SetTexture(
                   "_OriginalCube", null);
            }
        }
    }
 
    // This function computes a diffuse environment map in 
    // "filteredCubemap" of the same dimensions as "originalCubemap"
    // by integrating -- for each texel of "filteredCubemap" -- 
    // the diffuse illumination from all texels of "originalCubemap" 
    // for the surface normal vector corresponding to the direction 
    // of each texel of "filteredCubemap".
    private Cubemap computeFilteredCubeMap()
    {
        Cubemap filteredCubeMap = new Cubemap(originalCubeMap.width, 
           originalCubeMap.format, true);
 
        int filteredSize = filteredCubeMap.width;
        int originalSize = originalCubeMap.width;
 
        // Compute all texels of the diffuse environment cube map 
        // by itterating over all of them
        for (int filteredFace = 0; filteredFace < 6; filteredFace++) 
           // the six sides of the cube
        {
            for (int filteredI = 0; filteredI < filteredSize; filteredI++)
            {
                for (int filteredJ = 0; filteredJ < filteredSize; filteredJ++)
                {
                    Vector3 filteredDirection = 
                       getDirection(filteredFace, 
                       filteredI, filteredJ, filteredSize).normalized;
                    float totalWeight = 0.0f;
                    Vector3 originalDirection;
                    Vector3 originalFaceDirection;
                    float weight;
                    Color filteredColor = new Color(0.0f, 0.0f, 0.0f);
 
                    // sum (i.e. integrate) the diffuse illumination 
                    // by all texels in the original environment map
                    for (int originalFace = 0; originalFace < 6; originalFace++)
                    {
                        originalFaceDirection = getDirection(
                           originalFace, 1, 1, 3).normalized; 
                           //the normal vector of the face
 
                        for (int originalI = 0; originalI < originalSize; originalI++)
                        {
                            for (int originalJ = 0; originalJ < originalSize; originalJ++)
                            {
                                originalDirection = getDirection(
                                   originalFace, originalI, 
                                   originalJ, originalSize); 
                                   // direction to the texel 
                                   // (i.e. light source)
                                weight = 1.0f 
                                   / originalDirection.sqrMagnitude; 
                                   // take smaller size of more 
                                   // distant texels into account
                                originalDirection = 
                                   originalDirection.normalized;
                                weight = weight * Vector3.Dot(
                                   originalFaceDirection, 
                                   originalDirection); 
                                   // take tilt of texel compared 
                                   // to face into account
                                weight = weight * Mathf.Max(0.0f, 
                                   Vector3.Dot(filteredDirection, 
                                   originalDirection)); 
                                   // directional filter 
                                   // for diffuse illumination
                                totalWeight = totalWeight + weight; 
                                   // instead of analytically 
                                   // normalization, we just normalize 
                                   // to the potential max illumination
                                filteredColor = filteredColor + weight 
                                   * originalCubeMap.GetPixel(
                                   (CubemapFace)originalFace, 
                                   originalI, originalJ); // add the 
                                   // illumination by this texel 
                            }
                        }
                    }
                    filteredCubeMap.SetPixel(
                       (CubemapFace)filteredFace, filteredI, 
                       filteredJ, filteredColor / totalWeight); 
                       // store the diffuse illumination of this texel
                }
            }
        }
 
        // Avoid seams between cube faces: average edge texels 
        // to the same color on each side of the seam
        int maxI = filteredCubeMap.width - 1;
        for (int i = 0; i < maxI; i++)
        {
            setFaceAverage(ref filteredCubeMap, 
               0, i, 0, 2, maxI, maxI - i);
            setFaceAverage(ref filteredCubeMap, 
               0, 0, i, 4, maxI, i);
            setFaceAverage(ref filteredCubeMap, 
               0, i, maxI, 3, maxI, i);
            setFaceAverage(ref filteredCubeMap, 
               0, maxI, i, 5, 0, i);
 
            setFaceAverage(ref filteredCubeMap, 
               1, i, 0, 2, 0, i);
            setFaceAverage(ref filteredCubeMap, 
               1, 0, i, 5, maxI, i);
            setFaceAverage(ref filteredCubeMap, 
               1, i, maxI, 3, 0, maxI - i);
            setFaceAverage(ref filteredCubeMap, 
               1, maxI, i, 4, 0, i);
 
            setFaceAverage(ref filteredCubeMap, 
               2, i, 0, 5, maxI - i, 0);
            setFaceAverage(ref filteredCubeMap, 
               2, i, maxI, 4, i, 0);
            setFaceAverage(ref filteredCubeMap, 
               3, i, 0, 4, i, maxI);
            setFaceAverage(ref filteredCubeMap, 
               3, i, maxI, 5, maxI - i, maxI);
        }
 
        // Avoid seams between cube faces: 
        // average corner texels to the same color 
        // on all three faces meeting in one corner
        setCornerAverage(ref filteredCubeMap, 
           0, 0, 0, 2, maxI, maxI, 4, maxI, 0);
        setCornerAverage(ref filteredCubeMap, 
           0, maxI, 0, 2, maxI, 0, 5, 0, 0);
        setCornerAverage(ref filteredCubeMap, 
           0, 0, maxI, 3, maxI, 0, 4, maxI, maxI);
        setCornerAverage(ref filteredCubeMap, 
           0, maxI, maxI, 3, maxI, maxI, 5, 0, maxI);
        setCornerAverage(ref filteredCubeMap, 
           1, 0, 0, 2, 0, 0, 5, maxI, 0);
        setCornerAverage(ref filteredCubeMap, 
           1, maxI, 0, 2, 0, maxI, 4, 0, 0);
        setCornerAverage(ref filteredCubeMap, 
           1, 0, maxI, 3, 0, maxI, 5, maxI, maxI);
        setCornerAverage(ref filteredCubeMap, 
           1, maxI, maxI, 3, 0, 0, 4, 0, maxI);
 
        filteredCubeMap.Apply(); //apply all SetPixel(..) commands
 
        return filteredCubeMap;
    }
 
    private void setFaceAverage(ref Cubemap filteredCubeMap, 
       int a, int b, int c, int d, int e, int f)
    {
        Color average = 
           (filteredCubeMap.GetPixel((CubemapFace)a, b, c) 
           + filteredCubeMap.GetPixel((CubemapFace)d, e, f)) / 2.0f;
        filteredCubeMap.SetPixel((CubemapFace)a, b, c, average);
        filteredCubeMap.SetPixel((CubemapFace)d, e, f, average);
    }
 
    private void setCornerAverage(ref Cubemap filteredCubeMap, 
        int a, int b, int c, int d, int e, int f, int g, int h, int i)
    {
        Color average = 
           (filteredCubeMap.GetPixel((CubemapFace)a, b, c) 
           + filteredCubeMap.GetPixel((CubemapFace)d, e, f) 
           + filteredCubeMap.GetPixel((CubemapFace)g, h, i)) / 3.0f;
        filteredCubeMap.SetPixel((CubemapFace)a, b, c, average);
        filteredCubeMap.SetPixel((CubemapFace)d, e, f, average);
        filteredCubeMap.SetPixel((CubemapFace)g, h, i, average);
    }
 
    private Vector3 getDirection(int face, int i, int j, int size)
    {
        switch (face)
        {
            case 0:
                return new Vector3(0.5f, 
                   -((j + 0.5f) / size - 0.5f), 
                   -((i + 0.5f) / size - 0.5f));
            case 1:
                return new Vector3(-0.5f, 
                   -((j + 0.5f) / size - 0.5f), 
                   ((i + 0.5f) / size - 0.5f));
            case 2:
                return new Vector3(((i + 0.5f) / size - 0.5f), 
                   0.5f, ((j + 0.5f) / size - 0.5f));
            case 3:
                return new Vector3(((i + 0.5f) / size - 0.5f), 
                   -0.5f, -((j + 0.5f) / size - 0.5f));
            case 4:
                return new Vector3(((i + 0.5f) / size - 0.5f),  
                   -((j + 0.5f) / size - 0.5f), 0.5f);
            case 5:
                return new Vector3(-((i + 0.5f) / size - 0.5f), 
                   -((j + 0.5f) / size - 0.5f), -0.5f);
            default:
                return Vector3.zero;
        }
    }
}

ANYWAY ! THAT SAID ! …

Knoledge is power …

Interact WIth this Thread !
And Open Share your Custom Programed IBL SHaders With us !

More to come from me…

As i Would reaaly love to have a Whole Gamut of Custom Shaders Available for everyone To Share and Do variances of it !

ITS A COOL IDEA !

If you are around Join in here : )

The Chalenge here is to Call People Interested in IMAGE BASED LIGHTNING !
To COntribute Custom Shader OPEN Code !

SO we all can use this PHISICAL BASED / IBL SHADERS …

And Have also some / Greath Library of Diferent IBL Shaders to Work with !

Thats the Purpose of this Whole Thread and of the 3DLABS Project as well…

THANKS FOR PASSING !

Cheers

KYO