Apr
7
2013

Basic Illumination Model C#

basic_illumination_model_render_diffuse_specular_ambient_1

Converted this script to unity: Basic Illumination Model by andalmeida.

Problems / info:
– Converted most of the values to floats.. because Mathf.Max() didnt like doubles.. i guess could had made some extension to it.. (maybe thats why there are some artifacts)
– Specularity didnt work at first, but there was new code clip in the comments section of that link ^
– Rendering is currently done with invidual setpixel()’s on a plane..(texture size 200×200)

Webplayer:
http://unitycoder.com/upload/demos/BasicIlluminationModelRender/

Source: ()

// Original source : http://www.codeproject.com/Articles/19767/Basic-Illumination-Model-in-C
// converted to Unity: @unitycoder_com

using UnityEngine;
using System.Collections;

public class DiffuseRender : MonoBehaviour {

    
    public Transform shaderObject; // not really needed, just for testing
    private Texture2D tex;
    private bool ambientti = false;
    private bool spec = false;
    private Vector3 mpos;
    
    // Use this for initialization
    void Start () {
        
        // create texture
        tex = new Texture2D(200, 200, TextureFormat.ARGB32, false);
        renderer.material.mainTexture = tex;
        //renderer.material.mainTexture.filterMode = FilterMode.Point;
        
        Page_Load();
    }

    void Update()
    {
        // if properties changed, render again
        if (Input.GetMouseButton(0))
        {
            mpos = Input.mousePosition;
        }
        
        if (Input.GetKeyDown("1"))
        {
            shaderObject.renderer.material.SetColor("_DiffuseColor", new Color(Random.value,Random.value,Random.value,1));
        }
        
        if (Input.GetKeyDown("2"))
        {
            ambientti=!ambientti;
            if (ambientti)
            {
                shaderObject.renderer.material.SetColor("_AmbientColor", new Color(0,0,0,1));
            }else{
                shaderObject.renderer.material.SetColor("_AmbientColor", new Color(0.05f,0.03f,0.01f,1.0f));
            }
        }
        
        if (Input.GetKeyDown("3"))
        {
            spec=!spec;
            if (spec)
            {
                shaderObject.renderer.material.SetFloat("_Shininess", 0.6f);
            }else{
                shaderObject.renderer.material.SetFloat("_Shininess", 0.0f);
            }
        }
        
        Page_Load();
    }
    
    public class tAlgebra
    {
        public tAlgebra()
        {
        }

        public static void Cross3(double ax, double ay, double az,
            double bx, double by, double bz,
            ref double outx, ref double outy, ref double outz)
        {
            outx = ay * bz - az * by;
            outy = az * bx - ax * bz;
            outz = ax * by - ay * bx;
        }

        public static void Reflect(double inx, double iny, double inz,
            double mirrorx, double mirrory, double mirrorz,
            ref double outx, ref double outy, ref double outz)
        {
            double perp1x = 0.0, perp1y = 0.0, perp1z = 0.0;
            double perp2x = 0.0, perp2y = 0.0, perp2z = 0.0;

            Cross3(inx, iny, inz, mirrorx, mirrory, mirrorz,
                ref perp1x, ref perp1y, ref perp1z);
            Normalize(ref perp1x, ref perp1y, ref perp1z);

            Cross3(perp1x, perp1y, perp1z, mirrorx, mirrory, mirrorz,
                ref perp2x, ref perp2y, ref perp2z);
            Normalize(ref perp2x, ref perp2y, ref perp2z);

            double a = mirrorx;
            double b = perp2x;
            double c = inx;

            double x = mirrory;
            double y = perp2y;
            double z = iny;

            double i = mirrorz;
            double j = perp2z;
            double k = inz;

            double n = 0.0, m = 0.0;

            double eps = 1.0E-5;

            if (Mathf.Abs((float)a) < eps)
            {
                if (Mathf.Abs((float)i) < eps)
                {
                    outx = -inx;
                    outy = iny;
                    outz = -inz;
                    return;
                }
                else
                {
                    double dn = (y - (x * j) / i);

                    if (Mathf.Abs((float)dn) < eps)
                    {
                        outx = -inx;
                        outy = iny;
                        outz = -inz;
                        return;
                    }

                    n = (z - (x * k) / i) / dn;
                    m = (k - (j * n)) / i;
                }
            }
            else
            {
                double dn = (y - (x * b) / a);

                if (Mathf.Abs((float)dn) < eps)
                {
                    outx = -inx;
                    outy = iny;
                    outz = -inz;
                    return;
                }

                n = (z - (x * c) / a) / dn;
                m = (c - (b * n)) / a;
            }

            double v1x = mirrorx;
            double v1y = mirrory;
            double v1z = mirrorz;

            double v2x = perp2x;
            double v2y = perp2y;
            double v2z = perp2z;

            v1x *= m;
            v1y *= m;
            v1z *= m;

            v2x *= n;
            v2y *= n;
            v2z *= n;

            outx = v1x - v2x;
            outy = v1y - v2y;
            outz = v1z - v2z;

            return;
        }

