Support stem darkening in SSAA mode.

The normals are incorrect right now in some cases, but it looks OK-ish.
This commit is contained in:
Patrick Walton 2017-11-09 16:20:15 -08:00
parent 35e59b1a05
commit 8e7eb6ca60
9 changed files with 110 additions and 29 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ Cargo.lock
# VSCode
.vscode
*.code-workspace

View File

@ -403,7 +403,9 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
const expandedPathID = newPathIndex + 1;
const originalPathID = pathIDs[newPathIndex];
const bVertexCopyResult = copyVertices(['bVertexPositions', 'bVertexLoopBlinnData'],
const bVertexCopyResult = copyVertices(['bVertexPositions',
'bVertexLoopBlinnData',
'bVertexNormals'],
'bVertexPathRanges',
expandedArrays,
expandedRanges,

View File

@ -285,6 +285,12 @@ export abstract class Renderer {
this.pathColorsBufferTextures[meshIndex].bind(gl, uniforms, textureUnit);
}
setEmboldenAmountUniform(objectIndex: number, uniforms: UniformMap): void {
const gl = this.renderContext.gl;
const emboldenAmount = this.emboldenAmount;
gl.uniform2f(uniforms.uEmboldenAmount, emboldenAmount[0], emboldenAmount[1]);
}
renderTaskTypeForObject(objectIndex: number): RenderTaskType {
return 'color';
}
@ -420,14 +426,14 @@ export abstract class Renderer {
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
this.setHintsUniform(directInteriorProgram.uniforms);
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
this.setEmboldenAmountUniform(objectIndex, directInteriorProgram.uniforms);
this.pathTransformBufferTextures[meshIndex]
.bind(gl, directInteriorProgram.uniforms, 1);
if (renderingMode === 'color-depth') {
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2);
}
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges,
pathRange);
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
if (!this.pathIDsAreInstanced) {
gl.drawElements(gl.TRIANGLES,
coverInteriorRange.length,
@ -458,10 +464,8 @@ export abstract class Renderer {
// TODO(pcwalton): Cache these.
const directCurveProgramName = this.directCurveProgramName();
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
if (this.implicitCoverCurveVAO == null) {
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt
.createVertexArrayOES();
}
if (this.implicitCoverCurveVAO == null)
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO);
this.initImplicitCoverCurveVAO(objectIndex, instanceRange);
@ -470,6 +474,7 @@ export abstract class Renderer {
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
this.setHintsUniform(directCurveProgram.uniforms);
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
this.pathTransformBufferTextures[meshIndex].bind(gl, directCurveProgram.uniforms, 1);
if (renderingMode === 'color-depth') {
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
@ -592,10 +597,18 @@ export abstract class Renderer {
false,
B_LOOP_BLINN_DATA_SIZE,
B_LOOP_BLINN_DATA_SIGN_OFFSET);
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexNormals);
gl.vertexAttribPointer(directCurveProgram.attributes.aNormalAngle,
1,
gl.FLOAT,
false,
FLOAT32_SIZE,
0);
gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
gl.enableVertexAttribArray(directCurveProgram.attributes.aNormalAngle);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverCurveIndices);
}
@ -632,8 +645,17 @@ export abstract class Renderer {
.vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1);
}
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexNormals);
gl.vertexAttribPointer(directInteriorProgram.attributes.aNormalAngle,
1,
gl.FLOAT,
false,
FLOAT32_SIZE,
0);
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
gl.enableVertexAttribArray(directInteriorProgram.attributes.aNormalAngle);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverInteriorIndices);
}

View File

