0
\$\begingroup\$

I am rendering some sprites from a sprite sheet that I generated but as I do, I get a purple haze around the blocks (The purple is coming from the other blocks in the sprite sheet that are next to them)

enter image description here

I thought it might be down to float mathematics not being 100% accurate but from what I can tell there is no problem. Also, it only happens when loading in sprite sheets as this is the only image code that extracts a section of an image in my game.

Has anyone else came across this and know what might be causing it?

Edit: Here is some example code of how the shader gets the sprite position's

Vertex Shader

#version 400 core

in vec3 position;
in vec2 textureCoords;
in vec3 normal;

out vData{
    vec2 pass_textureCoords;
    vec3 surfaceNormal;
    vec3 toLightVector;
    vec3 toCameraVector;
    float visibility;
}vertexOut;


uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition;

uniform float useFakeLighting;

uniform float texture_spriteSheetWidth = 1;
uniform float texture_spriteSheetHeight = 1;

uniform float texture_spriteSheet_xOffset;
uniform float texture_spriteSheet_yOffset;

const float density = 0.0035;
const float gradient = 5.0;

void main(void) {
    vec4 worldPosition = transformationMatrix * vec4(position, 1.0);
    vec4 positionRelitiveToCam = viewMatrix * worldPosition;
    gl_Position = projectionMatrix * positionRelitiveToCam;
    vertexOut.pass_textureCoords = vec2((textureCoords.x + texture_spriteSheet_xOffset) / texture_spriteSheetWidth,
        (textureCoords.y + texture_spriteSheet_yOffset) / texture_spriteSheetHeight);


    vec3 actualNormal = normal;
    if (useFakeLighting>0.5) {
        actualNormal = vec3(0.0, 1.0, 0.0);
    }

    vertexOut.surfaceNormal = (transformationMatrix * vec4(actualNormal, 0.0)).xyz;
    vertexOut.toLightVector = lightPosition;// -worldPosition.xyz;
    vertexOut.toCameraVector = (inverse(viewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz - worldPosition.xyz;

    float distance = length(positionRelitiveToCam.xyz);
    vertexOut.visibility = exp(-pow((distance*density), gradient));
    vertexOut.visibility = clamp(vertexOut.visibility, 0.0, 1.0);
}

Fragment Shader

#version 400 core

in vData{
    vec2 pass_textureCoords;
    vec3 surfaceNormal;
    vec3 toLightVector;
    vec3 toCameraVector;
    float visibility;
}vertexIn;


out vec4 out_Color;

uniform sampler2D textureSampler;
uniform vec3 lightColour;
uniform float shineDamper;
uniform float reflectivity;
uniform vec3 skyColor;

void main(void) {

    vec3 unitNormal = normalize(vertexIn.surfaceNormal);
    vec3 unitLightVector = normalize(vertexIn.toLightVector);

    float nDotl = dot(unitNormal, unitLightVector);
    float brightness = max(nDotl, 0.2);
    vec3 diffuse = brightness * lightColour;

    vec3 unitVectorToCamera = normalize(vertexIn.toCameraVector);
    vec3 lightDirection = -unitLightVector;
    vec3 reflectedLightDirection = reflect(lightDirection, unitNormal);

    float specularFactor = dot(reflectedLightDirection, unitVectorToCamera);
    specularFactor = max(specularFactor, 0.0);
    float dampedFactor = pow(specularFactor, shineDamper);
    vec3 finalSpecular = dampedFactor * reflectivity * lightColour;

    vec4 textureColour = texture(textureSampler, vertexIn.pass_textureCoords);
    if (textureColour.a<0.5) {
        discard;
    }

    out_Color = vec4(diffuse, textureColour.a) * textureColour + vec4(finalSpecular, textureColour.a);
    //out_Color = mix(vec4(skyColor, 1.0), out_Color, vertexIn.visibility);

}

And the relevent part is here

vertexOut.pass_textureCoords = vec2((textureCoords.x + texture_spriteSheet_xOffset) / texture_spriteSheetWidth,
        (textureCoords.y + texture_spriteSheet_yOffset) / texture_spriteSheetHeight);

Loading Textures Into OpenGL

glEnable(GL_TEXTURE_2D);
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
textures.push_back(id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &finalBuffer[0]);

glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
float mipMapingAffectivness = 0.4f;
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, mipMapingAffectivness);

glBindTexture(GL_TEXTURE_2D, 0);
\$\endgroup\$
4
  • \$\begingroup\$ What are the texture parameters you're setting for these textures? And how does your shader sample the textures? Some code would help. \$\endgroup\$ Dec 28, 2016 at 3:56
  • \$\begingroup\$ @user1118321I have included my shader code, hopefully this helps \$\endgroup\$
    – 0xen
    Dec 28, 2016 at 4:02
  • \$\begingroup\$ Can you post the code where you create the textures in your app? Also, I'm more interested in the fragment shader than vertex. (Sorry, I should have specified that.) \$\endgroup\$ Dec 28, 2016 at 4:10
  • \$\begingroup\$ @user1118321 I have included the fragment shader code and the texture loading code \$\endgroup\$
    – 0xen
    Dec 28, 2016 at 4:20

1 Answer 1

4
\$\begingroup\$

If I understand correctly, you're using a texture atlas (several sprites in a single texture)? You've got the min and mag filters set to linear, which means it will interpolate between pixels if the texture sampling coordinate isn't exactly in the center of the pixel. That means that near the border, if you aren't careful, you'll get bleed-through from neighboring sprites. There are a few options:

  1. Set the min and mag filters to nearest instead of linear.
  2. Ensure that when the fragment shader actually samples the textures it never samples less than 1/2 a pixel from any border.
  3. Put a 1-pixel border around each sprite that simply repeats the current edge.
\$\endgroup\$
2
  • \$\begingroup\$ Fair point. I'll update that portion of the answer to clarify. \$\endgroup\$ Dec 28, 2016 at 6:37
  • \$\begingroup\$ I used the first approach but I found it was still leaving me with a very small edge bleeding, so i also modified the object texture quards to start at 0.0001 -> 0.9999 \$\endgroup\$
    – 0xen
    Dec 28, 2016 at 23:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .