瀏覽代碼

Lens flare alternative method. They look better

Panagiotis Christopoulos Charitos 12 年之前
父節點
當前提交
14272a6ac9

+ 0 - 0
engine-rsrc/ConsolaMono.ttf → engine_data/ConsolaMono.ttf


+ 0 - 0
engine-rsrc/ModernAntiqua.ttf → engine_data/ModernAntiqua.ttf


+ 0 - 0
engine-rsrc/cube.mesh → engine_data/cube.mesh


+ 0 - 0
engine-rsrc/dummy.norm.png → engine_data/dummy.norm.png


+ 0 - 0
engine-rsrc/dummy.png → engine_data/dummy.png


+ 0 - 0
engine-rsrc/fontmap.png → engine_data/fontmap.png


二進制
engine_data/lens_dirt.ankitex


+ 0 - 0
engine-rsrc/noise.png → engine_data/noise.png


+ 0 - 0
engine-rsrc/noise3.png → engine_data/noise3.png


+ 0 - 0
engine-rsrc/pyramid.blend → engine_data/pyramid.blend


+ 0 - 0
engine-rsrc/pyramid.mesh → engine_data/pyramid.mesh


+ 0 - 0
engine-rsrc/side-blur.png → engine_data/side-blur.png


+ 0 - 0
engine-rsrc/sphere.blend → engine_data/sphere.blend


+ 0 - 0
engine-rsrc/sphere.mesh → engine_data/sphere.mesh


+ 10 - 5
include/anki/renderer/Lf.h

@@ -12,6 +12,8 @@ namespace anki {
 /// Lens flare rendering pass
 /// Lens flare rendering pass
 class Lf: public OptionalRenderingPass
 class Lf: public OptionalRenderingPass
 {
 {
+	friend class MainRenderer;
+
 public:
 public:
 	Lf(Renderer* r_)
 	Lf(Renderer* r_)
 		: OptionalRenderingPass(r_)
 		: OptionalRenderingPass(r_)
@@ -22,13 +24,16 @@ public:
 	void init(const RendererInitializer& initializer);
 	void init(const RendererInitializer& initializer);
 	void run();
 	void run();
 
 
+	const Texture& getFai() const
+	{
+		return fai;
+	}
+
 private:
 private:
 	ShaderProgramResourcePointer drawProg;
 	ShaderProgramResourcePointer drawProg;
-	Ubo flareDataUbo;
-	const ShaderProgramUniformBlock* ublock;
-
-	U8 maxFlaresPerLight;
-	U8 maxLightsWithFlares;
+	Texture fai;
+	Fbo fbo;
+	TextureResourcePointer lensDirtTex;
 
 
 	void initInternal(const RendererInitializer& initializer);
 	void initInternal(const RendererInitializer& initializer);
 };
 };

+ 9 - 0
include/anki/renderer/Pps.h

@@ -50,6 +50,15 @@ public:
 		return bl;
 		return bl;
 	}
 	}
 
 