@ -221,7 +221,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
this.setAADepthState(renderer);
}
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap): void {
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): void {
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
@ -395,7 +395,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
gl.useProgram(lineProgram.program);
const uniforms = lineProgram.uniforms;
this.setAAUniforms(renderer, uniforms);
this.setAAUniforms(renderer, uniforms, objectIndex);
for (const direction of DIRECTIONS) {
const vao = this.lineVAOs[direction];
@ -431,7 +431,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
gl.useProgram(curveProgram.program);
const uniforms = curveProgram.uniforms;
this.setAAUniforms(renderer, uniforms);
this.setAAUniforms(renderer, uniforms, objectIndex);
for (const direction of DIRECTIONS) {
const vao = this.curveVAOs[direction];
@ -687,7 +687,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
const coverProgram = renderContext.shaderPrograms.mcaaCover;
gl.useProgram(coverProgram.program);
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO);
this.setAAUniforms(renderer, coverProgram.uniforms);
this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex);
const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges;
const count = calculateCountFromIndexRanges(pathRange, bQuadRange);
@ -751,12 +751,9 @@ export class ECAAStrategy extends XCAAStrategy {
this.antialiasCurvesOfObject(renderer, objectIndex);
}
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap): void {
super.setAAUniforms(renderer, uniforms);
const renderContext = renderer.renderContext;
const emboldenAmount = renderer.emboldenAmount;
renderContext.gl.uniform2f(uniforms.uEmboldenAmount, emboldenAmount[0], emboldenAmount[1]);
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): void {
super.setAAUniforms(renderer, uniforms, objectIndex);
renderer.setEmboldenAmountUniform(objectIndex, uniforms);
}
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
@ -929,7 +926,7 @@ export class ECAAStrategy extends XCAAStrategy {
gl.useProgram(lineProgram.program);
const uniforms = lineProgram.uniforms;
this.setAAUniforms(renderer, uniforms);
this.setAAUniforms(renderer, uniforms, objectIndex);
const vao = this.lineVAO;
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
@ -957,7 +954,7 @@ export class ECAAStrategy extends XCAAStrategy {
gl.useProgram(curveProgram.program);
const uniforms = curveProgram.uniforms;
this.setAAUniforms(renderer, uniforms);
this.setAAUniforms(renderer, uniforms, objectIndex);
const vao = this.curveVAO;
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);

View File

@ -177,10 +177,24 @@ impl<'a> Partitioner<'a> {
let next_active_edge_index = self.find_point_between_active_edges(endpoint_index);
let endpoint = &self.endpoints[endpoint_index as usize];
self.emit_b_quads_around_active_edge(next_active_edge_index, endpoint.position.x);
let emission_result = self.emit_b_quads_around_active_edge(next_active_edge_index,
endpoint.position.x);
self.add_new_edges_for_min_point(endpoint_index, next_active_edge_index);
// Add supporting interior triangles if necessary.
match emission_result {
BQuadEmissionResult::BQuadEmittedAbove | BQuadEmissionResult::BQuadEmittedAround => {
self.add_supporting_interior_triangle(next_active_edge_index,
next_active_edge_index - 1,
next_active_edge_index + 2);
self.add_supporting_interior_triangle(next_active_edge_index + 1,
next_active_edge_index - 1,
next_active_edge_index + 2);
}
_ => {}
}
let prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
let next_endpoint_index = self.next_endpoint_of(endpoint_index);
let new_point = self.create_point_from_endpoint(next_endpoint_index);
@ -277,8 +291,28 @@ impl<'a> Partitioner<'a> {
// TODO(pcwalton): Collapse the two duplicate endpoints that this will create together if
// possible (i.e. if they have the same parity).
self.emit_b_quads_around_active_edge(active_edge_indices[0], endpoint.position.x);
self.emit_b_quads_around_active_edge(active_edge_indices[1], endpoint.position.x);
let b_quad_emission_results = [
self.emit_b_quads_around_active_edge(active_edge_indices[0], endpoint.position.x),
self.emit_b_quads_around_active_edge(active_edge_indices[1], endpoint.position.x),
];
// Add supporting interior triangles if necessary.
match b_quad_emission_results[0] {
BQuadEmissionResult::BQuadEmittedAbove | BQuadEmissionResult::BQuadEmittedAround => {
self.add_supporting_interior_triangle(active_edge_indices[0],
active_edge_indices[0] - 1,
active_edge_indices[0] + 2)
}
_ => {}
}
match b_quad_emission_results[1] {
BQuadEmissionResult::BQuadEmittedBelow | BQuadEmissionResult::BQuadEmittedAround => {
self.add_supporting_interior_triangle(active_edge_indices[1],
active_edge_indices[1] - 2,
active_edge_indices[1] + 1)
}
_ => {}
}
self.heap.pop();
@ -837,6 +871,17 @@ impl<'a> Partitioner<'a> {
self.subdivide_active_edge_again_at_t(subdivision, t, bottom)
}
fn add_supporting_interior_triangle(&mut self,
active_edge_index: u32,
upper_active_edge_index: u32,
lower_active_edge_index: u32) {
self.library.cover_indices.interior_indices.extend([
self.active_edges[active_edge_index as usize].left_vertex_index,
self.active_edges[upper_active_edge_index as usize].left_vertex_index,
self.active_edges[lower_active_edge_index as usize].left_vertex_index,
].into_iter());
}
fn already_visited_point(&self, point: &Point) -> bool {
// FIXME(pcwalton): This makes the visited vector too big.
let index = point.endpoint_index as usize;
@ -1093,6 +1138,9 @@ impl<'a> Partitioner<'a> {
}
}
// FIXME(pcwalton): This creates incorrect normals for vertical lines. I think we should
// probably calculate normals for the path vertices first and then lerp them to calculate these
// B-vertex normals. That would be simpler, faster, and more correct, I suspect.
fn update_vertex_normals_for_new_b_quad(&mut self, b_quad: &BQuad) {
self.update_vertex_normal_for_b_quad_edge(b_quad.upper_left_vertex_index,
b_quad.upper_control_point_vertex_index,

View File

@ -114,6 +114,10 @@ int convertWindowDepthValueToPathIndex(float depthValue) {
return int(pathIndex);
}
vec2 dilatePosition(vec2 position, float normalAngle, vec2 amount) {
return position + vec2(cos(normalAngle), -sin(normalAngle)) * amount;
}
bool computeMCAAQuadPosition(out vec2 outPosition,
inout vec2 leftPosition,
inout vec2 rightPosition,
@ -164,8 +168,8 @@ bool computeECAAQuadPosition(out vec2 outPosition,
float leftNormalAngle,
float rightNormalAngle,
vec2 emboldenAmount) {
leftPosition += vec2(cos(leftNormalAngle), -sin(leftNormalAngle)) * emboldenAmount;
rightPosition += vec2(cos(rightNormalAngle), -sin(rightNormalAngle)) * emboldenAmount;
leftPosition = dilatePosition(leftPosition, leftNormalAngle, emboldenAmount);
rightPosition = dilatePosition(rightPosition, rightNormalAngle, emboldenAmount);
leftPosition = hintPosition(leftPosition, hints);
rightPosition = hintPosition(rightPosition, hints);

View File

@ -12,6 +12,7 @@ precision highp float;
uniform mat4 uTransform;
uniform vec4 uHints;
uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors;
@ -21,6 +22,7 @@ attribute vec2 aPosition;
attribute vec2 aTexCoord;
attribute float aPathID;
attribute float aSign;
attribute float aNormalAngle;
varying vec4 vColor;
varying vec2 vTexCoord;
@ -31,7 +33,8 @@ void main() {
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions);
vec2 position = hintPosition(aPosition, uHints);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = hintPosition(position, uHints);
position = transformVertexPositionST(position, pathTransform);
position = transformVertexPosition(position, uTransform);

View File

@ -12,6 +12,7 @@ precision highp float;
uniform mat4 uTransform;
uniform vec4 uHints;
uniform vec2 uEmboldenAmount;
uniform ivec2 uPathColorsDimensions;
uniform ivec2 uPathTransformDimensions;
uniform sampler2D uPathColors;
@ -19,6 +20,7 @@ uniform sampler2D uPathTransform;
attribute vec2 aPosition;
attribute float aPathID;
attribute float aNormalAngle;
varying vec4 vColor;
@ -27,7 +29,8 @@ void main() {
vec4 pathTransform = fetchFloat4Data(uPathTransform, pathID, uPathTransformDimensions);
vec2 position = hintPosition(aPosition, uHints);
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
position = hintPosition(position, uHints);
position = transformVertexPositionST(position, pathTransform);
position = transformVertexPosition(position, uTransform);

View File

@ -58,9 +58,10 @@ void main() {
leftNormalAngle,
rightNormalAngle,
uEmboldenAmount)) {
controlPointPosition += vec2(cos(controlPointNormalAngle),
-sin(controlPointNormalAngle)) * uEmboldenAmount;
controlPointPosition = hintPosition(aControlPointPosition, uHints);
controlPointPosition = dilatePosition(controlPointPosition,
controlPointNormalAngle,
uEmboldenAmount);
controlPointPosition = hintPosition(controlPointPosition, uHints);
controlPointPosition = transformVertexPositionST(controlPointPosition, transform);
controlPointPosition = transformVertexPositionST(controlPointPosition, uTransformST);
controlPointPosition = convertClipToScreenSpace(controlPointPosition, uFramebufferSize);