        public static double Dot3(double x1, double y1, double z1, double x2, double y2, double z2)
        {
            return ((x1 * x2) + (y1 * y2) + (z1 * z2));
        }

        public static double GetCosAngleV1V2(double v1x, double v1y, double v1z, double v2x, double v2y, double v2z)
        {
            // cos(t) = (v.w) / (|v|.|w|) = (v.w) / 1
            return Dot3(v1x, v1y, v1z, v2x, v2y, v2z);
        }

        public static double modv(double vx, double vy, double vz)
        {
            //return System.Mathf.Sqrt(vx * vx + vy * vy + vz * vz);
            return Mathf.Sqrt((float)(vx * vx + vy * vy + vz * vz));
        }

        public static bool Normalize(ref double vx, ref double vy, ref double vz)
        {
            double mod_v = tAlgebra.modv(vx, vy, vz);
            double eps = 1.0E-20;

            if (Mathf.Abs((float)mod_v) < eps)
                return true;

            vx = vx / mod_v;
            vy = vy / mod_v;
            vz = vz / mod_v;
            return false;
        }

    }
    public class tObject
    {
        public tObject()
        {
        }

        // Final illumination of a point (vertex) = ambient + diffuse + specular

        /*
        Ambient Light Contribution
        Ambient light = background light
        Light that is scattered by the environment
        Frequently assumed to be constant
        Very simple approximation of global illumination
        No direction: independent of light position, object
        orientation, observer’s position or orientation
        */

        // ambient RGBA reflectance of the material default = (0.2, 0.2, 0.2, 1.0)
        public double ambientR, ambientG, ambientB, ambientA;

        /*
        Diffuse Light Calculation
        Need to decide how much light the object point receive
        from the light source – based on Lambert’s Law    
        Lambert’s law: the radiant energy D that a small surface
        patch receives from a light source is:
        D = I x cos (q)
        */
        // diffuse RGBA reflectance of the material default = (0.8, 0.8, 0.8, 1.0)
        public double diffuseR, diffuseG, diffuseB, diffuseA;

        // specular RGBA reflectance of the material default = (0.0, 0.0, 0.0, 1.0)
        // Fresnel factor, which depends on angle of incidence and refractive index
        // of material (which in turn depends on wavelength of light)
        // The overall effect is that the specular reflection does depend on the angle
        // of incidence of the light (it is brighter for grazing angles of incidence),
        // and it does reflect the material colour (more so if the light is nearly
        // normal to surface)
        /*
        Specular light contribution
        The bright spot on the object
        The result of total reflection of
        the incident light in a concentrate
        specular = Ks x I x cos(f)^n
         * */
        public double specularR, specularG, specularB, specularA;

        // RGBA emitted light intensity of the material default = (0.0, 0.0, 0.0, 1.0)
        public double emissionR, emissionG, emissionB, emissionA;

        // specifies the RGBA specular exponent of the material default = 0
        public double shininess;

