https://gpuopen.com/learn/bilinear-interpolation-quadrilateral-barycentric-coordinates/ [CHIP_AMD_GPUOpen_Lockup_RGB_White_400px] Search [ ] Search Zhihu Youtube Twitter Mastodon Rss HOME SOFTWARE DOCS AMD FidelityFX AMD FidelityFXAMD FidelityFX * Meet the AMD FidelityFX SDK * Super Resolution 1 (FSR 1) * Super Resolution 2 (FSR 2) * Super Resolution 3 (FSR 3) * Breadcrumbs library * Brixelizer & Brixelizer GI * Contrast Adaptive Sharpening * Ambient Occlusion * Screen Space Reflections * Denoiser * Lens * Blur * Depth of Field * Downsampler * HDR Mapper * Variable Shading * Parallel Sort * Naming guidelines * Developer testimonials * Other - TressFX Radeon Developer Tool SuiteRadeon Developer Tool Suite Radeon Developer Tool SuiteRadeon Developer Tool Suite * Meet all our tools * Radeon(tm) GPU Detective * Radeon(tm) Raytracing Analyzer * Radeon(tm) GPU Profiler * Radeon(tm) GPU Analyzer * Radeon(tm) Memory Visualizer * Radeon(tm) Developer Panel * Other - Frame Latency Meter * Other - GPU Reshape * Other - Compressonator * Other - OCAT Engines and APIs Engines and APIs * Our support for engines and APIs * Unreal Engine * Unity * Vulkan(r) * DirectX(r)12 * DirectX(r)12 Ultimate Hybrid RT and samples Hybrid RT and samples * Meet all our samples * Hybrid Shadows * Hybrid Stochastic Reflections * Cauldron glTF sample Our SDKs and libraries Our SDKs and libraries * Meet all our SDKs * AMD GPU Services * Anti-Lag 2 SDK * Vulkan(r) Memory Allocator * Direct3D(r)12 Memory Allocator * Dense Geometry Format * Streaming SDK * AMD Schola (Unreal NPCs) * Render Pipeline Shaders * Brotli-G SDK * AMD Device Library eXtra * Advanced Media Framework * Cauldron framework (FidelityFX) * GPU Performance API [svg][RadeonProRender_menu] * Radeon(tm) ProRender suite * Radeon(tm) ProRender SDK * Radeon(tm) Rays * Radeon(tm) ML * Radeon(tm) Image Filtering * GPUOpen MaterialX Library Content creation Content creation * Advanced Rendering Research * HIP Ray Tracing * Orochi * Capsaicin framework (GI-1.1) Blogs and videos Blogs and videos * Meet all our blogs * GPUOpen software blogs * Technical blogs * Guest developer blogs * Videos Performance guides Performance guides * All performance guides * AMD RDNA(tm) Performance Guide * AMD Ryzen(tm) Performance Guide * Unreal Engine Performance Guide Reference Reference * Reference documenation * Manuals * Presentations * AMD GPU arch programming documentation * Radeon(tm) Vulkan(r) Drivers version table Latest news Latest news * Latest news from GPUOpen * Software release blogs * AMD FSR 3 at GDC 2024 * AMD FSR 3 at GDC 2024 deck * Mesh shaders in AMD RDNA 3 Architecture Events Events * Events * GDC 2024 * Earlier GDC events * Digital Dragons * SIGGRAPH * Let's build... (our virtual event) Research Research * Our publications * Advanced Rendering Research Group * AMD Lab Notes (HPC) Getting started with: Getting started with: * Our software on GPUOpen * Graphics and AMD hardware * Our tools * Our SDKs and libraries * Our effects * Content creation * Optimizing and performance * Developing Vulkan(r) applications * Developing DirectX(r)12 applications * Using the FSR 1 Unreal Engine 4 plugin * Using the FSR 2 Unreal Engine 4/5 plugin * Using the FSR 3 Unreal Engine 5 plugin * Mesh Shaders * AI NPCs in Unreal Engine * Work Graphs Site directory Home >> Blogs >> Bilinear interpolation on a quadrilateral using Barycentric coordinates Bilinear interpolation on a quadrilateral using Barycentric coordinates Picture of Lukasz IzdebskiPicture of Lukasz Izdebski Lukasz Izdebski Lukasz Izdebski, PhD, is a Developer Technology Engineer at AMD's Game Engineering, focusing on optimization of game engine rendering features. His research interests include animation, geometry modelling, and differential geometry. * Originally posted April 11, 2025 In computer graphics, we rarely encounter continuous data. We often work with digital data, and in the context of geometric modeling, this means we typically work with polygon meshes rather than procedural surfaces like Bezier patches. The most popular technique for constructing digital three-dimensional objects in dedicated modeling software is polygon modeling. The result of the creation phase is a set of polygons (mesh), where the polygons in the mesh can share vertices and edges with other polygons. Although users can create various types of surfaces (e.g., non-manifold), the most common surface is the topological 2-manifold. In short, a 2-manifold is a mathematical concept in topology, where the space locally resembles the Euclidean plane in \mathbb{R}^2. Essentially, every point on a 2-manifold has a neighborhood that looks like a piece of the plane. Examples of 2-manifold mesh Examples of 2-manifold mesh triangle-based quad-based _images/triangle_mesh1.png_images _images/triangle_mesh2.png_images /triangle_mesh1.png /triangle_mesh2.png At the vertices of a polygon, users can store additional data (per-vertex attributes), such as vertex normals (for simulating curved surfaces), texture coordinates (for texture mapping), or RGBA color. In theory, all types of polygons can be used. In practice, however, 3D graphics artists most commonly use triangles and quadrilaterals. These polygons are typically referred to as topology primitives in computer graphics APIs (such as Microsoft DirectX(r) or Vulkan(r)). From an artist's point of view, quadrilaterals are more advantageous because they are easier to work with. The properties of modeling based on quadrilaterals include: * The ease of generating grid-like surfaces. * Creating a topology that provides an edge flow that can be easily adjusted (when adding or deleting edge loops). * Producing a predictable result for subdivision algorithms. not clean looking mesh clean looking mesh _images/topo_bad.png_images/ _images/topo_good.png_images/ topo_bad.png topo_good.png * The quad-based topology also provides cleaner deformations for models that will be animated. These arguments make the quadrilateral-based topology preferred by artists when modeling 3D objects. Long ago, GPUs abandoned support for hardware accelerated quadrilaterals (or polygons consisting of more than 4 vertices) rasterization, therefore also interpolation of vertex attributes contained in their vertices (line rendering is for a different story). The only polygon that has hardware accelerated implementation of rasterization and interpolation of parameters is the triangle. There are very good reasons why it was the triangle that won the race I just name a few: * Triangulation Theorem: This theorem states that a mesh of triangles can approximate even complex surfaces. * Triangle vertices always lie on the same plane: This is due to the fact that any three non-collinear points will always define a plane in three-dimensional space. * Barycentric Coordinates: This coordinate system is used in geometry to express the position of a point within a triangle. These coordinates can be used for interpolation of vertex attributes across the surface of a triangle. * Less complexity of the circuit: Supporting rasterization and interpolation for triangles only requires fewer transistors, which means this functionality occupies less space on the chip. This can result in a smaller (and cheaper to produce) chip, or the saved space can be used for other functionalities. Triangles are the foundation of real-time computer graphics, as reflected in the primitive topology supported by graphics APIs. All other polygon types used in meshes must be converted into triangles. When a modeling application allows quad-mesh construction, the visualization of this mesh is not based on quadrilaterals. Instead, the application converts them into triangle meshes. This necessary conversion can introduce C^1 discontinuities in interpolated vertex attributes (such as texture coordinates, vertex normal vectors, and vertex colors) on the quadrilateral surface. In the case of the topic covered in this article, the discontinuity of C^1 refers to the point at which the piecewise function is continuous, but its first derivative is not. In other words, the piecewise function itself has no jumps or breaks, but the slope (or rate of change) of the piecewise function has jumps or breaks. C^1 continuity C^1 discontinuity piecewise _images/C0_con.png_images/ _images/C0_dis.png_images/ function C0_con.png C0_dis.png first _images/C1_con.png_images/ _images/C1_dis.png_images/ derivative C1_con.png C1_dis.png For rasterization of quadrilaterals as two triangles, C^1 discontinuity in the interpolation of vertex attributes is most visible along the newly created edge that splits the quadrilateral into two triangles. Vertex Color Texture Coordinates Vertex Normal _images/1.png_images/ _images/3.png_images/ _images/5.png_images/ 1.png 3.png 5.png _images/trapez1.gif _images/trapez2.gif _images/trapez3.gif _images/trapez1.gif _images/trapez2.gif _images/trapez3.gif _images/tea1.gif _images/tea2.gif _images/tea3.gif _images/tea1.gif _images/tea2.gif _images/tea3.gif Purpose The purpose of this article is to propose a new method that preserves C^1 continuity over the common edge of two generated triangles from convex quadrilaterals. This new method is based on an algebraic solution for the Bilinear interpolation coefficient expressed in Barycentric coordinates. Bilinear interpolation has the advantage of being the simplest interpolation from an algebraic perspective. Consequently, the computational overhead is negligibly small. Additionally, linear interpolation allows for the easy construction of other types of interpolation, such as polynomial interpolation. The algebraic solution will then be implemented and tested using the three available hardware-accelerated pipelines supported by GPU hardware. State of the Art Currently, efforts to address the problem outlined in this article can be categorized into the following approaches: Quadrilateral subdivision The first approach is not to eliminate the issue but to minimize it. This is achieved by subdividing the quadrilateral until rendering artifacts become imperceptible to the observer or are less noticeable than the aliasing artifacts created during rasterization. Quadrilateral subdivision can be performed dynamically (at application runtime) using a hardware-accelerated Tessellation Shaders stage. Tessellation Tessellation Tessellation Tessellation Tessellation level 1 level 2 level 3 level 4 level 5 _images/ _images/ _images/ _images/ _images/ Sub1.png_images Sub2.png_images Sub3.png_images Sub4.png_images Sub5.png_images /Sub1.png /Sub2.png /Sub3.png /Sub4.png /Sub5.png Alternatively, quadrilateral subdivision can be performed statically (during the content creation phase) using dedicated tools provided by modeling software, such as the Blender(r) Subdivision Surface Modifier. Mesh in Blender before usage of Mesh in Blender after usage of Subdivision Surface Modifier Subdivision Surface Modifier _images/Catmull_OFF2.png_images/ _images/Catmull_ON2.png_images/ Catmull_OFF2.png Catmull_ON2.png Subdividing meshes (at application runtime or not) effectively reduces the visibility of all types of C^1 discontinuities to the observer, but at the expense of decreasing performance and/or increasing memory overhead in the mesh rendering process. Mean value coordinates A different attempt to solve the problem was offered in the article A quadrilateral rendering primitive, where the authors proposed hardware-accelerated quadrilateral rasterization. For vertex attribute interpolation inside quadrilaterals (which may be non-planar), the authors chose to use mean value coordinates. However, these coordinates yield results similar to those of bilinear interpolation. The following caveats can be pointed out: * In the calculation of mean value coordinates, transcendental functions are used. The values of these functions can be determined with predetermined precision. However, from a performance perspective, they introduce a certain overhead, depending on the hardware implementation of the calculation of transcendental functions. * Mean value coordinates interpolation does not generate straight lines, which might not be desirable for users. This hardware solution has not yet been implemented using the GPU (at the time of writing this article). However, the authors of Barycentric quad rasterization attempted to implement it using the Geometry Shader pipeline available in modern GPUs. The presented implementation has a disadvantage: it uses double-precision floating-point variables, which significantly impact performance overhead. GPUs for real-time rendering are primarily designed to support single-precision floating-point calculations. Fragment Shader calculation Other authors, such as Inigo Quilez inverse bilinear interpolation - 2010 and Nathan Reed Quadrilateral Interpolation, Part 2, have observed the advantages of bilinear interpolation and proposed solutions through implementations using the Fragment Shader. The presented solutions demonstrate the implementation of bilinear interpolation for quadrilaterals, but they only show how to do it for a single quadrilateral and for its texture coordinate vertex attribute. They do not address how to apply it in real-life three-dimensional mesh models. Proposition of the New Method The method presented in the article consists of an equation that can express Bilinear interpolation coefficients u, v using Barycentric coordinates \alpha, \beta, \gamma of one of the two triangles into which each convex quadrilateral can be divided. The Euclidean coordinates of every point P in a given quadrilateral on the plane can be expressed as a Bilinear interpolation of the Euclidean coordinates of its vertices. The line segment AB is parameterized as E(u)=A + u(B-A), , u \in[0,1] , the line segment DC is parameterized as F(u)=D + u(C-D), , u \in[0,1] , the line segment DA is parameterized as G(v)=A + v(D-A), , v \in[0,1] , the line segment BC is parameterized as H(v)=G + v(H-G), , v \in[0,1] . The point P is the intersection of the two segments E(u)F(u) and G(v) H(v). Alternatively, the Euclidean coordinates of point P can be expressed as a Barycentric coordinates of a triangle ABD \ P = \alpha A + \beta B + \gamma D where \alpha,\beta,\gamma are positive real numbers such that \alpha + \beta + \gamma = 1.. This can be shown geometrically in two-dimensional space. Bilinear interpolation inside Barycentric interpolation inside quadrilateral ABCD triangle ABD _images/interpolation1.png_images _images/interpolation2.png_images /interpolation1.png /interpolation2.png The Euclidean coordinates of point P are the same whether it is inside the quadrilateral ABCD or the triangle ABC. Depending on the Euclidean coordinates of point P, it may lie inside triangle ABC or triangle ACD. There is a system of equations that describe the coordinates of point P using the vertices of quadrilateral ABCD and the Bilinear interpolation coefficients u,v, as well as the vertices of triangles ABC or ACD and the Barycentric coordinates for the same point P. The coordinates of point P in \mathbb{R}^2 can be calculated using Barycentric coordinates \alpha, \beta, \gamma and Bilinear interpolation coefficients u and v, which can be expressed by the following two independent set of equations: The coordinates of point P in \mathbb{R}^2 can be calculated using Barycentric coordinates \alpha, \beta, \gamma and Bilinear interpolation coefficients u and v, which can be expressed by the following two independent sets of equations: \begin{cases} A_x + v(D_x - A_x) = G_x \\ A_y + v(D_y - A_y) = G_y \\ B_x + v(C_x - B_x) = H_x \\ B_y + v(C_y - B_y) = H_y \\ G_x + s(H_x - G_x) = P_x \\ G_y + s(H_y - G_y) = P_y \\ \alpha A_x + \beta B_x + \ gamma D_x = P_x \\ \alpha A_y + \beta B_y + \gamma D_y = P_y \\ \end {cases} \newline \newline \begin{cases} A_x + u(B_x - A_x) = E_x \\ A_y + u(B_y - A_y) = E_y \\ D_x + u(C_x - D_x) = F_x \\ D_y + u(C_y - D_y) = F_y \\ E_x + t(F_x - E_x) = P_x \\ E_y + t(F_x - E_y) = P_y \\ \alpha A_x + \beta B_x + \gamma D_x = P_x \\ \alpha A_y + \beta B_y + \gamma D_y = P_y \\ \end{cases} The equations can be reduced to the form: \begin{cases} A_x + u(B_x - A_x) + s(D_x + u(C_x - D_x) - A_x - u(B_x - A_x)) = \alpha A_x + \beta B_x + \gamma D_x \\ A_y + u(B_y - A_y) + s(D_y + u(C_y - D_y) - A_y - u(B_y - A_y)) = \alpha A_y + \beta B_y + \gamma D_y \\ \end{cases} \newline \newline \begin{cases} A_x + v(D_x - A_x) + t(B_x + v(C_x - B_x) - A_x - v(D_x - A_x)) = \alpha A_x + \ beta B_x + \gamma D_x \\ A_y + v(D_y - A_y) + t(B_y + v(C_y - B_y) - A_y - v(D_y - A_y)) = \alpha A_y + \beta B_y + \gamma D_y \\ \end {cases} We can further simplify using: \begin{cases} \vec{P} = D-A \\ \vec{R} = B-A \\ \vec{Q} = C-B-D+A \\ \alpha = (1-\beta-\gamma) \\ \end{cases} to a two-system of equations: \begin{cases} u\vec{R}_x + s(\vec{P}_x + u\vec{Q}_x) = \beta \vec{R} _x + \gamma \vec{P}_x \\ u\vec{R}_y + s(\vec{P}_y + u\vec{Q}_y) = \ beta \vec{R}_y + \gamma \vec{P}_y \\ \end{cases} \newline \newline \ begin{cases} v\vec{P}_x + t(\vec{R}_x + v\vec{Q}_x) = \beta \vec{R}_x + \gamma \vec{P}_x \\ v\vec{P}_y + t(\vec{R}_y + v\vec{Q}_y) = \beta \vec{R}_y + \gamma \vec{P}_y \\ \end{cases} Now, solving the two systems of equations for u and v leads to the problem of solving two quadratic equations: \begin{cases} u^2(\vec{R}_x\vec{Q}_y - \vec{Q}_x\vec{R}_y) + u(\vec {R}_x\vec{P}_y - \vec{P}_x\vec{R}_y + \beta(\vec{Q}_x\vec{R}_y-\vec {R}_x\vec{Q}_y) + \gamma (\vec{Q}_x\vec{P}_y-\vec{P}_x\vec{Q}_y)) - \ \ \beta(\vec{P}_x\vec{R}_y-\vec{R}_x\vec{P}_y) = 0\\ \end{cases} \ newline \newline \begin{cases} v^2(\vec{P}_x\vec{Q}_y - \vec{Q}_x\vec {P}_y) + v(\vec{P}_x\vec{R}_y - \vec{R}_x\vec{P}_y + \beta(\vec{Q}_x\ vec{R}_y-\vec{R}_x\vec{Q}_y) + \gamma(\vec{Q}_x\vec{P}_y-\vec{P}_x\ vec{Q}_y)) - \\ \gamma(\vec{R}_x\vec{P}_y-\vec{P}_x\vec{R}_y) = 0\\ \ end{cases} Embedding this solution in \mathbb{R}^3 at the plane z=0 with the surface normal vector for a triangle \vec{N} = (0,0,1), the equation can be written as: u^2 \vec{N}\cdot(\vec{R}\times \vec{Q}) + u(\vec{N}\cdot(\vec{R}\ times \vec{P}) + \beta \vec{N}\cdot(\vec{Q}\times \vec{R}) + \gamma \ vec{N}\cdot(\vec{Q}\times \vec{P})) + \beta \vec{N}\cdot(\vec{P}\ times \vec{R}) = 0 \newline \newline v^2 \vec{N}\cdot(\vec{P}\times \ vec{Q}) + v(\vec{N}\cdot(\vec{P}\times \vec{R}) + \beta \vec{N}\cdot (\vec{Q}\times \vec{R}) + \gamma \vec{N}\cdot(\vec{Q}\times \vec{P})) - \gamma \vec{N}\cdot(\vec{R}\times \vec{P}) = 0 where \times is the cross product in \mathbb{R}^3 and \cdot is the dot product in \mathbb{R}^3. Substituting the triple dot product into the equation: \begin{cases} A_u = \vec{N}\cdot(\vec{R}\times \vec{Q}) \\ A_v = \vec {N}\cdot(\vec{P}\times \vec{Q}) \\ B = \vec{N}\cdot(\vec{P}\times \ vec{R}) \\ \end{cases} the final two equations are as follows: u^2 A_u - u(\beta A_u + \gamma A_v + B) + \beta B = 0 \\ v^2 A_v - v (\beta A_u + \gamma A_v - B) - \gamma B = 0 \\ The last step is to solve these two quadratic equations for the parameters u and v. The equation can be used to calculate bilinear interpolation coefficients u and v for any quadrilateral in three-dimensional space. This is because if a quadrilateral is embedded in any plane in \mathbb{R}^3, it can be transformed isometrically to the plane z=0, and the premise still holds after isometric mapping. It is worth noting that the above equations show that the bilinear interpolation coefficients u and v depend on all four Euclidean coordinates of the vertices in the quadrilateral. If we are dealing with static meshes, these coefficients can be calculated in advance (this is not necessary at runtime). However, if we are working with dynamic (animated) meshes, it is necessary to calculate these coefficients at runtime. Therefore, we need to use a Graphics Pipeline stage where we still have access to all four positions of the vertices of the quadrilateral. Parallelograms When rendering quadrilaterals limited to parallelograms, the solution is much simpler because \vec{Q} = \vec{0}. This fact can be deduced after a quick analysis. Vector \vec{Q} is described as \vec{Q} = (C - B) + (A - D). In parallelograms, the vector from the first parenthesis \vec{C - B}, by definition, has the same length as the vector \vec{A - D} but in the opposite direction. Thus, the sum of these vectors is always the zero vector. Therefore, when \vec{Q} = \vec{0}, we are no longer dealing with a quadratic equation, but with a linear equation, making the solution much simpler: u = \beta \\ v = \gamma \\ This simpler case has already been described, and the solution can be found in How to Correctly Interpolate Vertex Attributes on a Parallelogram Using Modern GPUs?. Hardware-accelerated implementation The hardware-accelerated implementation of the algebraic solution presented in the previous section can be achieved using three different Graphics Pipeline stages: Geometry Shader, Tessellation Shader, and Mesh Shader. This three-way implementation demonstrates that the technique is feasible on GPU hardware released as far back as 2008. The following source code uses the GLSL shading language. The table below describes what API versions and extensions are necessary to implement the presented technique: Vulkan(r) DirectX(r) OpenGL(r) Geometry Vulkan(r) geometry DirectX(r) OpenGL(r) 3.2 Shader Shader feature enabled 10 Tessellation Vulkan(r) tessellation DirectX(r) OpenGL(r) 4 Shader Shader feature enabled 11 Vulkan(r) DirectX(r) OpenGL(r) 4 Mesh Shader VK_EXT_mesh_shader 12 GL_NV_mesh_shader extension enabled Ultimate extension enabled The implementation of the presented method requires Barycentric coordinates of the currently processed fragment in the Fragment Shader. This is possible when the following extensions are available: * Vulkan(r) VK_KHR_fragment_shader_barycentric extension. * DirectX(r) 12 Shader Model 6.1. * OpenGL(r) 4 GL_NV_fragment_shader_barycentric or GL_AMD_shader_explicit_vertex_parameter. If the GPU does not support the above extension, there is a way to generate them in the Geometry, Tessellation, or Mesh Shader stage. The implementation of the new method presented in this article can be divided into the following steps: 1. Delivering Quadrilateral Primitives to the Graphics Pipeline. Quadrilateral primitives are not available in modern graphics APIs (excluding the legacy OpenGL GL_QUADS and GL_QUAD_STRIP primitive types). To support quadrilateral-like primitives, use the following methods: + Geometry Shader: With the Geometry Shader stage, adjacency primitives can be used to mimic quadrilateral primitives: o OpenGL(r) GL_LINES_ADJACENCY o Vulkan(r) VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY o DirectX(r) 12/11 D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ + With Tessellation stages, a new Patch primitive was introduced. In this topology, the number of vertices defined in the meshes is not fixed, but the so-called Control Points range from 1 to 32 per Patch. These Control Points can be treated as Control Points of Bezier patches, but they can also be treated as vertices of a polygon. The implementation of the solution presented in this article uses a Patch with 4 Control Points and treats them as vertices of a quadrilateral. + Mesh Shader: Using Mesh Shaders, there are many ways to introduce a quadrilateral primitive into the Graphics Pipeline. This stage was developed to provide more flexibility to the user. Therefore, it is up to the user to generate meshlets that will contain quadrilaterals in some way (this is not within the scope of this article). 2. The next step is to calculate the constants A_u, A_v, B (using one of the steps above), which will then be used in the Fragment Shader. We need to calculate these constants in one of the above pipeline stages because, in the Fragment Shader, we do not have access to the four attributes of the quadrilateral vertices (the Barycentric coordinate extension, if present, only gives us access to the three attributes of the triangle vertices). By analyzing the algebraic solution of the presented method, we can see that these constants depend on the positions of the vertices of the quadrilateral. The following function needs to be executed in the Geometry Shader, Tessellation Evaluation Shader, or Mesh Shader. Copied! vec3 calculateConstants(vec3 v0, vec3 v1, vec3 v2, vec3 v3) { const vec3 v10 = v1 - v0; const vec3 v30 = v3 - v0; const vec3 crossv10v30 = cross(v10, v30); const vec3 n = normalize(crossv10v30); const vec3 d = v0 - v1 + v2 - v3; float A_u = dot(n, cross(d, v30)); float A_v = dot(n, cross(d, v10)); const float B = dot(n, crossv10v30); A_u = abs(A_u) < 0.00001 ? 0.0 : A_u; A_v = abs(A_v) < 0.00001 ? 0.0 : A_v; return vec3(A_u, A_v, B); } Where v0, v1, v2, v3 are the Euclidean coordinates of the quadrilateral vertices in the following order: _images/Picture6a.png_images/Picture6a.png The calculated values of A_u, A_v and B are then passed to the Fragment Shader. 2. Passing vertex attributes to the Fragment Shader. For Bilinear interpolation to work in a Fragment Shader, we need to be able to fetch all four vertex attributes (such as texture coordinates, vertex normal, and vertex color) in it. * If the Barycentric coordinate extension is available, we have access to three of these attributes, so another stage must export the missing vertex attribute of the quadrilateral. The following code can be used in the Fragment Shader: Copied! layout (location = 0) pervertexEXT in block { vec3 Normal; flat vec3 NormalExtra; vec2 Texcoord; flat vec2 TexcoordExtra; vec4 Color; flat vec4 ColorExtra; flat vec3 BaryConstants; } In[]; * If the Barycentric coordinate extension is not available, all four vertex attributes need to be exported as a four-element array, with a variable calculated to imitate the Barycentric Coordinate. The following code can be used in the Fragment Shader: Copied! layout(location = 0) in block { flat vec3 Normal[4]; flat vec2 Texcoord[4]; flat vec4 Color[4]; flat vec3 BaryConstants; vec3 BarycentricCoordinate; } In; 3. Orders of Barycentric coordinates in the triangles formed when dividing the quadrilateral. When using Barycentric coordinates for interpolation of vertex attributes, the order in which they are defined in the triangle doesn't matter. However, in the implementation method described in this article, the specific order is important. This order can be visually represented as follows: _images/geom_bary3.png_images/geom_bary3.png Where red color represents the influence of the \alpha Barycentric coordinate, green represents \beta, and blue represents \gamma. This order of Barycentric coordinates can be supplied by hardware when the proper extension is available, or these data can be generated in the Tessellation or Geometry Shader stage. 4. Calculate u, v Bilinear coefficients. In the Fragment Shader, the calculation of Bilinear interpolation coefficients u and v can be done by calling the following function. Copied! vec2 calculateBilinear(float beta, float gamma, float A_u, float A_v, float B) { const float B_u = B; const float B_v = -B; const float B2 = beta * A_v + gamma * A_u; const float t_u = B_u - B2; const float t_v = B_v - B2; const float b_u = t_u / A_u * 0.5; const float b_v = t_v / A_v * 0.5; const float c_u = gamma * B_v; const float c_v = beta * B_u; const float d_u = b_u * b_u - c_u / A_u; const float d_v = b_v * b_v - c_v / A_v; const float s_u = A_u >= 0.0 ? -1.0 : 1.0; const float s_v = A_v >= 0.0 ? 1.0 : -1.0; const float u = A_u != 0.0 ? (-b_u - s_u * sqrt(d_u)) : (-c_u / t_u); const float v = A_v != 0.0 ? (-b_v - s_v * sqrt(d_v)) : (-c_v / t_v); return vec2(u, v); } Where beta is \beta Barycentric coordinate, gamma is \gamma Barycentric coordinate, A_u, A_v, B are constants calculated in previous Graphics Pipeline Stage. 5. Bilinear interpolation of vertices attributes. When Bilinear interpolation coefficients u and v are calculated, the interpolation of vertex attributes can be achieved using functions. Copied! vec4 interpolateBilinear(vec4 v0, vec4 v1, vec4 v2, vec4 v3, vec2 uv) { return mix(mix(v0, v1, uv.y), mix(v2, v3, uv.y), uv.x); } vec3 interpolateBilinear(vec3 v0, vec3 v1, vec3 v2, vec3 v3, vec2 uv) { return mix(mix(v0, v1, uv.y), mix(v2, v3, uv.y), uv.x); } vec2 interpolateBilinear(vec2 v0, vec2 v1, vec2 v2, vec2 v3, vec2 uv) { return mix(mix(v0, v1, uv.y), mix(v2, v3, uv.y), uv.x); } float interpolateBilinear(float v0, float v1, float v2, float v3, vec2 uv) { return mix(mix(v0, v1, uv.y), mix(v2, v3, uv.y), uv.x); } Where v0, v1, v2, v3 are the quadrilateral vertex attributes. Parallelograms For quadrilaterals, which are restricted to parallelograms, implementing the technique described in this article is even simpler. * In the Tessellation Shader, Geometry Shader, or Mesh Shader stage, when data for four vertex attributes is still available, one extra constant data (per attribute) needs to be calculated. Copied! vec4 calculateConstants(vec4 A, vec4 B, vec4 C, vec4 D) { return A - B + C - D; } vec3 calculateConstants(vec3 A, vec3 B, vec3 C, vec3 D) { return A - B + C - D; } vec2 calculateConstants(vec2 A, vec2 B, vec2 C, vec2 D) { return A - B + C - D; } float calculateConstants(float A, float B, float C, float D) { return A - B + C - D; } Where A, B, C, D are vertex attributes arranged as specified. The calculated value for each vertex attribute needs to be passed to the Fragment Shader. * In Fragment Shader, the following. Copied! vec4 interpolateBilinear(vec4 attribute, vec2 barycentric, vec4 extraVal) { return attribute + barycentric.x * barycentric.y * extraVal; } vec3 interpolateBilinear(vec3 attribute, vec2 barycentric, vec3 extraVal) { return attribute + barycentric.x * barycentric.y * extraVal; } vec2 interpolateBilinear(vec2 attribute, vec2 barycentric, vec2 extraVal) { return attribute + barycentric.x * barycentric.y * extraVal; } float interpolateBilinear(float attribute, vec2 barycentric, float extraVal) { return attribute + barycentric.x * barycentric.y * extraVal; } Where attribute represents a value interpolated by traditional Barycentric interpolation (available in the Fragment Shader), barycentric is a vec2 data type containing the fragments' \beta and \ gamma Barycentric coordinates, and extra is a constant calculated in the previous Geometry, Tessellation, Mesh Shader stage. Results The output of the algebraic solution presented in this article remains consistent across different implementations. Depending on the type of vertex attributes, the results can be summarized in the following table. Vertex Bilinear interpolation using Attribute Barycentric interpolation the solution presented in the article Color _images/1.png_images/1.png _images/2.png_images/2.png Texture _images/3.png_images/3.png _images/4.png_images/4.png coordinate Normal _images/5.png_images/5.png _images/6.png_images/6.png Color _images/trapez1.gif_images/ _images/trapez1a.gif_images trapez1.gif /trapez1a.gif Texture _images/trapez2.gif_images/ _images/trapez2a.gif_images coordinate trapez2.gif /trapez2a.gif Normal _images/trapez3.gif_images/ _images/trapez3a.gif_images trapez3.gif /trapez3a.gif Color _images/tea1.gif_images/ _images/tea1a.gif_images/ tea1.gif tea1a.gif Texture _images/tea2.gif_images/ _images/tea2a.gif_images/ coordinate tea2.gif tea2a.gif Normal _images/tea3.gif_images/ _images/tea3a.gif_images/ tea3.gif tea3a.gif Mesh Example _images/Picture1.png_images _images/Picture2.png_images /Picture1.png /Picture2.png Animation _images/anim1.gif_images/ _images/anim1a.gif_images/ Example anim1.gif anim1a.gif Summary As presented in this article, the algebraic solution for Bilinear interpolation using Barycentric coordinates can be implemented through APIs such as Vulkan(r) or DirectX(r). This implementation leverages hardware-accelerated rendering on GPUs. The paper proposes three different implementations based on the available Graphics Pipeline supported by the GPU. These implementations enable the use of the new method on GPUs (both PCs and mobile devices) ranging from models released in 2008 to the latest versions. Blender is a registered trademark of the Blender Foundation in EU and USA. DirectX is a registered trademark of Microsoft Corporation in the US and other jurisdictions. OpenGL(r) and the oval logo are trademarks or registered trademarks of Hewlett Packard Enterprise in the United States and/or other countries worldwide. Vulkan and the Vulkan logo are registered trademarks of the Khronos Group Inc. Picture of Lukasz IzdebskiPicture of Lukasz Izdebski Lukasz Izdebski Lukasz Izdebski, PhD, is a Developer Technology Engineer at AMD's Game Engineering, focusing on optimization of game engine rendering features. His research interests include animation, geometry modelling, and differential geometry. Related content [svg][featured_dx12_ultimate-768x420] New DirectX(r) + video encoding features with AgilitySDK Preview Release 1.716.0 We now support new Microsoft(r) DirectX(r) and video encoding features, with the latest release of the AgilitySDK Preview Release 1.716.0. GPU Reshape - Modern Shader Instrumentation and Instruction Level Validation - Digital DragonsGPU Reshape - Modern Shader Instrumentation and Instruction Level Validation - Digital Dragons GPU Reshape - Modern Shader Instrumentation and Instruction Level Validation (Digital Dragons 2024) - YouTube link GPU Reshape is, a just-in-time instrumentation framework with instruction level validation of shaders. A deep dive into current validation methodologies, and what the future of instrumentation may hold. Digital Dragons - Mesh Shaders - Learning ExamplesDigital Dragons - Mesh Shaders - Learning Examples Mesh Shaders - Learning Through Examples (Digital Dragons 2024) - YouTube link Learn about the new Mesh Shader pipeline which can help to create even more better-looking games. Fractal image from Work Graph PlaygroundFractal image from Work Graph Playground Work Graph Playground: a learning framework for GPU Work Graphs Read about our latest sample for D3D12 GPU Work Graphs. We're making Work Graphs more accessible with a tutorial framework. AMD FSR 3AMD FSR 3 Microsoft(r) DirectSR has integrated AMD FidelityFX(tm) Super Resolution 3.1 This integration enhances upscaling capabilities, offering improved temporal stability and detail preservation. [svg][vulkan_featured_black-768x420] GPU Work Graphs mesh nodes now in Vulkan(r) We've added mesh nodes to our Vulkan(r) experimental extension, VK_AMDX_shader_enqueue. [svg][mesh_nodes_author-768x502] GPU Work Graphs mesh nodes in Microsoft DirectX(r) 12 Mesh nodes are a new type of leaf node in work graphs that, unlike all other nodes, does not invoke a compute shader, but dispatches a mesh-shader graphics pipeline instead. This blog series covers how to get started with mesh nodes as well as best practices. AMD Advanced Media FrameworkAMD Advanced Media Framework AMF v1.4.34 features stable support for RADV drivers in VideoConverter/HQScaler + more Features stable support for RADV drivers for AMF on Linux in VideoConverter / HQScaler / VideoEncoder (experimental for decoder), DX11 support for FRC component, Linux support for DVR sample. Enjoy this blog post? If you found it useful, why not share it with other game developers? You may also like... Getting started: AMD GPUOpen softwareGetting started: AMD GPUOpen software New or fairly new to AMD's tools, libraries, and effects? This is the best place to get started on GPUOpen! AMD GPUOpen Getting Started Development and PerformanceAMD GPUOpen Getting Started Development and Performance Looking for tips on getting started with developing and/or optimizing your game, whether on AMD hardware or generally? We've got you covered! GPUOpen ManualsGPUOpen Manuals Don't miss our manual documentation! And if slide decks are what you're after, you'll find 100+ of our finest presentations here. AMD GPUOpen Technical blogsAMD GPUOpen Technical blogs Browse our technical blogs, and find valuable advice on developing with AMD hardware, ray tracing, Vulkan(r), DirectX(r), Unreal Engine, and lots more. AMD GPUOpen videosAMD GPUOpen videos Words not enough? How about pictures? How about moving pictures? We have some amazing videos to share with you! AMD GPUOpen Performance GuidesAMD GPUOpen Performance Guides The home of great performance and optimization advice for AMD RDNA(tm) 2 GPUs, AMD Ryzen(tm) CPUs, and so much more. AMD GPUOpen software blogsAMD GPUOpen software blogs Our handy software release blogs will help you make good use of our tools, SDKs, and effects, as well as sharing the latest features with new releases. AMD GPUOpen publicationsAMD GPUOpen publications Discover our published publications. [svg][53863A_AMD_E_Wh_RGB-1] GPUOpen Zhihu Youtube Twitter Mastodon Rss * Privacy * Trademarks * Terms & Conditions * Cookie Policy * Privacy * Trademarks * Terms & Conditions * Cookie Policy Cookie Settings (c)2025 Advanced Micro Devices, Inc.