Adam's Lair Forum

game development and casual madness
It is currently 2017/03/24, 23:59

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: 2017/02/21, 09:54 
Junior Member
Junior Member
User avatar

Joined: 2017/02/09, 19:26
Posts: 38
Role: Hobbyist
Hi, I've been poking around GLSL, making some shaders to solve the seams problem in ComplexBody. So far it's going ok, but I'm having trouble with one fragment shader that's making me crazy.

The shader itself is ok, but It does not cast the light, and I don't know why.
This is where the problem lies (I think):
Code:
   vec4 clrDiffuse = gl_Color;   
   vec4 clrNormal = vec4(.9, .9, .9, .9);
   vec4 clrSpecular = gl_Color;
   vec4 finalColor = vec4(.0, .0, .0, clrDiffuse.a);
   
   vec2 pos = mod(worldSpacePos.xy, vec2(Size)) - vec2(Size / 2);
   float dist_squared = dot(pos, pos);
   
   // Color
   for(int i = 0; i < 36; i++)
   {
      pos = mod((worldSpacePos.xy * i), vec2(Size)) - vec2(Size / 2.0);
      dist_squared = dot(pos, pos);
   
      clrDiffuse *= dist_squared < Size * 6.0 ? vec4(.9, .9, .9, .9) - ((.75 / i) / dist_squared) : vec4(.8, .8, .8, .8);
      clrNormal -= dist_squared / Size;
   }
And this is the full .frag code:
Code:
uniform vec3 CameraPosition;

uniform float Size;
uniform float Brightness;

uniform int _lightCount;
uniform vec4 _lightPos[8];
uniform vec4 _lightDir[8];
uniform vec3 _lightColor[8];

varying vec3 worldSpacePos;
varying mat2 objTransform;

void main()
{
   vec3 eyeDir = normalize(CameraPosition - worldSpacePos);
   
   vec4 clrDiffuse = gl_Color;   
   vec4 clrNormal = vec4(.9, .9, .9, .9);
   vec4 clrSpecular = gl_Color;
   vec4 finalColor = vec4(.0, .0, .0, clrDiffuse.a);
   
   vec2 pos = mod(worldSpacePos.xy, vec2(Size)) - vec2(Size / 2);
   float dist_squared = dot(pos, pos);
   
   // Color
   for(int i = 0; i < 36; i++)
   {
      pos = mod((worldSpacePos.xy * i), vec2(Size)) - vec2(Size / 2.0);
      dist_squared = dot(pos, pos);
   
      clrDiffuse *= dist_squared < Size * 6.0 ? vec4(.9, .9, .9, .9) - ((.75 / i) / dist_squared) : vec4(.8, .8, .8, .8);
      clrNormal -= dist_squared / Size;
   }
   
   // Lighting START (copied from the DynamicLightingSample)
   vec3 normal = normalize(clrNormal.xyz - vec3(.5, .5, .5));
   normal.z = -normal.z;
   
   vec3 lightDir;
   float attenFactor;
   for (int i = 0; i < _lightCount; i++)
   {
      if (_lightPos[i].w > .0)
      {
         // positional light source (pos.w encodes range)
         float dist   = distance(_lightPos[i].xyz, worldSpacePos);
         attenFactor   = 1.0 - min(dist / _lightPos[i].w, 1.0);
         lightDir   = normalize(_lightPos[i].xyz - worldSpacePos);
         
         attenFactor = attenFactor * pow(max(dot(lightDir, -_lightDir[i].xyz), 0.000001), _lightDir[i].w);
      }
      else
      {
         // directional light source   (pos.xyz encodes an ambient term)
         attenFactor   = 1.0;
         lightDir   = -_lightDir[i].xyz;
         
         finalColor.rgb += _lightPos[i].xyz * clrDiffuse.rgb;
      }
      
      // Apply rotation to the light direction to match rotated normal map.
      lightDir.xy = lightDir.xy * objTransform;
      
      // Diffuse lighting
      float diffuseFactor = max(dot(normal, lightDir), 0.0);
      finalColor.rgb += attenFactor * _lightColor[i] * clrDiffuse.rgb * diffuseFactor;
      
      // Specular lighting
      float specularFactor = pow(max(dot(normal, normalize(eyeDir + lightDir)), 0.000001), clrSpecular.a * 64.0);
      finalColor.rgb += _lightColor[i] * clrSpecular.rgb * specularFactor * diffuseFactor * attenFactor;
   }
   
   finalColor.rgb = max(finalColor.rgb, mix(clrDiffuse.rgb, finalColor.rgb, clrNormal.a));   
   // Lighting END
   
   // A final touch to apply the Brightness parameter
   gl_FragColor = vec4(finalColor.rgb * Brightness, gl_Color.a);
}
As you can see, the lighting code is the same as the one in the DynamicLightingSample.
The vertex shader is also the same:
Code:
uniform float CameraFocusDist;
uniform vec3 CameraPosition;

varying vec3 worldSpacePos;
varying mat2 objTransform;

attribute vec4 objTrAttrib;

