Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wip] postprocess shader #1605

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/include/tangram/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ class Map {

std::shared_ptr<Platform>& getPlatform();

void enablePostProcess(bool _enable);

private:

class Impl;
Expand Down
87 changes: 87 additions & 0 deletions core/shaders/fxaa.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifdef GL_ES
precision mediump float;
#else
#define mediump
#endif

//texcoords computed in vertex step
//to avoid dependent texture reads
varying vec2 v_rgbNW;
varying vec2 v_rgbNE;
varying vec2 v_rgbSW;
varying vec2 v_rgbSE;
varying vec2 v_rgbM;

varying vec2 vUv;
uniform vec2 u_resolution;
uniform sampler2D iChannel0;

#ifndef FXAA_REDUCE_MIN
#define FXAA_REDUCE_MIN (1.0/ 128.0)
#endif
#ifndef FXAA_REDUCE_MUL
#define FXAA_REDUCE_MUL (1.0 / 8.0)
#endif
#ifndef FXAA_SPAN_MAX
#define FXAA_SPAN_MAX 8.0
#endif

//optimized version for mobile, where dependent
//texture reads can be a bottleneck
vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,
vec2 v_rgbNW, vec2 v_rgbNE,
vec2 v_rgbSW, vec2 v_rgbSE,
vec2 v_rgbM) {
vec4 color;
mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);
vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;
vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;
vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;
vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;
vec4 texColor = texture2D(tex, v_rgbM);
vec3 rgbM = texColor.xyz;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
float lumaNE = dot(rgbNE, luma);
float lumaSW = dot(rgbSW, luma);
float lumaSE = dot(rgbSE, luma);
float lumaM = dot(rgbM, luma);
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));

mediump vec2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));

float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
(0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);

float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
dir * rcpDirMin)) * inverseVP;

vec3 rgbA = 0.5 * (
texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +
texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (
texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +
texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);

float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax))
color = vec4(rgbA, 1.0); // texColor.a);
else
color = vec4(rgbB, 1.0); // texColor.a);
return color;
}


void main() {
//can also use gl_FragCoord.xy
mediump vec2 fragCoord = vUv * u_resolution;
//mediump vec2 fragCoord = gl_FragCoord.xy;

gl_FragColor = fxaa(iChannel0, fragCoord, u_resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);

}
46 changes: 46 additions & 0 deletions core/shaders/fxaa.vs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifdef GL_ES
precision mediump float;
#endif

uniform mat4 u_proj;

//texcoords computed in vertex step
//to avoid dependent texture reads
varying vec2 v_rgbNW;
varying vec2 v_rgbNE;
varying vec2 v_rgbSW;
varying vec2 v_rgbSE;
varying vec2 v_rgbM;

//a resolution for our optimized shader
uniform vec2 u_resolution;
attribute vec2 a_position;
attribute vec2 a_uv;
varying vec2 vUv;

void texcoords(vec2 fragCoord, vec2 resolution,
out vec2 v_rgbNW, out vec2 v_rgbNE,
out vec2 v_rgbSW, out vec2 v_rgbSE,
out vec2 v_rgbM) {
vec2 inverseVP = 1.0 / resolution.xy;
v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;
v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;
v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;
v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;
v_rgbM = vec2(fragCoord * inverseVP);
}

