From f92262fdc1e3166c106a35a1552f7d689d55b527 Mon Sep 17 00:00:00 2001 From: Victor Coda Date: Mon, 5 Oct 2020 03:37:50 +0300 Subject: [PATCH] Described Gaussian blur sample --- README.md | 6 ++++++ screenshots/blur-gaussian.jpg | Bin 0 -> 221336 bytes 2 files changed, 6 insertions(+) create mode 100644 screenshots/blur-gaussian.jpg diff --git a/README.md b/README.md index 3b5b2d5..42059b7 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,12 @@ Vertex texture fetch was first instroduced by NVIDIA with [Shader Model 3.0](htt This demo shows two useful applications of a geometry shader. First, it allows to draw wireframe meshes without using line rasterization primitive. Instead, geometry shader is inserted between vertex and fragment stages to supply additional barycentric attribute for each triangle's vertex. Interpolated barycentric values are used to calculate distance from current fragment to the triangle edge and use it as color alpha in normal blending. In this way we can render mesh in wireframe mode with superior quality without MSAA enabled. Second, geometry shader can be utilized to visualize normals and tangents. For this, geometry shader accepts triangle as input primitive but outputs line strip primitive. For each triangle we consider only the first vertex. Simply adding normal vector to vertex's coordinate, we can define endpoint of the line. In this demo vertex buffer doesn't provide tangent vectors, so I computed them directly in the geometry shader using input positions and texture coordinates. +### [Gaussian blur](blur-gaussian/) + + +Gaussian blur is a widely used technique in the domain of computer graphics and many rendering techniques rely on it in order to produce convincing photorealistic effects. +The image space Gaussian filter is an NxN-tap convolution filter that weights the pixels inside of its footprint based on the [Gaussian function](https://en.wikipedia.org/wiki/Normal_distribution). While using two-dimensional filter kernel in fragment shader is straitforward, it is inefficient due to enormous number of texture fetched required to blur whole image. Fortunately, the 2-dimensional Gaussian function can be calculated by multiplying two 1-dimensional Gaussian function. That means that we can separate our Gaussian filter into a horizontal blur pass and the vertical blur pass, still getting the accurate results. In this demo I precomputed Gaussian weights, so fragment shader became a simple cycle of weighted texture fetches with final normalization. + ### [Edge detection](edge-detection/) diff --git a/screenshots/blur-gaussian.jpg b/screenshots/blur-gaussian.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9f2676a7ffe091bb1494b564f841c525388aaeb6 GIT binary patch literal 221336 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 literal 0 HcmV?d00001