indexed deferred lighting artefacts [solved]

Started by
0 comments, last by sprite_hound 16 years ago
I've been working on implementing indexed deferred lighting, and it's mainly working nicely. However, I seem to be getting one pixel line artefacts around the lit areas, as shown here: They only occur where the light volumes overlap (in this scene there's a large radius light as well as the visible ones), and tend to be dark / black at the side of a light nearest the viewer, and lighter on the side farthest away. They stay at 1px wide wherever the camera is, which makes them horribly obvious. (They also occur from lights located behind the surface.) They're not visible on the index texture, so I don't think it's anything to do with my use of the stencil buffer, so I suppose it's likely to be one of the shaders? Anyway, I'll post the likely culprits. Light volume / texture creation code:


void Lighting::render(Renderer* rd) {
	// State setup for volume rendering...
	framebuffer->bind();
	framebuffer->check();
	
	rd->clear(true, false, true);
	
	rd->colour.push();
	
	rd->blend.push();
	rd->blend.enableBlend();
	rd->blend.setBlend(GL_ONE, GL_CONSTANT_COLOR);
	rd->blend.setConstColour(0.251f, 0.251f, 0.251f, 0.251f);
	
	rd->depth.push();
	rd->depth.disableWrite();
	
	rd->stencil.push();
	rd->stencil.enableTest();
	
	rd->geometry.push();
	
	rd->shader.push(lightColorProg.get());
	
	// Setup for texture creation...
	std::vector<GLubyte> colourData((maxLights+1)*3, 0);
	std::vector<GLubyte>::size_type cdcount = 2;
	std::vector<GLfloat> positionData((maxLights+1)*4, 0);
	std::vector<GLfloat>::size_type pdcount = 3;
	
	cml::matrix44f_c m = rd->view.getViewMatrix();
	
	unsigned int numLights = enabledLights.size() <= maxLights ? enabledLights.size() : maxLights;
	for (std::vector<const Light*>::iterator i = enabledLights.begin(); i != enabledLights.begin() + numLights; ++i) {
		// Convert the light index into 4 2bit values
		GLubyte index = static_cast<GLubyte>(i - enabledLights.begin() +1);
		GLubyte rBit = (index & (0x3 << 0)) << 6;
		GLubyte gBit = (index & (0x3 << 2)) << 4;
		GLubyte bBit = (index & (0x3 << 4)) << 2;
		GLubyte aBit = (index & (0x3 << 6)) << 0;
		
		lightColorProg->passToUniform3f("LightPos", 
			(*i)->position[0], 
			(*i)->position[1], 
			(*i)->position[2]);
		lightColorProg->passToUniform1f("LightRadius", (*i)->radius);
		lightColorProg->passToUniform4f("OutColor", 
			static_cast<float>(rBit) / 255.f,
			static_cast<float>(gBit) / 255.f,
			static_cast<float>(bBit) / 255.f,
			static_cast<float>(aBit) / 255.f);
		
		// Render back faces with greater than depth to the stencil.
		rd->stencil.setFunction(GL_ALWAYS, index, 0xff);
		rd->stencil.setOperation(GL_KEEP, GL_KEEP, GL_REPLACE);
		
		rd->geometry.setFaceCulling(GL_FRONT);
		rd->depth.setFunction(GL_GREATER);
		rd->colour.disableWrite();
		sphere.render(rd);
		
		// Render front faces with less than depth, check value with stencil.
		rd->stencil.setFunction(GL_EQUAL, index, 0xff);
		rd->stencil.setOperation(GL_KEEP, GL_KEEP, GL_KEEP);
		
		rd->geometry.setFaceCulling(GL_BACK);
		rd->depth.setFunction(GL_LESS);
		rd->colour.enableWrite();
		sphere.render(rd);
		
		// Texture creation stuff...
		colourData[++cdcount] = static_cast<GLubyte>(std::min((*i)->colour.r * 256.f, 255.f));
		colourData[++cdcount] = static_cast<GLubyte>(std::min((*i)->colour.g * 256.f, 255.f));
		colourData[++cdcount] = static_cast<GLubyte>(std::min((*i)->colour.b * 256.f, 255.f));
		
		cml::vector3f p = cml::transform_point(m, (*i)->position);
		positionData[++pdcount] = p[0];
		positionData[++pdcount] = p[1];
		positionData[++pdcount] = p[2];
		positionData[++pdcount] = 1.f / (*i)->radius;
	}
	// Create our textures...
	Texture::Settings cts = Texture::Settings();
	cts.hasMipMaps = false; cts.interpolateMode = Texture::INTERP_NEAREST;
	cts.internalFormat = GL_RGB8;
	colourTexture.reset( new Texture1D(&colourData[0], maxLights+1, GL_RGB, GL_UNSIGNED_BYTE, cts) );
	
	Texture::Settings pts = Texture::Settings();
	pts.hasMipMaps = false; pts.interpolateMode = Texture::INTERP_NEAREST;
	pts.internalFormat = GL_RGBA32F_ARB;
	positionTexture.reset( new Texture1D(&positionData[0], maxLights+1, GL_RGBA, GL_FLOAT, pts) );
	
	// Cleanup states...
	rd->shader.pop();
	
	rd->geometry.pop();
	rd->stencil.pop();
	rd->depth.pop();
	rd->blend.pop();
	rd->colour.pop();
	
	framebuffer->unbind();
}








"lightColorProg" shaders (used when rendering the light volumes in the code above):


//VERTEX SHADER:
uniform vec3 LightPos;
uniform float LightRadius;

void main() {
	
	// Position the light sphere in the scene
	vec4 outPos = gl_ModelViewProjectionMatrix * 
		vec4(LightPos + (gl_Vertex.xyz * LightRadius), 1.0);
	
	// This is in the demo... prevents lights disappearing when you get close
	if (outPos.z < -outPos.w) {
		outPos.z = -0.999999;
		outPos.w = 1.0;
	}
	
	gl_Position = outPos;
}

// FRAGMENT SHADER:
uniform vec4 OutColor;

void main(){
	gl_FragColor = OutColor;
}








And the shaders for the standard rendering pass for the terrain:


// VERTEX SHADER:
varying vec4 ProjectSpace;
varying vec3 ECPosition3;
varying vec3 Normal;

void main() {
	ECPosition3 = (gl_ModelViewMatrix * gl_Vertex).xyz;
	
	gl_TexCoord[0] = gl_MultiTexCoord0;
	Normal = normalize(gl_NormalMatrix * gl_Normal);
	
	ProjectSpace = gl_ModelViewProjectionMatrix * gl_Vertex;
	gl_Position = ProjectSpace;
	ProjectSpace.xy = (ProjectSpace.xy + vec2(ProjectSpace.w)) * 0.5;
}

// FRAGMENT SHADER:
#define OVERLAP_LIGHTS 4

uniform sampler2D Base;
uniform sampler2D BitPlane;

uniform sampler1D LightPosTex;
uniform sampler1D LightColorTex;

varying vec4 ProjectSpace;
varying vec3 ECPosition3;
varying vec3 Normal;

const vec4 unpackConst = vec4(4.0, 16.0, 64.0, 256.0) / 256.0;

float nextLightIndex(inout vec4 packedLight, inout vec4 floorValues) {
	packedLight = floorValues * 0.25;
	floorValues = floor(packedLight);
	vec4 fracParts = packedLight - floorValues;
	return dot(fracParts, unpackConst);
}

void main() {
	vec3 base = texture2D(Base, gl_TexCoord[0].st).rgb;
	vec3 lighting = vec3(0.0);
	
	vec4 packedLight = texture2DProj(BitPlane, ProjectSpace);
	vec4 floorValues = ceil(packedLight * 254.5);
	
	vec3 viewVec = -normalize(ECPosition3);
	Normal = normalize(Normal);
	
	for(int i = 0; i < OVERLAP_LIGHTS; i++) {
		float lightIndex = nextLightIndex(packedLight, floorValues);
		
		vec3 lightColor = texture1D(LightColorTex, lightIndex).rgb;
		
		vec4 lightPosSize = texture1D(LightPosTex, lightIndex);
		vec3 lightViewPos = lightPosSize.xyz;
		
		vec3 lightVec = lightViewPos - ECPosition3;
		float attenuation = clamp(1.0 - length(lightVec) * lightPosSize.a, 0.0, 1.0);
		lightVec = normalize(lightVec);
		
		float nDotlightVec = clamp(dot(Normal, lightVec), 0.0, 1.0);
		vec3 diffuse = lightColor * nDotlightVec * attenuation;
		
		lighting += diffuse;
	}

	gl_FragColor.rgb = base * 0.2 + base * lighting;
	gl_FragColor.a = 1.0;
}









Sorry this is rather a code dump, but I don't know what could be causing this. Any help is much appreciated :) sprite [Edited by - sprite_hound on April 22, 2008 11:42:04 AM]
Advertisement
Hah. Typical. Post something here and solve it two seconds later.

Changed the texture interpolation to nearest, instead of linear, and it's now working fine.

This topic is closed to new replies.

Advertisement