Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (578)
games submitted by our members
Games in WIP (499)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Optimizing lighting opengl  (Read 1660 times)
0 Members and 1 Guest are viewing this topic.
Offline obsidian_golem

Senior Newbie




Computer programmer / Google oracle


« Posted 2012-05-20 23:20:24 »

I am trying to figure out how to optimize lighting in opengl 2. I am using 4 lights per object, with the lights sorted by distance. It works well with just one light, but with any more than that It starts to slow down. I would like a way to speed up my lighting while getting similar visual results. Here is my lighting code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
#version 120
uniform vec4 ulight1;
uniform vec4 ulight2;
uniform vec4 ulight3;
uniform vec4 ulight4;

varying vec4 v_color;
varying vec3 v_position;
varying vec3 v_normal;


vec3 ambient = vec3(0.2,0.2,0.2);
vec3 lightcolor = vec3(0.6,0.6,0.6);

vec3 phong() {
   vec3 nn = normalize(v_normal);
   vec3 dtl1 = ulight1.xyz-(v_position);
   vec3 dtl2 = ulight2.xyz-(v_position);
   vec3 dtl3 = ulight3.xyz-(v_position);
   vec3 dtl4 = ulight4.xyz-(v_position);
   float dis1 = length(dtl1);
   float dis2 = length(dtl2);
   float dis3 = length(dtl3);
   float dis4 = length(dtl4);
   float att1 = (1.0 / (1.0 + (dis1 * dis1)));
   float att2 = (1.0 / (1.0 + (dis2 * dis2)));
   float att3 = (1.0 / (1.0 + (dis3 * dis3)));
   float att4 = (1.0 / (1.0 + (dis4 * dis4)));
   float d1 = max(dot(nn,normalize(dtl1)),0.0);
   float d2 = max(dot(nn,normalize(dtl2)),0.0);
   float d3 = max(dot(nn,normalize(dtl3)),0.0);
   float d4 = max(dot(nn,normalize(dtl4)),0.0);
   vec3 lw1 = att1*(ambient+lightcolor*d1)*ulight1.w;
   vec3 lw2 = att2*(ambient+lightcolor*d2)*ulight2.w;
   vec3 lw3 = att3*(ambient+lightcolor*d3)*ulight3.w;
   vec3 lw4 = att4*(ambient+lightcolor*d4)*ulight4.w;
   return lw1+lw2+lw3+lw4;
}


This function is called once per pixel in the fragment shader. The width of each light tells it whether or not that light is enabled.
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #1 - Posted 2012-05-20 23:54:30 »

The obvious optimisation is that for each dtXX vector you call both length() and normalize() on it, which means you're calculating the length twice. You can save four square roots by just dividing by the length you already have.

Also, is that first normalize necessary? Shouldn't your vertex normals already be unit length

You may want to pull out the common 'ambient+lightcolor' into a temporary, but I'd hope the compiler is already doing that optimisation.

Edit: Double-also, you calculate the length(), then do disX*disX to get the length squared. You could just manually calculate that, then sqrt to get the length to save you some computation. That may or may not be an improvement depending on how smart length() is handled under the hood.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline obsidian_golem

Senior Newbie




Computer programmer / Google oracle


« Reply #2 - Posted 2012-05-21 00:04:23 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
#version 120
uniform vec4 ulight[4];

varying vec4 v_color;
varying vec3 v_position;
varying vec3 v_normal;


vec3 ambient = vec3(0.2,0.2,0.2);
vec3 lightcolor = vec3(0.6,0.6,0.6);