        /*
        Illumination from each light:  (*sum all)
        Illum = ambient + diffuse + specular
        = Ka x I + Kd x I x ( cos q) + Ks x I x cos(f)^n
         q = angle between light vector and normal to surface
        f is the angle between reflection light and viewer direction
        n = shininess
        */

    }
    public class tSphere : tObject
    {
        public tSphere(double x, double y, double z, double r, double clr, double clg, double clb)
        {
            cx = x;
            cy = y;
            cz = z;
            radius = r;
            clR = clr;
            clG = clg;
            clB = clb;
        }
        public static double GetCoord(double i1, double i2, double w1, double w2, double p)
        {
            return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1;
        }
        void Move(double vx, double vy, double vz)
        {
            cx += vx;
            cy += vy;
            cz += vz;
        }
        void MoveTo(double vx, double vy, double vz)
        {
            cx = vx;
            cy = vy;
            cz = vz;
        }
        void RotX(double angle)
        {
            double y = cy * Mathf.Cos((float)angle) - cz * Mathf.Sin((float)angle);
            double z = cy * Mathf.Sin((float)angle) + cz * Mathf.Cos((float)angle);
            cy = y;
            cz = z;
        }
        void RotY(double angle)
        {
            double x = cx * Mathf.Cos((float)angle) - cz * Mathf.Sin((float)angle);
            double z = cx * Mathf.Sin((float)angle) + cz * Mathf.Cos((float)angle);
            cx = x;
            cz = z;
        }
        public static double GetSphereIntersec(double cx, double cy, double cz, double radius,
                           double px, double py, double pz, double vx, double vy, double vz)
        {
            // x-xo 2 + y-yo 2 + z-zo 2 = r 2
            // x,y,z = p+tv
            // At2 + Bt + C = 0

            double A = (vx * vx + vy * vy + vz * vz);
            double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
            double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy + pz * pz - 2 * pz * cz + cz * cz - radius * radius;
            double D = B * B - 4 * A * C;
            double t = -1.0;
            if (D >= 0)
            {
                double t1 = (-B - Mathf.Sqrt((float)D)) / (2.0 * A);
                double t2 = (-B + Mathf.Sqrt((float)D)) / (2.0 * A);
                if (t1 < t2) t = t1; else t = t2;
            }

            return t;
        }
        public void getNormal(double x1, double y1, double z1, ref double vx1, ref double vy1, ref double vz1)
        {
            vx1 = x1 - cx;
            vy1 = y1 - cy;
            vz1 = z1 - cz;
        }
        public double cx, cy, cz, radius, clR, clG, clB;
    }

//    private void Page_Load(object sender, System.EventArgs e)
    private void Page_Load()
    {
//        Bitmap newBitmap = new Bitmap(200, 200, PixelFormat.Format32bppArgb);
//        Graphics g = Graphics.FromImage(newBitmap);
//        Pen blackPen = new Pen(Color.Black);
//        Color clrBackground = Color.Black;
//        g.FillRectangle(new SolidBrush(clrBackground), new Rectangle(0, 0, 200, 200));
//        Rectangle rect = new Rectangle(0, 0, 200, 200);
        
        
        

        ///////////////////////////////////////
        System.Collections.ArrayList obj3dArrayList;
        obj3dArrayList = new System.Collections.ArrayList();
        //tSphere sph1 = new tSphere(0.01, 0.001, 10, 200.0, 0.0, 0.0, 255.0);
        
        
        Color mDiffuse = shaderObject.renderer.material.GetColor("_DiffuseColor");
        Color mAmbient = shaderObject.renderer.material.GetColor("_AmbientColor");
        Color mSpecular = shaderObject.renderer.material.GetColor("_SpecularColor");
        float mShininess = shaderObject.renderer.material.GetFloat("_Shininess");

        //tSphere sph1 = new tSphere(0.01, 0.001, 10, 200.0, 1.0, 1.0, 1.0);
        tSphere sph1 = new tSphere(0.0, 0.0, 10, 200.0, mDiffuse.r,mDiffuse.g,mDiffuse.b);
        
        //tSphere sph2 = new tSphere(-50, 0.001, 350, 30.0, mDiffuse.r,mDiffuse.g,mDiffuse.b);

        //Debug.Log(mSpecular);
        
/*         // ambient properties for the material   
        sph1.ambientR = 0.329412;
        sph1.ambientG = 0.223529;
        sph1.ambientB = 0.027451;

        // specular properties for the material   
        sph1.specularR = 0.992157;
        sph1.specularG = 0.941176;
        sph1.specularB = 0.807843;
        sph1.shininess = 27.8974;

        sph1.diffuseR = 0.780392;
        sph1.diffuseG = 0.568627;
        sph1.diffuseB = 0.113725;    
         */
        // ambient properties for the material   
        sph1.ambientR = mAmbient.r;
        sph1.ambientG = mAmbient.g;
        sph1.ambientB = mAmbient.b;
        // specular properties for the material   
        sph1.specularR = mSpecular.r;
        sph1.specularG = mSpecular.g;
        sph1.specularB = mSpecular.b;
        sph1.shininess = mShininess;
        
        sph1.diffuseR = mDiffuse.r;
        sph1.diffuseG = mDiffuse.g;
        sph1.diffuseB = mDiffuse.b;
/*
        sph2.ambientR = mAmbient.r;
        sph2.ambientG = mAmbient.g;
        sph2.ambientB = mAmbient.b;
        // specular properties for the material   
        sph2.specularR = mSpecular.r;
        sph2.specularG = mSpecular.g;
        sph2.specularB = mSpecular.b;
        sph2.shininess = mShininess;
        sph2.diffuseR = mDiffuse.r;
        sph2.diffuseG = mDiffuse.g;
        sph2.diffuseB = mDiffuse.b;
*/

        obj3dArrayList.Add(sph1);
       // obj3dArrayList.Add(sph2);
        
        //Graphics graphics = g;

        double px = 0.0;
        double py = 0.0;
        double pz = 600.0;

        // light?
//        double lpx = 200.0;
//        double lpy = 200.0;
//        double lpz = 200.0;
    
        
        // get mousePos
        
        //Vector3 = Camera.main.ViewportToScreenPoint(Input.MousePosition);
        
        double lpx = (mpos.x-Screen.width*0.5f)*2;
        double lpy = (Screen.height-(mpos.y*2))*2; //-Screen.height*0.5f);
        double lpz = 400.0;

        double fMax = 320.0;

        //for (int i = rect.Left; i <= rect.Right; i++)
        for (int i = 0; i <= 200; i++)
        {
            //double x = Sphere.GetCoord(rect.Left, rect.Right, -fMax, fMax, i);
            double x = Sphere.GetCoord(0, 200, -fMax, fMax, i);

            //for (int j = rect.Top; j <= rect.Bottom; j++)
            for (int j = 0; j <= 200; j++)
            {
                //double y = Sphere.GetCoord(rect.Top, rect.Bottom, fMax, -fMax, j);
                double y = Sphere.GetCoord(0,200, fMax, -fMax, j);

                double t = 1.0E10;

                double vx = x - px, vy = y - py, vz = -pz;

                double mod_v = tAlgebra.modv(vx, vy, vz);
                vx = vx / mod_v;
                vy = vy / mod_v;
                vz = vz / mod_v;

                bool bShadow = false;

                tSphere spherehit = null;

                for (int k = 0; k < (int)obj3dArrayList.Count; k++)
                {
                    tSphere sphn = (tSphere)obj3dArrayList[k];
                    double taux = tSphere.GetSphereIntersec(sphn.cx, sphn.cy, sphn.cz, sphn.radius, px, py, pz, vx, vy, vz);
                    if (taux < 0) continue;

                    if (taux > 0 && taux < t)
                    {
                        t = taux;
                        spherehit = sphn;
                    }
                }

                //Color color = Color.FromArgb(0, 0, 0);
                Color color = new Color(0,0,0,1);

                if (spherehit != null)
                {
                    double intersx = px + t * vx,
                           intersy = py + t * vy,
                           intersz = pz + t * vz;

                    double normalX = intersx - spherehit.cx,
                           normalY = intersy - spherehit.cy,
                           normalZ = intersz - spherehit.cz;

                    double lvX = lpx - intersx,
                           lvY = lpy - intersy,
                           lvZ = lpz - intersz;

                    tAlgebra.Normalize(ref normalX, ref normalY, ref normalZ);
                    tAlgebra.Normalize(ref lvX, ref lvY, ref lvZ);

                    double cost = tAlgebra.GetCosAngleV1V2(lvX, lvY, lvZ,
                        normalX, normalY, normalZ);

                    //double cosf = 0;

                    double vReflX = 0, vReflY = 0, vReflZ = 0;
                    
                    double vEye2IntersX = px - intersx, vEye2IntersY = py - intersy, vEye2IntersZ = pz - intersz;

//                    tAlgebra.Reflect(-lvX, -lvY, -lvZ,
//                                     normalX, normalY, normalZ,
//                                     ref vReflX, ref vReflY, ref vReflZ);
                tAlgebra.Reflect(lvX,lvY,lvZ, normalX,normalY,normalZ,ref vReflX,ref vReflY, ref vReflZ);
                
                // specular calculation: based on the angle phi (the angle between viewing direction and reflected ray direction)
double cosf = tAlgebra.GetCosAngleV1V2(vReflX, vReflY, vReflZ,
vEye2IntersX, vEye2IntersY, vEye2IntersZ);

                    tAlgebra.Normalize(ref vReflX, ref vReflY, ref vReflZ);
                    tAlgebra.Normalize(ref vx, ref vy, ref vz);

/*
                    cosf = tAlgebra.GetCosAngleV1V2(vx, vy, vz, vReflX, vReflY, vReflZ);

                    double result1 = Mathf.Max(0.0f, (float)cost) * 255.0;
                    double result2 = Mathf.Pow(Mathf.Max(0, (float)cosf), (float)spherehit.shininess) * 255.0;

                    double rgbR = (spherehit.ambientR * 255.0) + (spherehit.diffuseR * result1) + (spherehit.specularR * result2);
                    double rgbG = (spherehit.ambientG * 255.0) + (spherehit.diffuseG * result1) + (spherehit.specularG * result2);
                    double rgbB = (spherehit.ambientB * 255.0) + (spherehit.diffuseB * result1) + (spherehit.specularB * result2);

                    rgbR = Mathf.Min((float)rgbR, 255);
                    rgbG = Mathf.Min((float)rgbG, 255);
                    rgbB = Mathf.Min((float)rgbB, 255);
                    rgbR = Mathf.Max(0, (float)rgbR);
                    rgbG = Mathf.Max(0, (float)rgbG);
                    rgbB = Mathf.Max(0, (float)rgbB);

                    //color = Color.FromArgb((int)rgbR, (int)rgbG, (int)rgbB);
                    color = new Color((int)rgbR/255, (int)rgbG/255, (int)rgbB/255);*/
                    
                    double result1 = Mathf.Max(0.0f, (float)cost);
                    double result2 = Mathf.Pow(Mathf.Max(0.0f, (float)cosf), (float)spherehit.shininess);

                    double rgbR = (spherehit.ambientR) + (spherehit.diffuseR * result1) + (spherehit.specularR * result2);
                    double rgbG = (spherehit.ambientG) + (spherehit.diffuseG * result1) + (spherehit.specularG * result2);
                    double rgbB = (spherehit.ambientB) + (spherehit.diffuseB * result1) + (spherehit.specularB * result2);

                    rgbR = Mathf.Min((float)rgbR, 1.0f);
                    rgbG = Mathf.Min((float)rgbG, 1.0f);
                    rgbB = Mathf.Min((float)rgbB, 1.0f);
                    rgbR = Mathf.Max(0, (float)rgbR);
                    rgbG = Mathf.Max(0, (float)rgbG);
                    rgbB = Mathf.Max(0, (float)rgbB);

                    //color = Color.FromArgb((int)rgbR, (int)rgbG, (int)rgbB);
                    color = new Color((float)rgbR, (float)rgbG, (float)rgbB, 1.0f);
                    
                }

                tex.SetPixel(i,j,color);
                //Brush brs = new SolidBrush(color);
                //graphics.FillRectangle(brs, i, j, 1, 1);
                //brs.Dispose();

            }// for pixels lines
        }// for pixels columns
        ///////////////////////////////////////
        
        tex.Apply(false);

    }

    
    
}

 

 


1 Comment + Add Comment

Leave a comment

Connect

Twitter View LinkedIn profile Youtube Github Join Discord Twitch Instagram BlueSky

UnityLauncherPro

Get UnityLauncherPRO and work faster with Unity Projects!
*free unity hub alternative

@unitycoder_com

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.