void main()
{
   gl_Position = ftransform();
   gl_TexCoord[0] = gl_MultiTexCoord0;
   gl_FrontColor = gl_Color;
   
   float camDistScaleInv = gl_Vertex.z / CameraFocusDist;
   worldSpacePos = CameraPosition + vec3(gl_Vertex.xy * camDistScaleInv, gl_Vertex.z);
   
   objTransform = mat2(objTrAttrib.x, objTrAttrib.y, objTrAttrib.z, objTrAttrib.w);
}
Any idea why the light does not work for this shader?
I'm new to GLSL, so maybe I'm missing something obvious.

Thanks!


Top
 Profile  
 
PostPosted: 2017/02/21, 10:04 
Junior Member
Junior Member
User avatar

Joined: 2017/02/09, 19:26
Posts: 38
Role: Hobbyist
This is how it looks.
Gfycat Video - Click to Play. [Source]
As you can see, the light is working fine, but not in the red shape.


Top
 Profile  
 
PostPosted: 2017/02/21, 17:21 
Newbie
Newbie

Joined: 2017/01/15, 18:59
Posts: 4
Location: Germany
Role: Hobbyist
Well quick and easy suggestion:
Are you sure, that the red shape is actually "below" the lightsource? Because your lights don't seem to be omnidirectional.

Also your function to iterate the color 36 times seems to be a bit crazy, or I'm just not getting it. Maybe you could explain it some more.

And don't calculate Matrixes on every vertex. Do it before passing it to the shader. The ModelMatrix should be accessible as a uniform(for every object that is drawn) if you need it. If not you should start a petition to make it available.

Here's a fragment-shader example of directional lighting (3D Blinn-Phong)
It is just a very simple example but it should give you the idea what to do if you are actually trying to create directional lighting. The Shader is for 3D shading, but you should get the idea.

Code:
#version 330

// Holds information about a light
struct Light {
 vec3 position;
 vec3 color;
 float ambientIntensity;
 float diffuseIntensity;

 int type;
 vec3 direction;
 float coneAngle;

 float attenuationConstant;
 float attenuationLinear;
 float attenuationQuadratic;
 float radius;
};

in vec3 v_norm;
in vec3 v_pos;
in vec2 f_texcoord;
out vec4 outputColor;

// Texture information
uniform sampler2D maintexture;
uniform bool hasSpecularMap;
uniform sampler2D map_specular;

uniform mat4 view;

// Material information
uniform vec3 material_ambient;
uniform vec3 material_diffuse;
uniform vec3 material_specular;
uniform float material_specExponent;

// Array of lights used in the shader
uniform Light lights[5];

void
main()
{
 outputColor = vec4(0,0,0,1);
 // Texture information
 vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y);
 vec4 texcolor = texture2D(maintexture, flipped_texcoord.xy);

 vec3 n = normalize(v_norm);
 
 // Loop through lights, adding the lighting from each one
 for(int i = 0; i < 5; i++){

  // Skip lights with no effect
  if(lights[i].color == vec3(0,0,0))
  {
   continue;
  }
 
  vec3 lightvec = normalize(lights[i].position - v_pos);

  // Colors
  vec4 light_ambient = lights[i].ambientIntensity * vec4(lights[i].color, 0.0);
  vec4 light_diffuse = lights[i].diffuseIntensity * vec4(lights[i].color, 0.0);

  // Ambient lighting
  outputColor = outputColor + texcolor * light_ambient * vec4(material_ambient, 0.0);

  // Diffuse lighting
  float lambertmaterial_diffuse = max(dot(n, lightvec), 0.0);

  // Spotlight, limit light to specific angle
  outputColor = outputColor + (light_diffuse * texcolor * vec4(material_diffuse, 0.0)) * lambertmaterial_diffuse;

  // Specular lighting
  vec3 reflectionvec = normalize(reflect(-lightvec, v_norm));
  vec3 viewvec = normalize(vec3(inverse(view) * vec4(0,0,0,1)) - v_pos);
  float material_specularreflection = max(dot(v_norm, lightvec), 0.0) * pow(max(dot(reflectionvec, viewvec), 0.0), material_specExponent);
 
  // Spotlight, specular reflections are also limited by angle
  outputColor = outputColor + vec4(material_specular * lights[i].color, 0.0) * material_specularreflection;
 }

}

Source:http://neokabuto.blogspot.de/


Top
 Profile  
 
PostPosted: 2017/02/21, 18:49 
Junior Member
Junior Member
User avatar

Joined: 2017/02/09, 19:26
Posts: 38
Role: Hobbyist
afraidOfNight wrote:
Are you sure, that the red shape is actually "below" the lightsource?
I'm affraid it is. The light pos is {577.26, -645.06, -10.00} and the shape is at {211.12, -404.64, -1.50}. I've moved it maintaining the Z values just in case ;)

afraidOfNight wrote:
your function to iterate the color 36 times seems to be a bit crazy
I guess it is. I was just doing some tests, trying to understand how shaders work while looking for a way to create procedural textures, when I saw the result and liked it. I can't really explain it yet.