void main(void) {
//gl_Position = vec4(a_uv, 1.0, 1.0);
//gl_Position = vec4(a_position, 0.0, 1.0);
gl_Position = u_proj * vec4(a_position, 1.0, 1.0);

//compute the texture coords and send them to varyings
vec2 pos = a_position / u_resolution;
// vUv = (pos - 0.5) * 2.0;
// vUv.y = 1.0 - vUv.y;
vUv = a_uv;
//vUv = pos;
vec2 fragCoord = vUv * u_resolution;
texcoords(fragCoord, u_resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
}
2 changes: 2 additions & 0 deletions core/src/gl/framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class FrameBuffer {

void drawDebug(RenderState& _rs, glm::vec2 _dim);

auto& colorTexture() { return m_texture; }

private:

void init(RenderState& _rs);
Expand Down
65 changes: 65 additions & 0 deletions core/src/gl/fxaa.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "fxaa.h"

#include "fxaa_vs.h"
#include "fxaa_fs.h"

#include "glm/mat4x4.hpp"
#include "glm/gtc/matrix_transform.hpp"

namespace Tangram {

Fxaa::Fxaa() {

m_shader = std::make_unique<ShaderProgram>();

m_shader->setShaderSource(SHADER_SOURCE(fxaa_vs),
SHADER_SOURCE(fxaa_fs));

m_vertexLayout = std::unique_ptr<VertexLayout>(new VertexLayout({
{"a_position", 2, GL_FLOAT, false, 0},
{"a_uv", 2, GL_FLOAT, false, 0},}));

}

Fxaa::~Fxaa() {}

void Fxaa::draw(RenderState& _rs, Texture& _tex, glm::vec2 _dim) {

if (!m_shader->use(_rs)) { return; }

_rs.vertexBuffer(0);
_rs.depthTest(GL_FALSE);

float w = _tex.getWidth();
float h = _tex.getHeight();

if (_dim != glm::vec2(0)) {
w = _dim.x;
h = _dim.y;
}

glm::mat4 proj = glm::ortho(0.f, w, h, 0.f, -1.f, 1.f);
m_shader->setUniformf(_rs, m_uResolution, w, h);
m_shader->setUniformMatrix4f(_rs, m_uProj, proj);

glm::vec2 _pos(0);

glm::vec4 vertices[6] = {
{_pos.x, _pos.y, 0, 1},
{_pos.x, _pos.y + h, 0, 0},
{_pos.x + w, _pos.y, 1, 1},

{_pos.x + w, _pos.y, 1, 1},
{_pos.x, _pos.y + h, 0, 0},
{_pos.x + w, _pos.y + h, 1, 0},
};

_tex.bind(_rs, 0);

// enable the layout for the _polygon vertices
m_vertexLayout->enable(_rs, *m_shader, 0, (void*)vertices);

GL::drawArrays(GL_TRIANGLES, 0, 6);
}

}
29 changes: 29 additions & 0 deletions core/src/gl/fxaa.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include "gl/renderState.h"
#include "gl/shaderProgram.h"
#include "gl/texture.h"
#include "gl/vertexLayout.h"

namespace Tangram {

struct PostProcessEffect {
virtual void draw(RenderState& _rs, Texture& _tex, glm::vec2 _dim) = 0;
};

class Fxaa : PostProcessEffect {
public:

Fxaa();
~Fxaa();

void draw(RenderState& _rs, Texture& _tex, glm::vec2 _dim) override;

std::unique_ptr<ShaderProgram> m_shader;
std::unique_ptr<VertexLayout> m_vertexLayout;

UniformLocation m_uProj{"u_proj"};
UniformLocation m_uResolution{"u_resolution"};
};

}
35 changes: 33 additions & 2 deletions core/src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "gl.h"
#include "gl/glError.h"
#include "gl/framebuffer.h"
#include "gl/fxaa.h"
#include "gl/hardware.h"
#include "gl/primitives.h"
#include "gl/renderState.h"
Expand Down Expand Up @@ -85,6 +86,9 @@ class Map::Impl {
TileManager tileManager;
MarkerManager markerManager;
std::unique_ptr<FrameBuffer> selectionBuffer = std::make_unique<FrameBuffer>(0, 0);
std::unique_ptr<FrameBuffer> renderBuffer;
bool postProcess = true;
std::unique_ptr<Fxaa> postProcessFxaa = std::make_unique<Fxaa>();

bool cacheGlState = false;
float pickRadius = .5f;
Expand All @@ -94,6 +98,10 @@ class Map::Impl {
SceneReadyCallback onSceneReady = nullptr;
};

void Map::enablePostProcess(bool _enable) {
impl->postProcess = _enable;
}

void Map::Impl::setEase(EaseField _f, Ease _e) {
eases[static_cast<size_t>(_f)] = _e;
platform->requestRender();
Expand Down Expand Up @@ -176,6 +184,10 @@ void Map::Impl::setScene(std::shared_ptr<Scene>& _scene) {
if (animated != platform->isContinuousRendering()) {
platform->setContinuousRendering(animated);
}

if (postProcess) {
renderBuffer = std::make_unique<FrameBuffer>(view.getWidth(), view.getHeight(), false);
}
}

// NB: Not thread-safe. Must be called on the main/render thread!
Expand Down Expand Up @@ -369,6 +381,9 @@ void Map::resize(int _newWidth, int _newHeight) {
impl->view.setSize(_newWidth, _newHeight);

impl->selectionBuffer = std::make_unique<FrameBuffer>(_newWidth/2, _newHeight/2);
if (impl->postProcess) {
impl->renderBuffer = std::make_unique<FrameBuffer>(_newWidth, _newHeight);
}

Primitives::setResolution(impl->renderState, _newWidth, _newHeight);
}
Expand Down Expand Up @@ -522,8 +537,15 @@ void Map::render() {

// Setup default framebuffer for a new frame
glm::vec2 viewport(impl->view.getWidth(), impl->view.getHeight());
FrameBuffer::apply(impl->renderState, impl->renderState.defaultFrameBuffer(),
viewport, impl->scene->background().asIVec4());

if (impl->postProcess && !drawSelectionBuffer) {
impl->renderBuffer->applyAsRenderTarget(impl->renderState,
impl->scene->background().asIVec4());

} else {
FrameBuffer::apply(impl->renderState, impl->renderState.defaultFrameBuffer(),
viewport, impl->scene->background().asIVec4());
}

if (drawSelectionBuffer) {
impl->selectionBuffer->drawDebug(impl->renderState, viewport);
Expand Down Expand Up @@ -556,6 +578,15 @@ void Map::render() {
}
}

if (impl->postProcess) {
FrameBuffer::apply(impl->renderState, impl->renderState.defaultFrameBuffer(),
viewport, impl->scene->background().asIVec4());

if (impl->renderBuffer->colorTexture()) {
impl->postProcessFxaa->draw(impl->renderState, *impl->renderBuffer->colorTexture(), viewport);
}
}

impl->labels.drawDebug(impl->renderState, impl->view);

FrameInfo::draw(impl->renderState, impl->view, impl->tileManager);
Expand Down
7 changes: 6 additions & 1 deletion platforms/common/glfwApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Tangram::MarkerID poiMarker = 0;
Tangram::MarkerID polyline = 0;

bool keepRunning = true;
bool postProcessOn = true;

void loadSceneFile(bool setPosition = false) {
std::vector<SceneUpdate> updates;
Expand Down Expand Up @@ -127,7 +128,7 @@ void create(std::shared_ptr<Platform> p, int w, int h) {
}

// Create a windowed mode window and its OpenGL context
glfwWindowHint(GLFW_SAMPLES, 2);
//glfwWindowHint(GLFW_SAMPLES, 2);
if (!main_window) {
main_window = glfwCreateWindow(width, height, "Tangram ES", NULL, NULL);
}
Expand Down Expand Up @@ -364,6 +365,10 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods

if (action == GLFW_PRESS) {
switch (key) {
case GLFW_KEY_0:
postProcessOn = !postProcessOn;
map->enablePostProcess(postProcessOn);
break;
case GLFW_KEY_1:
Tangram::toggleDebugFlag(Tangram::DebugFlags::freeze_tiles);
break;
Expand Down