vec3 phong() {
   vec3 nn = normalize(v_normal);
        vec3 dtl[4];
        float dis[4];

for(
   vec3 dtl1 = ulight1.xyz-(v_position);
   vec3 dtl2 = ulight2.xyz-(v_position);
   vec3 dtl3 = ulight3.xyz-(v_position);
   vec3 dtl4 = ulight4.xyz-(v_position);
   float dis1 = length(dtl1);
   float dis2 = length(dtl2);
   float dis3 = length(dtl3);
   float dis4 = length(dtl4);
   float att1 = (1.0 / (1.0 + (dis1 * dis1)));
   float att2 = (1.0 / (1.0 + (dis2 * dis2)));
   float att3 = (1.0 / (1.0 + (dis3 * dis3)));
   float att4 = (1.0 / (1.0 + (dis4 * dis4)));
   float d1 = max(dot(nn,normalize(dtl1)),0.0);
   float d2 = max(dot(nn,normalize(dtl2)),0.0);
   float d3 = max(dot(nn,normalize(dtl3)),0.0);
   float d4 = max(dot(nn,normalize(dtl4)),0.0);
   vec3 lw1 = att1*(ambient+lightcolor*d1)*ulight1.w;
   vec3 lw2 = att2*(ambient+lightcolor*d2)*ulight2.w;
   vec3 lw3 = att3*(ambient+lightcolor*d3)*ulight3.w;
   vec3 lw4 = att4*(ambient+lightcolor*d4)*ulight4.w;
   return lw1+lw2+lw3+lw4;
}

Are for loops faster than static code? I thought that static code was fastest in shaders.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Danny02
« Reply #3 - Posted 2012-05-21 00:06:57 »

sry i was not finished^^ will post soon, pressed the published button without wanting too^^
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #4 - Posted 2012-05-21 00:10:33 »

Double-double also: you're going to be completely vector op bound (obviously) while the texture unit sits idle. It may be worth moving some of your computation into a texture lookup. Possibly the light attenuation calculation?

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline obsidian_golem

Senior Newbie




Computer programmer / Google oracle


« Reply #5 - Posted 2012-05-21 00:12:42 »

Double-double also: you're going to be completely vector op bound (obviously) while the texture unit sits idle. It may be worth moving some of your computation into a texture lookup. Possibly the light attenuation calculation?
How would I do this? I am not using textures in my program.
Offline Danny02
« Reply #6 - Posted 2012-05-21 00:15:44 »

So:
- For loops get automatically unrolled by the compiler, if constant loop count and if this constant is not to big
- many loops instead of one big prevents read after write delays.
- only real speed up I did, is getting rid of the sqrt in the length function(there is a distance(p0, p1) function in glsl when you need the distance between two points in a shader next time

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
#version 120
const int LIGHT_COUNT = 4;
uniform vec4 ulight[LIGHT_COUNT];

varying vec4 v_color;
varying vec3 v_position;
varying vec3 v_normal;


vec3 ambient = vec3(0.2,0.2,0.2);
vec3 lightcolor = vec3(0.6,0.6,0.6);

vec3 lambert() {
   vec3 nn = normalize(v_normal);
        vec3 dtl[LIGHT_COUNT];
        float disSquare[LIGHT_COUNT];
        float d[LIGHT_COUNT];
        vec3 lw[LIGHT_COUNT];
       
        for(int i=0; i<LIGHT_COUNT; ++i)
         dtl[i] = ulight[i].xyz-(v_position);

        for(int i=0; i<LIGHT_COUNT; ++i)
         disSquare[i] = dtl[i].x*dtl[i].x + dtl[i].y*dtl[i].y + dtl[i].z*dtl[i].z;

        for(int i=0; i<LIGHT_COUNT; ++i)
         d[i] = max(dot(nn,normalize(dtl[i])),0.0);

        for(int i=0; i<LIGHT_COUNT; ++i)
         lw[i] =(lightcolor*d[i] + ambient)*ulight[i].w / (1.0 + disSquare[i]);

        vec3 result = lw[0];
        for(int i=1; i<LIGHT_COUNT; ++i)
              result += lw[i];

   return result;
}
Offline obsidian_golem

Senior Newbie




Computer programmer / Google oracle


« Reply #7 - Posted 2012-05-21 00:17:41 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
#version 120
const int LIGHT_COUNT = 4;
uniform vec4 ulight[LIGHT_COUNT];

varying vec4 v_color;
varying vec3 v_position;
varying vec3 v_normal;


vec3 ambient = vec3(0.2,0.2,0.2);
vec3 lightcolor = vec3(0.6,0.6,0.6);

vec3 lambert() {
   vec3 nn = normalize(v_normal);
        vec3 dtl[LIGHT_COUNT];
        float disSquare[LIGHT_COUNT];
        float d[LIGHT_COUNT];
        vec3 lw[LIGHT_COUNT];
       
        for(int i=0; i<LIGHT_COUNT; ++i)
         dtl[i] = ulight[i].xyz-(v_position);

        for(int i=0; i<LIGHT_COUNT; ++i)
         disSquare[i] = dtl[i].x*dtl[i].x + dtl[i].y*dtl[i].y + dtl[i].z*dtl[i].z;

        for(int i=0; i<LIGHT_COUNT; ++i)
         d[i] = max(dot(nn,normalize(dtl[i])),0.0);

        for(int i=0; i<LIGHT_COUNT; ++i)
         lw[i] =(lightcolor*d[i] + ambient)*ulight[i].w / (1.0 + disSquare[i]);

        vec3 result = lw[0];
        for(int i=1; i<LIGHT_COUNT; ++i)
              result += lw[i];

   return result;
}

Again, would this be faster than static code?
Offline Danny02
« Reply #8 - Posted 2012-05-21 00:21:06 »

no,
but the code is cleaner and both will compile to the same instructions
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #9 - Posted 2012-05-21 00:28:07 »

How would I do this? I am not using textures in my program.
You would create and load a texture with your falloff ramp in it, then pass it into your shader in the normal way. Then just look-up into it instead of performing your attenuation calculation.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Danny02
« Reply #10 - Posted 2012-05-21 00:29:22 »

get rid of one the normalize
1  
2  
3  
4  
5  
...
        for(int i=0; i<LIGHT_COUNT; ++i)
         d[i] = max(dot(nn, dtl[i] /(sqrt(disSquare[i])),0.0);
...
}


ps:
perhaps you noticed that I changed the name to lambert, because the dot product between the normal and lightdirection is the Lambert Term. Phong describes only how to calculate the specular reflection not the diffuse. Where Blin-Phong should be prefered over standart Phong.
Offline pitbuller
« Reply #11 - Posted 2012-05-21 14:40:04 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
#define LIGHTS_NUM 4
uniform vec4 ulight[LIGHTS_NUM];

varying vec4 v_color;
varying vec3 v_position;
varying vec3 v_normal;


vec3 ambient = vec3(0.2,0.2,0.2);
vec3 lightcolor = vec3(0.6,0.6,0.6);

vec3 lights() {
   
   vec3 light = ambient;
   vec3 nn = normalize(v_normal);  
   for (int i=0;i < LIGHTS_NUM;i++)
   {
         vec3 dtl = ulight[i].xyz - v_position;
         float dis = length(dtl);
         float att = (1.0 / (1.0 + (dis * dis)));
         float d = max(dot(nn, normalize(dtl)),0.0);
         light += (att  * d * ulight[i].w) * lightcolor;
   
   }
   return light;
}

void main(){
      gl_FragColor.rgb = lights();

}


This is best that I got. Its use only 12registers instead of 19 that original needed. Try to profile your bottleneck and optimize it after that.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (28 views)
2014-04-15 18:08:23

BurntPizza (25 views)
2014-04-15 03:46:01

UprightPath (40 views)
2014-04-14 17:39:50

UprightPath (22 views)
2014-04-14 17:35:47

Porlus (38 views)
2014-04-14 15:48:38

tom_mai78101 (62 views)
2014-04-10 04:04:31

BurntPizza (121 views)
2014-04-08 23:06:04

tom_mai78101 (221 views)
2014-04-05 13:34:39

trollwarrior1 (188 views)
2014-04-04 12:06:45

CJLetsGame (195 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!