I'm writing a small libGdx application that may be able to distort a face simulating hits (something similar to FaceSmash), but can't find what kind of filter should I apply, neither info about math algorithms to achieve something like a bulge effect.
I've started from SphereFilter on
http://www.jhlabs.com/
but definitely the effect is not what I'm looking for.
I'm aware of
Image Warping - Bulge Effect Algorithm
and
How to warp images in Android?
I've achieved to 'translate' the bulge effect mentioned on the first thread, but is relatively slow, and can't find the way to create bulges in a region, not the whole image.
The warp sample on Api demos (2nd thread) is really fast, and changes only part of the image, but is not exactly a bulge effect, and my image processing maths are far from understanding how could I modify the algorithm to change the effect.
I can feel I'm in the right direction, but I'm totally stuck. Any idea of how any of these algorithms could be modified in order to get 'local' bulges inside the image?
EDIT
Just found this thread.-
How can you apply distortions to a UIImage using OpenGL ES?
Not android, but looks promising. I'll give a try to OpenGL shaders and share (hopefully) a solution for my scenario.
Answering my own question, I managed to find a solution using OpenGL shaders based on GPUImage framework
The resulting fragment shader looks like this.-
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float aspectRatio;
uniform vec2 center;
uniform float radius;
uniform float scale;
void main()
{
vec2 textureCoordinateToUse = vec2(v_texCoords.x, (v_texCoords.y * aspectRatio + center.y - center.y * aspectRatio));
float dist = distance(center, textureCoordinateToUse);
textureCoordinateToUse = v_texCoords;
if (dist < radius)
{
textureCoordinateToUse -= center;
float percent = 1.0 - ((radius - dist) / radius) * scale;
percent = percent * percent;
textureCoordinateToUse = textureCoordinateToUse * percent;
textureCoordinateToUse += center;
}
gl_FragColor = texture2D(u_texture, textureCoordinateToUse);
}
Hope someone find it helpful.
Related
I've got a question about some code that I found on the internet without further explanation.
It is about the calculation for normal mapping.
On my vertex shader, I got a uniform variable (vec3) of the light position. But the position of the light got premultiplied with the view matrix. So the light position is accessed relative to the camera.
The Java code looks like this: (note that I work with multiple lights, this has no influence on the calculation itself; super.loadVector() uploads a uniform vector).
public void loadLights(List<Light> lights, Matrix4f viewMatrix){
super.loadFloat(this.location_lightAmount, Math.min(RenderSettings.ENTITIES_MAX_LIGHTS,lights.size()));
for(int i=0;i<RenderSettings.ENTITIES_MAX_LIGHTS;i++){
if(i<lights.size()){
super.loadVector(location_lightPositionEyeSpace[i], getEyeSpacePosition(lights.get(i), viewMatrix));
super.loadVector(location_lightColor[i], lights.get(i).getColor());
super.loadVector(location_lightAttenuation[i], lights.get(i).getAttenuation());
}
}
}
public static Vector3f getEyeSpacePosition(Light light, Matrix4f viewMatrix){
Vector3f position = light.getAbsolutePosition();
Vector4f eyeSpacePos = new Vector4f(position.x,position.y, position.z, 1f);
Matrix4f.transform(viewMatrix, eyeSpacePos, eyeSpacePos);
return new Vector3f(eyeSpacePos);
}
This makes no sense to me because the camera position should have no influence on the calculation of the normals, right?
The next thing is following: When I render without normal mapping I transform the normal of each vertex by using the transformation matrix like this:
in vec3 normal;
out vec3 surfaceNormal;
uniform mat4 transformationMatrix;
void(main) {
//........
surfaceNormal = (transformationMatrix * vec4(normal,0.0)).xyz;
//........
}
However, this calculation is not applied in the normal mapping code that I found. Here, the normal (and the tangent) is multiplied with the viewMatrix and transformationMatrix like this:
mat4 modelViewMatrix = viewMatrix * transformationMatrix;
vec3 surfaceNormal = (modelViewMatrix * vec4(normal,0.0)).xyz;
The bitangent can be easily calculated with the surfaceNormal and the surfaceTangent calculated. The tangentSpaceMatrix is then used for transforming the light position. But why is the view matrix used for all the transformations?
The way that I understood normal mapping is the following: transform the whole system, so that the triangle (that is being rendered) lies flat on the ground (tangent space). Then the normal equals the RGB-value of the normal map.
(I know that this might sound a little bit confusing, I hope you understand what I mean).
Greetings, Finn
I've been wondering how to efficiently implement the following image scale procedure in Java or Processing. When scaling out, the bounds of the image wrap around the screen edges.I'd like to apply the same at runtime to my Pixels() array in Processing. (to keep this Processing agnostic - Pixels() is nothing else than a method that returns all pixels on my current screen in an array).
(Note that this example was made in MaxMsp/Jitter using the jit.rota module, which appears to use a very efficient implementation).
unscaled
zoomed out
Can anyone help me out on how to get started? I assume it must be a combination of downscaling the image and creating adjactent copies of it - but this doesn't sound very efficient to me. the above example works perfectly on videos with even the most extreme settings.
One option I can think that will be fast is using a basic fragment shader.
Luckily you've got an example pretty close to what you need that ships with Processing via File > Examples > Topics > Shaders > Infinite Tiles
I won't be able to efficiently provide a decent start to finish guide, but
there's an exhaustive PShader tutorial on the Processing website if you're starting the from scratch.
A really rough gist of what you need:
shaders are programs that run really fast and parallelised on the GPU, split into two: vertex shaders (deal with 3d geometry mainly), fragment shaders (deal with "fragments"(what's about to become pixels on screen) mainly). You'll want to play with a fragment shader
The language is called GLSL and is a bit different(fewer types, stricter, simpler syntax), but not totally alien(similar C type of declaring variables, functions, conditions, loops, etc.)
if you want to make a variable from a GLSL program accessible in Processing you prefix it with the keyword uniform
use textureWrap(REPEAT) to wrap edges
to scale the image and wrap it you'll need to scale the texture sampling coordinates:
Here's what the InfiniteTiles scroller shader looks like:
//---------------------------------------------------------
// Display endless moving background using a tile texture.
// Contributed by martiSteiger
//---------------------------------------------------------
uniform float time;
uniform vec2 resolution;
uniform sampler2D tileImage;
#define TILES_COUNT_X 4.0
void main() {
vec2 pos = gl_FragCoord.xy - vec2(4.0 * time);
vec2 p = (resolution - TILES_COUNT_X * pos) / resolution.x;
vec3 col = texture2D (tileImage, p).xyz;
gl_FragColor = vec4 (col, 1.0);
}
You can simplify this a bit as you don't need to scrolling. Additionally, instead of subtracting, and multiplying(- TILES_COUNT_X * pos), you can simply multiply:
//---------------------------------------------------------
// Display endless moving background using a tile texture.
// Contributed by martiSteiger
//---------------------------------------------------------
uniform float scale;
uniform vec2 resolution;
uniform sampler2D tileImage;
void main() {
vec2 pos = gl_FragCoord.xy * vec2(scale);
vec2 p = (resolution - pos) / resolution.x;
vec3 col = texture2D (tileImage, p).xyz;
gl_FragColor = vec4 (col, 1.0);
}
Notice I've repurposed the time variable to become scale, therefore the Processing code accessing this uniform variable must also change:
//-------------------------------------------------------------
// Display endless moving background using a tile texture.
// Contributed by martiSteiger
//-------------------------------------------------------------
PImage tileTexture;
PShader tileShader;
void setup() {
size(640, 480, P2D);
textureWrap(REPEAT);
tileTexture = loadImage("penrose.jpg");
loadTileShader();
}
void loadTileShader() {
tileShader = loadShader("scroller.glsl");
tileShader.set("resolution", float(width), float(height));
tileShader.set("tileImage", tileTexture);
}
void draw() {
tileShader.set("scale", map(mouseX,0,width,-3.0,3.0));
shader(tileShader);
rect(0, 0, width, height);
}
Move the mouse to change scale:
Update You can play with a very similar shader here:
I effectively did come up with a solution - but will implement George's method next as the speed difference using shaders seems to be worth it!
public void scalePixels(double wRatio,double hRatio, PGraphics viewPort) {
viewPort.loadPixels();
int[] PixelsArrayNew = viewPort.pixels.clone();
double x_ratio = wRatio ;
double y_ratio = hRatio ;
double px, py ;
for (int i=0;i<viewPort.height;i++) {
for (int j=0;j<viewPort.width;j++) {
px = Math.floor(j%(wRatio*viewPort.width)/x_ratio) ;
py = Math.floor(i%(hRatio*viewPort.height)/y_ratio) ;
viewPort.pixels[(int)(i*viewPort.width)+j] = PixelsArrayNew[(int)((py*viewPort.width)+px)] ;
}
}
viewPort.updatePixels();
}
I have a project I'm working on in libGDX. I'm running tests on a distance field font and I've run into issues while compiling the shader on my Android phone (Galaxy Core 2 4.4.2). When deployed on my phone I get errors while the desktop app works fine (mostly - I'll get to that).
I'll take you through what I've been trying.
I want to be able to enable and disable having a font border during run time, and I can do this fine on the desktop app using the following shader and methods.
.frag:
#ifdef GL_ES
precision mediump float;
#else
#define LOWP
#endif
uniform sampler2D u_texture;
uniform float u_lower;
uniform float u_upper;
varying vec4 v_color;
uniform vec4 u_outlineColor;
uniform float u_enableOutline;
varying vec2 v_texCoord;
const float smoothing = 1.0/12.0;
const float outlineWidth = 3.0/12.0; //will need to be tweaked
const float outerEdgeCenter = 0.5 - outlineWidth; //for optimizing below calculation
void main() {
float distance = texture2D(u_texture, v_texCoord).a;
if (u_enableOutline > 0){
float alpha = smoothstep(outerEdgeCenter - smoothing, outerEdgeCenter + smoothing, distance);//Bigger to accomodate outline
float border = smoothstep(0.45 - smoothing, 0.55 + smoothing, distance);
gl_FragColor = vec4( mix(u_outlineColor.rgb, v_color.rgb, border), alpha );
}
else{
float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
gl_FragColor = vec4(v_color.rgb, alpha);
}
}
.vert:
uniform mat4 u_projTrans;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec4 a_color;
varying vec4 v_color;
varying vec2 v_texCoord;
void main() {
gl_Position = u_projTrans * a_position;
v_texCoord = a_texCoord0;
v_color = a_color;
}
With the distance font method to enable / disable the outline being:
public void enableOutline(float enable) {
ENABLE_OUTLINE = enable;
}
Where ENABLE_OUTLINE is passed to the shader by
distanceFieldShader.setUniformf("u_enableOutline", ENABLE_OUTLINE);
In this set up, running on my phone gives the following error:
"cannot compare float to int"
referencing this line in the .frag
if (u_enableOutline > 0){
Fair enough I say, so I change the data type like so:
uniform int u_enableOutline;
And the method to pass through an int:
public void enableOutline(int enable) {
ENABLE_OUTLINE = enable;
}
BUT there is no way to pass an int to the shader (which is why I chose to use floats, see this image: http://imgur.com/nVTN12i) and because of this my method to enable the outline doesn't work due to mixing up data types.
So my question is: can I get around this somehow so that I can enable and disable a border on my phone given these constraints?
It sounds like the API you are using does not offer you the possibility to use bool and int as Uniforms. The solution of using floats to circumvent this seems to be a good idea.
In your example, the problem you are having is because, unlike C and java, the GLSL compiler does not implicitly convert ints to floats.
what you need to do, is tell the compiler the type of your "0".
By using the syntax, 0.0, the compiler knows that your constant is a float and not an integer.
if (u_enableOutline > 0.0){
should fix your problem
I'm very new to OpenGL and LibGdx. I started with these tutorials but wanted to apply a phong texture. I've tried to merge a number of examples but am having issues.
I've got a sphere and spinning cube on the center of the screen. I've still got hundreds of things to work out but for the moment, I don't understand why LibGdx is reporting that my uniform material can't be found...
Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: java.lang.IllegalArgumentException: no uniform with name 'uMvpMatrix' in shader
Pixel Shader
I don't believe the Fragment shader is relevant but it's at the bottom in case.
#version 120
uniform mat4 uMvpMatrix;
varying vec3 diffuseColor;
// the diffuse Phong lighting computed in the vertex shader
varying vec3 specularColor;
// the specular Phong lighting computed in the vertex shader
varying vec4 texCoords; // the texture coordinates
void main()
{
vec3 normalDirection =
normalize(gl_NormalMatrix * gl_Normal);
vec3 viewDirection =
-normalize(vec3(gl_ModelViewMatrix * gl_Vertex));
vec3 lightDirection;
float attenuation;
if (0.0 == gl_LightSource[0].position.w)
// directional light?
{
attenuation = 1.0; // no attenuation
lightDirection =
normalize(vec3(gl_LightSource[0].position));
}
else // point light or spotlight (or other kind of light)
{
vec3 vertexToLightSource =
vec3(gl_LightSource[0].position
- gl_ModelViewMatrix * gl_Vertex);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
if (gl_LightSource[0].spotCutoff <= 90.0) // spotlight?
{
float clampedCosine = max(0.0, dot(-lightDirection,
gl_LightSource[0].spotDirection));
if (clampedCosine < gl_LightSource[0].spotCosCutoff)
// outside of spotlight cone?
{
attenuation = 0.0;
}
else
{
attenuation = attenuation * pow(clampedCosine,
gl_LightSource[0].spotExponent);
}
}
}
vec3 ambientLighting = vec3(gl_LightModel.ambient);
// without material color!
vec3 diffuseReflection = attenuation
* vec3(gl_LightSource[0].diffuse)
* max(0.0, dot(normalDirection, lightDirection));
// without material color!
vec3 specularReflection;
if (dot(normalDirection, lightDirection) < 0.0)
// light source on the wrong side?
{
specularReflection = vec3(0.0, 0.0, 0.0);
// no specular reflection
}
else // light source on the right side
{
specularReflection = attenuation
* vec3(gl_LightSource[0].specular)
* vec3(gl_FrontMaterial.specular)
* pow(max(0.0, dot(reflect(-lightDirection,
normalDirection), viewDirection)),
gl_FrontMaterial.shininess);
}
diffuseColor = ambientLighting + diffuseReflection;
specularColor = specularReflection;
texCoords = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Setup
shader = new ShaderProgram(vertexShader, fragmentShader);
mesh = Shapes.genCube();
mesh.getVertexAttribute(Usage.Position).alias = "a_position";
Render
...
float aspect = Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight();
projection.setToProjection(1.0f, 20.0f, 60.0f, aspect);
view.idt().trn(0, 0, -2.0f);
model.setToRotation(axis, angle);
combined.set(projection).mul(view).mul(model);
Gdx.gl20.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
shader.begin();
shader.setUniformMatrix("uMvpMatrix", combined);
mesh.render(shader, GL20.GL_TRIANGLES);
shader.end();
Stack Trace
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:113)
Caused by: java.lang.IllegalArgumentException: no uniform with name 'uMvpMatrix' in shader
at com.badlogic.gdx.graphics.glutils.ShaderProgram.fetchUniformLocation(ShaderProgram.java:283)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.setUniformMatrix(ShaderProgram.java:539)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.setUniformMatrix(ShaderProgram.java:527)
at com.overshare.document.Views.Test.onRender(Test.java:150)
...
Fragment Shader
#ifdef GL_ES
precision mediump float;
#endif
precision mediump float;
varying vec4 v_Color;
void main()
{
gl_FragColor = v_Color;
}
Can someone please tell me what I'm missing?
I ran into something similar. I think because your shader doesn't use the "uMvpMatrix" uniform, it declaration gets optimized out, and so its "not there" when you go to set it. If you change your shader to reference the matrix in some way, you should get farther.
See (indirectly)
Do (Unused) GLSL uniforms/in/out Contribute to Register Pressure?
I believe there are ways of developing and compiling shaders offline, so for a complex shader it may make sense to develop it outside of Libgdx (hopefully you'd get better error messages). Libgdx is just passing the giant string on to the lower layers, it doesn't do much with the shader itself, so there shouldn't be compatibility issues.
Also, problem could be in precision specifier. On device(Nexus S) the next uniform defining will throw the same error:
uniform float yShift;
Using precision specifier solves the problem:
uniform lowp float yShift;
LibGDX allows to check shader compilation and get error log:
if(!shader.isCompiled()){
String log = shader.getLog();
}
Finally, there's flag to ignore shader errors:
ShaderProgram.pedantic = false;
EDIT: Changing the fragment shader so only one light per-run was possible solved my first problem. My second problem still stands.
thanks in advance for any help you can offer. I have been working on a deferred shading pipeline for my LWJGL rendering engine for a couple weeks now. I though I had managed to get everything to work as I would expected, but after distributing the program to a few people I know, I began encountering problems. I'll try to keep this as short as possible. Thanks for staying with me.
I'll start with the first of the two problems in my title. On my machine (AMD Phenom II 965 and Nvidia GTX 480) the final product of my renderer was exactly as expected. (I was going to post a link to an image, but seeing as I am a new user, I was unable to post more than 3 hyperlinks. But it is sufficient to say, it looked like it should have.)
This is exactly what I intended so I though the renderer was working fine. I sent it off to a friend (who was using a GT 440) and they had the same results.
Soon after this I gave a build of the engine to a friend of mine who has a laptop (with a GT 540M). This was what the renderer produced (ignore the FPS counter, it doesn't work):
http://i.imgur.com/DxxFEpy.png
Obviously this is not at all the results I expected. I experienced the same results on every other mobile graphics card I was able to test on. After more than a week of banging my head on my desk, I was able to narrow the problem down to the lighting pass, where glBlendFunc is called. My code is as follows:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
List<Float[]>[] listArray = LightData.getInstance().updateLights();
List<Float[]> lightsColor = listArray[1];
List<Float[]> lightsPos = listArray[0];
viewMatrix.setViewMatrix(camera.getTranslation(), camera.getRotation());
glDisable(GL_DEPTH_TEST);
glUseProgram(0);
glCallList(quadList);
FBO.useShader();
FBO.passTextures(); //Just sets the shader uniform values to the correct textures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glLoadIdentity();
glBlendFunc(GL_ONE, GL_ONE) ; //using GL_ONE and GL_ONE_MINUS_SRC_ALPHA have the same effect
for (int i = 0; i < lightsPos.size(); i++) {
glClear(GL_DEPTH_BUFFER_BIT);
int uniformLightPosition = glGetUniformLocation(FBO.getShaderID(), "uniformLightPosition");
int uniformLightColor = glGetUniformLocation(FBO.getShaderID(), "uniformLightColor");
int uniformViewMatrix = glGetUniformLocation(FBO.getShaderID(), "uniformViewMatrix");
int uniformAmbient = glGetUniformLocation(FBO.getShaderID(), "uniformAmbient");
glUniform1(uniformLightPosition, Tools.asFloatBuffer(lightsPos.get(i)));
glUniform1(uniformLightColor, Tools.asFloatBuffer(lightsColor.get(i)));
glUniform1f(uniformAmbient, 0.01f);
glUniformMatrix4(uniformViewMatrix, true, viewMatrix.asFloatBuffer());
glCallList(quadList); //is just a display list for a fullscreen quad (using GL_QUADS)
}
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
This first thing that you might notice is the fact that I draw a quad and then clear the depth and color buffers. That will be a addressed in my next question, although I wouldn't be surprised if the problem in my next question was closely related to the one in this question. I am almost sure (99%) that the problem is in this method because when testing with an older build of the engine that only supported one light but was still using the deferred pipeline I was able to get perfect results on every computer I tested on. Once again, the renderer works on every desktop graphics card I have tested, but not on any laptop graphics cards. I have ruled out almost everything except this method. It might be worth noting that I have had no success using a texture with an internal format that is not GL_RGBA32f or GL_RGBA16f as a render target. Has anyone seen this before, or can anyone offer assistance? I would love if anyone even had any idea where to start looking for problems at this point, because I've got nothing. I've been complete unable to find a solution by myself.
Then moving on to the second problem and second question. In the beginning of the last code block I had a few line of codes that created a quad on the screen with no shader:
glDisable(GL_DEPTH_TEST);
glUseProgram(0);
glCallList(quadList);
FBO.useShader();
FBO.passTextures(); //Just sets the shader uniform values to the correct textures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
As far as I can tell, this code should do absolutely nothing. But when I remove the drawing of the quad, The window displays this:
http://i.imgur.com/mkMsP0F.png
I didn't know what else to call this besides "ghosting" because it is like a ghost image (at least that how it seems to me). When I rotate the MV matrix it distorts in the direction I rotate, and the first set of lights (I use an array of 7) light it, but then the rest light the actual model. I can't explain why this happens because the code that generates this image is exactly like the code above without the glCallList(quadList); which means the depth and color buffers are still cleared right before I enter the loop. I can't explain this problem at all. Does anyone have any idea what's wrong and how to fix it, or at least an idea about what's wrong?
EDIT I have found that this only happens to models that have texture coordinates. I don't know why.
EDIT It looks like when I limit the amount of lights allowed in each shader to 1, the ghosting gets much less noticeable, but is still there, So I assume this means that one run of the fragment shader results in these ghosts.
Thanks for ANY help anyone has with either of these two problems, it is greatly appreciated. If you have any questions for me just ask, although it might take me some time to get back to you, I'll try to get back as fast as possible.
EDIT Sory, I forgot my shader code:
GeometryPass vertex:
uniform sampler2D tex;
varying vec3 surfaceNormal;
varying vec3 varyingVertex;
void main() {
vec4 color = vec4(texture2D(tex, gl_TexCoord[1].st));
gl_FragColor = color;
}
GeometryPass fragment:
uniform sampler2D tex;
varying vec3 surfaceNormal;
varying vec3 varyingVertex;
uniform float materialValue;
uniform float specValue;
void main() {
vec4 color = vec4(texture2D(tex, gl_TexCoord[1].st)) ;//vec4(0.25,0.25,0.25,1);
vec4 vertex = vec4(varyingVertex, materialValue);
vec4 normal = vec4(surfaceNormal, specValue);
gl_FragData[0] = color;
gl_FragData[1] = vertex;
gl_FragData[2] = normal;
}
LightPass Phong vertex:
void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewMatrix * gl_Vertex;
}
LightPass Phong Fragment
uniform sampler2D location;
uniform sampler2D normal;
uniform sampler2D color;
uniform float uniformLightPosition[21];
uniform mat4 uniformViewMatrix;
uniform float uniformLightColor[28];
void main() {
vec4 color = texture2D(color, gl_TexCoord[0].st);
vec4 locationAndMat = texture2D(location, gl_TexCoord[0].st);
vec4 normalAndSpec = texture2D(normal, gl_TexCoord[0].st);
vec3 vertexPosition = locationAndMat.xyz;
vec3 surfaceNormal = normalAndSpec.xyz;
float spec = normalAndSpec.a;
float specA = locationAndMat.a;
vec4 lightColor[7];
int iterator = 0;
for (int i = 0; i<28; i = i+4) {
lightColor[iterator] = vec4(uniformLightColor[i], uniformLightColor[i+1], uniformLightColor[i+2], uniformLightColor[i+3]);
iterator = iterator + 1;
}
vec3 lightPos[7];
iterator = 0;
for (int i = 0; i<21; i = i+3) {
lightPos[iterator] = vec3(uniformLightPosition[i], uniformLightPosition[i+1], uniformLightPosition[i+2]);
lightPos[iterator] = (uniformViewMatrix * vec4(lightPos[iterator],1)).xyz ;
iterator = iterator + 1;
}
vec4 fragData[7];
vec4 endColor;
for (int i = 0; i<7 ; i++) {
if (lightColor[i] != vec4(0,0,0,0) && color != vec4(0,0,0,0)) {
vec3 lightDistance = lightPos[i]-vertexPosition;
float distance = pow((pow(lightDistance.x, 2) + pow(lightDistance.y, 2) + pow(lightDistance.z, 2)), 0.5);
if (distance < lightColor[i].a) {
float att = 1/((-3/800*(lightColor[i].a) + 0.225)*pow(distance, 2));
vec3 lightDirection = normalize(lightDistance);
float diffuseLightIntensity = max(0.0, dot(surfaceNormal, lightDirection));
fragData[i] += (vec4(diffuseLightIntensity,diffuseLightIntensity,diffuseLightIntensity,1));
vec3 reflectionDirection = normalize(reflect(-lightDirection, surfaceNormal));
float specular = max(0.0, dot(reflectionDirection, -normalize(vertexPosition)));
if (diffuseLightIntensity != 0) {
float fspecular = pow(specular, spec);
vec4 fspec = vec4(fspecular*specA, fspecular*specA, fspecular*specA,1);
fragData[i] += fspec;
}
fragData[i] *= lightColor[i];
fragData[i] *= 0.1;
fragData[i].a = 0;
fragData[i] *= att;
endColor += fragData[i];
}
}
}
gl_FragData[0] = endColor * color;
}
I solved the primary problem! This was good enough for me. It appears the problem I was having was that I had to many instructions per fragment shader (because of the for loop). When I adjusted the shader to only allow one light it worked as expected! I just use blending to take care of everything as I used to, but run the shader more. The downside is It requires more filtrate, but the upside is it works on older hardware and laptops.
I still can't figure out what's causing the ghosting, but it is less important to me, as I have a poor fix for that.