afraidOfNight wrote:
don't calculate Matrixes on every vertex
I see your point. Just found this, so I think the model matrix already exists.

afraidOfNight wrote:
Here's a fragment-shader example of directional lighting (3D Blinn-Phong)
Nice! I'll take a look at it asap.

Thanks!


Top
 Profile  
 
PostPosted: 2017/02/21, 20:20 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 1933
Location: Germany
Role: Professional
Hey! Glad to see you're making progress ^^

YMR wrote:
Hi, I've been poking around GLSL, making some shaders to solve the seams problem in ComplexBody.

I'm pretty sure you don't need shaders to solve this problem, but to fix the texture coordinates you're generating for each vertex. Can you share the source code where you do that, i.e. the renderer that submits them?

Edit: Though I must admit, not 100% sure I'm thinking of the same kind of seams as you do - I think you showed them in the chat once? But just to be sure, can you share a picture on this?

Lighting is a different matter and I think it would be a good idea to fix the seams first and then tackle the lighting separately.

I'm not entirely sure what the first part of the shader is supposed to do - why are you iterating 36 times and what is the purpose of each iteration? You already mentioned that you're not sure about its details yet, but you should definitely make sure the values you are generating are in a reasonable range - if one of them is 100000 or something, it might screw up followup computations.

In general, have you used debug colors to see the values of your various variables per pixel? Just map them onto RGB or greyscale space to take a glance. That's usually pretty helpful to understand what's going on!

As far as the lighting goes, you should be aware that the lighting uniforms that provide the shader with all the data it needs are not set up by default. To initialize them properly, your material needs to use a drawtechnique that is a LightingTechnique, which is defined in the core plugin of the dynamic lighting sample. This will take care of setting the uniform values.

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2017/02/21, 22:53 
Junior Member
Junior Member
User avatar

Joined: 2017/02/09, 19:26
Posts: 38
Role: Hobbyist
Damn! I forgot the LightingTechnique :redface: I was using a DrawTechnique in this one.
Now it works, more or less (it inverts the light effect):
Gfycat Video - Click to Play. [Source]
Adam wrote:
what is the purpose of each iteration
I still don't understand what I'm doing ;) but in the first part I was trying to create a fractal-like texture.

Gfycat Video - Click to Play. [Source]
Adam wrote:
I'm pretty sure you don't need shaders to solve this problem, but to fix the texture coordinates you're generating for each vertex. Can you share the source code where you do that, i.e. the renderer that submits them?
I think you are right, but I couldn't make it work with C#. It could be something really simple (it seems it should be) but sometimes can't view the trees or the forest.
This is the rendering code:
Code:
                // Texture
                if (showTexture)
                {
                    canvas.PushState();
                    canvas.State.SetMaterial(this.material);
                    Rect boundingRect = points.BoundingBox();
                    canvas.State.TextInvariantScale = true;
                    canvas.State.TransformAngle = angle;
                    canvas.State.TransformScale = scale;
                    IEnumerable<ShapeInfo> shapes = rb.Shapes.Where(x => x.GetType() == typeof(PolyShapeInfo));

                    foreach (PolyShapeInfo shape in shapes)
                    {
                        int tShapes = shape.Vertices.Count();
                        Vector2[] vs = new Vector2[tShapes];
                        for (int i = 0; i < tShapes; i++)
                        {
                            vs[i] = new Vector2(shape.Vertices[i].X, shape.Vertices[i].Y);
                        }

                        canvas.FillPolygon(vs, trans.Pos.X, trans.Pos.Y, trans.Pos.Z);
                    }
                    canvas.PopState();
                }


Top
 Profile  
 
PostPosted: 2017/02/22, 18:58 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 1933
Location: Germany
Role: Professional
Ah, yep. Those are the seams that I pictured. ^^ The reason they show up is that you draw each shape separately, and the Canvas generates texture coordinates locally to each shape. I don't have a solution before me right now, but I can point you to Canvas.State.TextureCoordinateRect - that's the property you want to adjust before drawing each polygon so they line up properly.

By default, that rect is always set to [0, 0, 1, 1] which means that the entire used part of the texture will be mapped to the axis aligned bounding rect of the polygon you're drawing. But what you really want in this case is all polygons to align to the same bounding rect that contains all of them, right?

So I'd imagine that you could determine the bounding rect over all polygons before drawing, then determine the relative / local sub-rect that each polygon is representing and then adjusting the texture coordinate rect to match that.

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2017/02/22, 19:25 
Junior Member
Junior Member
User avatar

Joined: 2017/02/09, 19:26
Posts: 38
Role: Hobbyist
Thanks Adam!
I think now I understand how to do it.
Right now I'm trying to understand how Synfig works, and one can't think as a designer and as a programer at the same time if one expect to get it right, but I'll try soon :)


Top
 Profile  
 
PostPosted: 2017/02/23, 06:21 
Junior Member
Junior Member
User avatar

Joined: 2017/02/09, 19:26
Posts: 38
Role: Hobbyist
It worked :D
I just updated the ComplexBody plugin thread and the GitHub code.
Thanks again!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group