WebGL: Drawing Edge Lines
Related Topics: Loading OBJ, Vector3 class
Overview

An edge is a line segment joining 2 vertices of a polygon, for example, a triangle has 3 edges. A geometry consists of multiple triangles and some triangles in the geometry may share common edges by the neighbour triangles. Sometimes, you want to find the edges of a 3D geometry, particularly hard edges, which are sharp angle between 2 neighbour faces. Or, you want to the outline of 3D object from the view point or draw the wireframe of the 3D model.
This page explains how to find the edge lines from a 3D model.
Finding Edges
Edge class is used to define an edge from the given vertex array of a 3D gemetry. It consists of 2 endpoint vertices as Vector3 class. It also stores 2 face normals; one for the current face and the other for the adjacent face to determine if it is hard edge or not.
It also provides a class function, Edge.generateEdges() to find all edges from the input vertex list of a 3D mesh. (The geometry must be triangulated first.) The steps to find all edges are;
- Find 3 edge segments from a single triangle and its face normal
- Store each edge to the edge list if it is new
- Update the second normal of the edge if it already exits in th edge list (shared edge)
- Repeat the above steps for every triangle
The following code is finding all the edges after loading an OBJ model. Edge.generateEdges() returns an array of Edge objects.
// global var
let gl = {};
...
// load OBJ file
gl.obj = new ObjModel();
gl.obj.read("cube.obj").then(obj =>
{
// convert vertices to an array of Vector3 objects
let vertices = ObjModel.toVertices(obj);
// find edges from vertex list
let edges = Edge.generateEdges(vertices);
// can convert to Float32Array for VBO
let vboVertices = Edge.toFloat32Array(edges)
});
...
Finding Hard Edges

A class function Edge.generateHardEdges() will return only hard edges from the given edge list and angle. Each edge object contains 2 normals of 2 adjacent faces. If the angle between 2 face normals is greater than the given value, it is considered as a hard edge. The angle is calculated by the inner product of 2 face normals.
The following code is generating the hard edges where the angle is greater than or equal to 90 degree.
// global var
let gl = {};
...
// load OBJ file
gl.obj = new ObjModel();
gl.obj.read("cube.obj").then(obj =>
{
// convert vertices to an array of Vector3 objects
let vertices = ObjModel.toVertices(obj);
// find edges from vertex list
let edges = Edge.generateEdges(vertices);
// find hard edges with 90 degree
let hardEdges = Edge.generateHardEdges(edges, 90);
// copy hard edges to VBO
gl.vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vbo);
let vboData = Edge.toFloat32Array(hardEdges);
gl.bufferData(gl.ARRAY_BUFFER, vboData, gl.STATIC_DRAW);
});
...
Example
This example is to find all edges and hard edge lines from an OBJ model. You can slide the hard edge angle to determine the hard edges. The angle represents the sharpness at the shared edges, a greater angle is shaper edge.
Note that some edges are not shown when you render it with the surface together. It is because of failing the depth test at the same Z value. One solution to avoid this depth testing issue is to offset the Z value of the edge lines slightly forward to the view. Please see gles_flatOffset.vert shader for details.
Fullscreen Demo: test_edge.html
GitHub Repo: test_edge.html