+	const Lf& getLf() const
+	{
+		return lf;
+	}
+	Lf& getLf()
+	{
+		return lf;
+	}
+
 	const Texture& getFai() const
 	const Texture& getFai() const
 	{
 	{
 		return fai;
 		return fai;

+ 6 - 0
shaders/Pps.glsl

@@ -11,6 +11,7 @@ uniform highp sampler2D msDepthFai;
 uniform lowp sampler2D isFai;
 uniform lowp sampler2D isFai;
 uniform lowp sampler2D ppsHdrFai;
 uniform lowp sampler2D ppsHdrFai;
 uniform lowp sampler2D ppsSsaoFai;
 uniform lowp sampler2D ppsSsaoFai;
+uniform lowp sampler2D ppsLfFai;
 
 
 in vec2 vTexCoords;
 in vec2 vTexCoords;
 
 
@@ -107,6 +108,11 @@ void main(void)
 	fColor *= ssao;
 	fColor *= ssao;
 #endif
 #endif
 
 
+#if defined(LF_ENABLED)
+	vec3 lf = textureLod(ppsLfFai, vTexCoords, 0.0).rgb;
+	fColor += lf;
+#endif
+
 	fColor = gammaCorrectionRgb(vec3(0.9, 0.92, 0.75), fColor);
 	fColor = gammaCorrectionRgb(vec3(0.9, 0.92, 0.75), fColor);
 
 
 #if 0
 #if 0

+ 53 - 28
shaders/PpsLfPass.glsl

@@ -2,46 +2,71 @@
 
 
 #pragma anki start vertexShader
 #pragma anki start vertexShader
 
 
-// Per flare information
-struct Flare
-{
-	vec4 posScale; // xy: Position, z: Scale, w: Scale again
-	vec4 alphaDepth; // x: alpha, y: texture depth
-};
+#pragma anki include "shaders/SimpleVert.glsl"
 
 
-// The block contains data for all flares
-layout(std140) uniform flaresBlock
-{
-	Flare flares[MAX_FLARES];
-};
+#pragma anki start fragmentShader
+
+#define MAX_GHOSTS 4
+#define FMAX_GHOSTS (float(MAX_GHOSTS))
+#define GHOST_DISPERSAL (0.7)
+#define HALO_WIDTH 0.4
+#define DISTORTION 4.0
 
 
-layout(location = 0) in vec2 position;
+uniform sampler2D tex;
+uniform sampler2D lensDirtTex;
 
 
-out vec3 vTexCoords;
-out flat float vAlpha;
+in vec2 vTexCoords;
+
+out vec3 fColor;
+
+vec3 textureDistorted(
+	in sampler2D tex,
+	in vec2 texcoord,
+	in vec2 direction, // direction of distortion
+	in vec3 distortion ) // per-channel distortion factor  
+{
+	return vec3(
+		texture(tex, texcoord + direction * distortion.r).r,
+		texture(tex, texcoord + direction * distortion.g).g,
+		texture(tex, texcoord + direction * distortion.b).b);
+}
 
 
 void main()
 void main()
 {
 {
-	Flare flare = flares[gl_InstanceID];
+	vec2 texcoord = -vTexCoords + vec2(1.0);
 
 
-	vTexCoords = vec3((position * 0.5) + 0.5, flare.alphaDepth.y);
+	vec2 imgSize = vec2(textureSize(tex, 0));
 
 
-	vec4 posScale = flare.posScale;
-	gl_Position = vec4(position * posScale.zw + posScale.xy , 0.0, 1.0);
+	vec2 ghostVec = (vec2(0.5) - texcoord) * GHOST_DISPERSAL;
 
 
-	vAlpha = flare.alphaDepth.x;
-}
+	const vec2 texelSize = 1.0 / vec2(TEX_DIMENSIONS);
 
 
-#pragma anki start fragmentShader
+	const vec3 distortion = 
+		vec3(-texelSize.x * DISTORTION, 0.0, texelSize.x * DISTORTION);
 
 
-uniform sampler2DArray images;
+	// sample ghosts:  
+	vec3 result = vec3(0.0);
+	for(int i = 0; i < MAX_GHOSTS; ++i) 
+	{ 
+		vec2 offset = fract(texcoord + ghostVec * float(i));
 
 
-in vec3 vTexCoords;
-in flat float vAlpha;
+		float weight = length(vec2(0.5) - offset) / length(vec2(0.5));
+		weight = pow(1.0 - weight, 10.0);
 
 
-out vec3 fColor;
+		result += textureDistorted(tex, offset, offset, distortion) * weight;
+	}
 
 
-void main()
-{
-	fColor = texture(images, vTexCoords).rgb * vAlpha;
+	// sample halo:
+	vec2 haloVec = normalize(ghostVec) * HALO_WIDTH;
+	float weight = 
+		length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));
+	weight = pow(1.0 - weight, 5.0);
+	result += textureDistorted(tex, texcoord + haloVec, haloVec, distortion) 
+		* weight;
+
+	// lens dirt
+	result *= texture(lensDirtTex, vTexCoords).rgb;
+
+	// Write
+	fColor = result;
 }
 }

+ 26 - 158
src/renderer/Lf.cpp

@@ -69,37 +69,28 @@ void Lf::initInternal(const RendererInitializer& initializer)
 		return;
 		return;
 	}
 	}
 
 
-	maxFlaresPerLight = initializer.pps.lf.maxFlaresPerLight;
-	maxLightsWithFlares = initializer.pps.lf.maxLightsWithFlares;
-
-	if(maxLightsWithFlares > ANKI_MAX_LIGHTS_WITH_FLARE)
-	{
-		throw ANKI_EXCEPTION("Too big maxLightsWithFlares");
-	}
-
-	if(maxFlaresPerLight > ANKI_MAX_FLARES_PER_LIGHT)
-	{
-		throw ANKI_EXCEPTION("Too big maxFlaresPerLight");
-	}
-
 	// Load the shader
 	// Load the shader
