PHP Tutorial: The basics of lighting

alv(55)
Published in
#utopian-io
Words
1025
Reading
5 min
Listen
Play
9y

What Will I Learn?

This tutorial will guide you through the basics of lighting in PHP.

Requirements

PHP http://www.php.net

Difficulty

Intermediate

PHP Tutorial: The basics of lighting

The basic principle of lighting is that the more light you have the brighter an object is. In terms of 3D there are two basic types of lighting: per vertex and per pixel. Per vertex lighting simply means that the light is applied only to the vertex. Say for example that in the previous tutorial the triangle was white. And then we apply a red light to it. With per vertex lighting the value of the light would be calculated only at each vertex and then just like in the previous tutorial, the entire triangle would be colored. With per pixel lighting, the amount and color of the light would be calculated at every pixel in the triangle. Per vertex is an okay approximation used commonly in video games when rendering speed is more important than realism. Per pixel lighting is being used more and more often as graphics hardware and PCs get faster. It’s possible to generate much more realistic scenes.

First lets examine some images of a couple light sources. One has a constant intensity, the other increases in intensity.

You can see that as the light source on the right becomes brighter, the left side also becomes brighter. In these graphics we’re applying a bluish light to a white surface. Now lets take a look at the lights that we will be applying to a more colorful surface.

This is what the lights would look like if we applied them to a white surface. The brighter the color, the closer to the light source the pixel is. Now, let’s take a look at the texture we will be applying these lights to.

The texture looks pretty bland. Now when we apply the two together, we get the final composite image you saw at the top of this tutorial.

The first step to being able to apply lighting is to create a light class. Object orientated programming makes things much easier. Using classes, we’ll be able to contain everything that needs to be known about a light source in a single variable type.

class light
    {
        var $x;
        var $y;
        var $z;
        var $r;
        var $g;
        var $b;
        var $i;
        function light()
        {
            $this->setPos();
            $this->setCol();
            $this->setIntensity();
        }
        function setPos($px=0,$py=0,$pz=0)
        {
            $this->x=$px;
            $this->y=$py;
            $this->z=$pz;
        }
        function setCol($pr=0,$pg=0,$pb=0)
        {
            $this->r=$pr;
            $this->g=$pg;
            $this->b=$pb;
        }
        function setIntensity($pi=0)
        {
            $this->i = $pi;
        }
        function getIntensityAt($x=0,$y=0,$z=0)
        {
            $dist = sqrt(($this->x-$x)*($this->x-$x) +
                    ($this->y-$y)*($this->y-$y) +
                    ($this->z-$z)*($this->z-$z) );
            if($dist>0)
                return $this->i/($this->i+$dist);
            return 1.0;
        }
    }

We're working with a flat surface but the light class is ready to go to be used in three dimensions. The first bit of code simply tells PHP what variables the class will contain. They are prepended with the "var" keyword and are not set to any value. The light function is the constructor which is called whenever the class is instantiated. It in turn calls the three functions that define the light source. No parameters are specified as the functions all have default parameter values. In our case everything is set to zero.

The interesting part of this class is the getIntensityAt function. The first thing we do is find the distance from the light source to the location we pass in. If that distance is less than or equal to the intensity we return 1.0 which is maximum intensity. If the distance is greater than 0 we divide it by the distance added to the intensity and return that instead. The farther away from the light source the less the intensity is. This formula should look familiar. It’s the same one used to determine the perspective multiple based on z and the center of perspective.

Now that we have a class that can do the math to determine the intensity of the light at a point we need to initialize a light source or few.

$lights = array();
    $lights[] = new light();
    $lights[0]->setPos(0,120,-100);
    $lights[0]->setCol(0,0,255);
    $lights[0]->setIntensity(50);

Since we intend to have multiple lights we define our $lights variable to be an array. We then use empty brackets which indicates we’re adding a new object to the end of the array and add a new light. We then reference it by number and define it’s position, color and intensity. We’re not dealing with scale or anything so you’ll just need to play with intensity and see how it looks.

Now that we’ve defined our light class and set up light, it’s time to draw the scene and apply the lights to our generated texture.

function draw()
    {
        global  $screenH, $screenW, $screen,
                $rad, $lights, $debug;
        $r=0;
        $g=0;
        $b=0;
        $m = sizeof($lights);
        for($x=0;$x<$screenW;$x++)
        for($y=0;$y<$screenH;$y++)
        {
            $r=(sin($x*5.0*$rad)+1)*255.0/2.0
                +(cos($y*5.0*$rad)+1)*255.0/2.0;
            $g=(sin($x*5.0*$rad)+1)*255.0/2.0
                +(sin($y*5.0*$rad)+1)*255.0/2.0;
            $b=(cos($x*5.0*$rad)+1)*255.0/2.0
                +(cos($y*5.0*$rad)+1)*255.0/2.0;
            $lr=0;
            $lg=0;
            $lb=0;
            for($j=0;$j<$m;$j++)
            {
                $q = $lights[$j]->getIntensityAt($x,$y,0);
                $lr += $lights[$j]->r*$q;
                $lg += $lights[$j]->g*$q;
                $lb += $lights[$j]->b*$q;
            }
            $r=$lr/255.0*$r;
            $g=$lg/255.0*$g;
            $b=$lb/255.0*$b;
            $screen[$x][$y]=RGB($r,$g,$b);
        }
    }

The initial $r, $g, and $b values generate the original unlit texture. You could set those to anything. $lr, $lg and $lb are the lightmap values at the current pixel. $m stores the number of lights we have and then for every pixel we run through all the lights. The first thing we do is grab the intensity of the light at our current position. We have a flat surface so we just use 0 for the z value. The next thing we do is add the component colors of the current light multiplied by the intensity of the light to the total light values. It’s quite possible that you will end up with a value greater than 255 for any of the component colors.

Now that we have the color of the texture and the color of the light we combine the two. We first divide the component color of the light source by 255 to get a value from 0 to possibly infinity if you were to have that many lights. We then multiply the result by the component color of the texture. And that’s it. We have successfully applied light to a pixel.

So what happens if a component color from the combined light is greater than 255? You may recall that the RGB function caps the r,g, and b values at 255. So in our case if a component color is greater than 255 we render it with the value 255. If you wanted to be clever you could take the run off value and apply it to the other two component values. In that case you would see that as the light becomes overly bright it would start turning the pixel to white regardless of the actual color of the light.

And that concludes this tutorial. You know now the math behind basic lighting. In the next tutorial I'll explain how to apply basic shadows.



Posted on Utopian.io - Rewarding Open Source Contributors

PHP Tutorial: The basics of lighting | Ecency