-	std::string pps = "#define MAX_FLARES " 
-		+ std::to_string(maxFlaresPerLight * maxLightsWithFlares) + "\n";
-	std::string fname = ShaderProgramResource::createSrcCodeToCache(
-		"shaders/PpsLfPass.glsl", pps.c_str());
-	drawProg.load(fname.c_str());
+	std::string pps = "#define TEX_DIMENSIONS vec2(" 
+		+ std::to_string(r->getPps().getHdr().getFai().getWidth()) + ".0, "
+		+ std::to_string(r->getPps().getHdr().getFai().getHeight()) + ".0)\n";
 
 
-	ublock = &drawProg->findUniformBlock("flaresBlock");
-	ublock->setBinding(0);
+	drawProg.load(ShaderProgramResource::createSrcCodeToCache(
+		"shaders/PpsLfPass.glsl", pps.c_str()).c_str());
 
 
-	PtrSize blockSize = sizeof(Flare) * maxFlaresPerLight * maxLightsWithFlares;
-	if(ublock->getSize() != blockSize)
+	// Create the FAI
+	fai.create2dFai(r->getPps().getHdr().getFai().getWidth(), 
+		r->getPps().getHdr().getFai().getHeight(), 
+		GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
+
+	fbo.create();
+	fbo.setColorAttachments({&fai});
+	if(!fbo.isComplete())
 	{
 	{
-		throw ANKI_EXCEPTION("Incorrect block size");
+		throw ANKI_EXCEPTION("Fbo not complete");
 	}
 	}
 
 
-	// Init UBO
-	flareDataUbo.create(blockSize, nullptr);
+	// Textures
+	lensDirtTex.load("engine-rsrc/lens_dirt.ankitex");
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -107,143 +98,20 @@ void Lf::run()
 {
 {
 	ANKI_ASSERT(enabled);
 	ANKI_ASSERT(enabled);
 
 
-	// Retrieve some things
-	SceneGraph& scene = r->getSceneGraph();
-	Camera& cam = scene.getActiveCamera();
-	VisibilityTestResults& vi = *cam.getVisibilityTestResults();
-
-	//
-	// Iterate the visible light and get those that have lens flare
-	//
-	Array<Light*, ANKI_MAX_LIGHTS_WITH_FLARE> lights;
-	U lightsCount = 0;
-	for(auto it = vi.getLightsBegin(); it != vi.getLightsEnd(); ++it)
-	{
-		SceneNode& sn = *(*it).node;
-		ANKI_ASSERT(sn.getLight());
-		Light* light = sn.getLight();
-
-		if(light->hasLensFlare())
-		{
-			lights[lightsCount % maxLightsWithFlares] = light;
-			++lightsCount;
-		}
-	}
-
-	// Early exit
-	if(lightsCount == 0)
-	{
-		return;
-	}
-
-	lightsCount = lightsCount % (maxLightsWithFlares + 1);
-
-	//
-	// Sort the lights using their lens flare texture
-	//
-	std::sort(lights.begin(), lights.begin() + lightsCount, LightSortFunctor());
-
-	//
-	// Write the UBO and get the groups
-	//
-
-	Array<Flare, ANKI_MAX_FLARES> flares;
-	U flaresCount = 0;
-
-	// Contains the number of flares per flare texture
-	Array<U, ANKI_MAX_LIGHTS_WITH_FLARE> groups;
-	Array<const Texture*, ANKI_MAX_LIGHTS_WITH_FLARE> texes;
-	U groupsCount = 0;
-
-	GLuint lastTexId = 0;
-
-	// Iterate all lights and update the flares as well as the groups
-	while(lightsCount-- != 0)
-	{
-		Light& light = *lights[lightsCount];
-		const Texture& tex = light.getLensFlareTexture();
-		const U depth = tex.getDepth();
-
-		// Transform
-		Vec3 posWorld = light.getWorldTransform().getOrigin();
-		Vec4 posClip = cam.getViewProjectionMatrix() * Vec4(posWorld, 1.0);
-		Vec2 posNdc = posClip.xy() / posClip.w();
-
-		Vec2 dir = -posNdc;
-		F32 len = dir.getLength();
-		dir /= len; // Normalize dir
-
-		// New group?
-		if(lastTexId != tex.getGlId())
-		{
-			texes[groupsCount] = &tex;
-			groups[groupsCount] = 0;
-			lastTexId = tex.getGlId();
-
-			++groupsCount;
-		}
-
-		// First flare 
-		flares[flaresCount].pos = posNdc;
-		flares[flaresCount].scale = 
-			Vec2(0.1, r->getAspectRatio() * 0.1);
-		flares[flaresCount].depth = 0.0;
-		flares[flaresCount].alpha = 0.5;
-		++flaresCount;
-		++groups[groupsCount - 1];
-
-		// The rest of the flares
-		for(U d = 1; d < depth; d++)
-		{
-			// Write the "flares"
-			F32 factor = d / ((F32)depth - 1.0);
-
-			F32 flen = len * 2.0 * factor;
-
-			flares[flaresCount].pos = posNdc + dir * flen;
-
-			flares[flaresCount].scale = 
-				Vec2(0.1, r->getAspectRatio() * 0.1) 
-				* (len - flen) * 2.0;
-
-			flares[flaresCount].depth = d;
-
-			flares[flaresCount].alpha = 0.1;
-
-			// Advance
-			++flaresCount;
-			++groups[groupsCount - 1];
-		}
-	}
-
-	//
-	// Time to render
-	//
-
-	// Write the buffer
-	flareDataUbo.write(&flares[0], 0, sizeof(Flare) * flaresCount);
-
 	// Set the common state
 	// Set the common state
-	drawProg->bind();
-	GlStateSingleton::get().disable(GL_DEPTH_TEST);
-	GlStateSingleton::get().enable(GL_BLEND);
-	GlStateSingleton::get().setBlendFunctions(GL_ONE, GL_ONE);
-
-	PtrSize offset = 0;
-	for(U i = 0; i < groupsCount; i++)
-	{
-		const Texture& tex = *texes[i];
-		U instances = groups[i];
-		PtrSize buffSize = sizeof(Flare) * instances;
+	const Texture& inTex = r->getPps().getHdr().getFai();
 
 
-		drawProg->findUniformVariable("images").set(tex);
+	fbo.bind();
+	drawProg->bind();
+	drawProg->findUniformVariable("tex").set(inTex);
+	drawProg->findUniformVariable("lensDirtTex").set(*lensDirtTex);
 
 
-		flareDataUbo.setBindingRange(0, offset, buffSize);
-		
-		r->drawQuadInstanced(instances);
+	GlStateSingleton::get().setViewport(
+		0, 0, inTex.getWidth(), inTex.getHeight());
+	GlStateSingleton::get().disable(GL_DEPTH_TEST);
+	GlStateSingleton::get().disable(GL_BLEND);
 
 
-		offset += buffSize;
-	}
+	r->drawQuad();
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 1 - 1
src/renderer/MainRenderer.cpp

@@ -101,7 +101,7 @@ void MainRenderer::render(SceneGraph& scene)
 		GlStateSingleton::get().disable(GL_BLEND);
 		GlStateSingleton::get().disable(GL_BLEND);
 		sProg->bind();
 		sProg->bind();
 #if 0
 #if 0
-		const Texture& finalFai = pps.getHdr().getFai();
+		const Texture& finalFai = pps.getLf().fai;
 #else
 #else
 		const Texture& finalFai = pps.getFai();
 		const Texture& finalFai = pps.getFai();
 #endif
 #endif

+ 14 - 6
src/renderer/Pps.cpp

@@ -48,6 +48,11 @@ void Pps::initInternal(const RendererInitializer& initializer)
 		pps += "#define HDR_ENABLED\n";
 		pps += "#define HDR_ENABLED\n";
 	}
 	}
 
 
+	if(lf.getEnabled())
+	{
+		pps += "#define LF_ENABLED\n";
+	}
+
 	if(initializer.pps.sharpen)
 	if(initializer.pps.sharpen)
 	{
 	{
 		pps += "#define SHARPEN_ENABLED\n";
 		pps += "#define SHARPEN_ENABLED\n";
@@ -76,12 +81,6 @@ void Pps::init(const Renderer::Initializer& initializer)
 //==============================================================================
 //==============================================================================
 void Pps::run()
 void Pps::run()
 {
 {
-	// Draw flares
-	if(lf.getEnabled())
-	{
-		lf.run();
-	}
-
 	GlStateSingleton::get().disable(GL_BLEND);
 	GlStateSingleton::get().disable(GL_BLEND);
 
 
 	// First SSAO because it depends on MS where HDR depends on IS
 	// First SSAO because it depends on MS where HDR depends on IS
@@ -95,6 +94,11 @@ void Pps::run()
 		hdr.run();
 		hdr.run();
 	}
 	}
 
 
+	if(lf.getEnabled())
+	{
+		lf.run();
+	}
+
 	if(drawToDefaultFbo)
 	if(drawToDefaultFbo)
 	{
 	{
 		Fbo::bindDefault();
 		Fbo::bindDefault();
@@ -122,6 +126,10 @@ void Pps::run()
 	{
 	{
 		prog->findUniformVariable("ppsHdrFai").set(hdr.getFai());
 		prog->findUniformVariable("ppsHdrFai").set(hdr.getFai());
 	}
 	}
+	if(lf.getEnabled())
+	{
+		prog->findUniformVariable("ppsLfFai").set(lf.getFai());
+	}
 
 
 	r->drawQuad();
 	r->drawQuad();
 }
 }