Use stencil to integrate the vector scene into the 3D environment

This commit is contained in:
Patrick Walton 2019-02-19 12:03:02 -08:00
parent 3b8ecfd74c
commit c7a1d9e960
7 changed files with 154 additions and 156 deletions

View File

@ -390,11 +390,12 @@ impl DemoApp {
color.g(),
color.b(),
color.a());
gl::DepthFunc(gl::LESS);
gl::DepthMask(gl::FALSE);
gl::DepthFunc(gl::ALWAYS);
gl::DepthMask(gl::TRUE);
gl::Enable(gl::DEPTH_TEST);
gl::StencilFunc(gl::ALWAYS, 1, !0);
gl::StencilFunc(gl::ALWAYS, 2, 2);
gl::StencilOp(gl::KEEP, gl::KEEP, gl::REPLACE);
gl::StencilMask(2);
gl::Enable(gl::STENCIL_TEST);
gl::Disable(gl::BLEND);
gl::DrawArrays(gl::LINES, 0, (GRIDLINE_COUNT as GLsizei + 1) * 4);
@ -419,7 +420,7 @@ impl DemoApp {
gl::DepthFunc(gl::LESS);
gl::DepthMask(gl::TRUE);
gl::Enable(gl::DEPTH_TEST);
gl::StencilFunc(gl::NOTEQUAL, 1, !0);
gl::StencilFunc(gl::NOTEQUAL, 2, 2);
gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP);
gl::Enable(gl::STENCIL_TEST);
gl::Disable(gl::BLEND);
@ -442,6 +443,12 @@ impl DemoApp {
self.renderer.disable_subpixel_aa();
}
if self.ui.threed_enabled {
self.renderer.enable_depth();
} else {
self.renderer.disable_depth();
}
self.renderer.render_scene(&built_scene);
}

View File

@ -13,6 +13,7 @@ use crate::device::{Buffer, BufferTarget, BufferUploadMode, Device, Framebuffer,
use crate::device::{TimerQuery, Uniform, VertexArray, VertexAttr};
use euclid::Size2D;
use gl::types::{GLfloat, GLint};
use pathfinder_geometry::basic::point::Point3DF32;
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
use pathfinder_renderer::paint::{ColorU, ObjectShader};
use pathfinder_renderer::post::DefringingKernel;
@ -52,6 +53,10 @@ pub struct Renderer {
postprocess_vertex_array: PostprocessVertexArray,
gamma_lut_texture: Texture,
// Stencil shader
stencil_program: StencilProgram,
stencil_vertex_array: StencilVertexArray,
// Debug
pending_timer_queries: VecDeque<TimerQuery>,
free_timer_queries: Vec<TimerQuery>,
@ -60,6 +65,7 @@ pub struct Renderer {
// Extra info
main_framebuffer_size: Size2D<u32>,
postprocess_options: PostprocessOptions,
use_depth: bool,
}
impl Renderer {
@ -69,6 +75,7 @@ impl Renderer {
let mask_tile_program = MaskTileProgram::new(device);
let postprocess_program = PostprocessProgram::new(device);
let stencil_program = StencilProgram::new(device);
let area_lut_texture = device.create_texture_from_png("area-lut");
let gamma_lut_texture = device.create_texture_from_png("gamma-lut");
@ -86,6 +93,7 @@ impl Renderer {
let postprocess_vertex_array = PostprocessVertexArray::new(&postprocess_program,
&quad_vertex_positions_buffer);
let stencil_vertex_array = StencilVertexArray::new(&stencil_program);
let mask_framebuffer_texture = Texture::new_r16f(&Size2D::new(MASK_FRAMEBUFFER_WIDTH,
MASK_FRAMEBUFFER_HEIGHT));
@ -113,6 +121,9 @@ impl Renderer {
postprocess_vertex_array,
gamma_lut_texture,
stencil_program,
stencil_vertex_array,
pending_timer_queries: VecDeque::new(),
free_timer_queries: vec![],
@ -120,6 +131,7 @@ impl Renderer {
main_framebuffer_size: *main_framebuffer_size,
postprocess_options: PostprocessOptions::default(),
use_depth: false,
}
}
@ -131,16 +143,18 @@ impl Renderer {
self.upload_shaders(&built_scene.shaders);
if self.use_depth {
self.draw_stencil(&built_scene.quad);
}
self.upload_solid_tiles(&built_scene.solid_tiles);
self.draw_solid_tiles(&built_scene);
/*
for batch in &built_scene.batches {
self.upload_batch(batch);
self.draw_batch_fills(batch);
self.draw_batch_mask_tiles(&built_scene, batch);
self.draw_batch_mask_tiles(batch);
}
*/
if self.postprocessing_needed() {
self.postprocess();
@ -187,6 +201,16 @@ impl Renderer {
self.postprocess_options.gamma_correction_bg_color = Some(bg_color);
}
#[inline]
pub fn disable_depth(&mut self) {
self.use_depth = false;
}
#[inline]
pub fn enable_depth(&mut self) {
self.use_depth = true;
}
#[inline]
pub fn quad_vertex_positions_buffer(&self) -> &Buffer {
&self.quad_vertex_positions_buffer
@ -247,7 +271,7 @@ impl Renderer {
}
}
fn draw_batch_mask_tiles(&mut self, built_scene: &BuiltScene, batch: &Batch) {
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
unsafe {
self.bind_draw_framebuffer();
self.set_main_viewport();
@ -272,26 +296,12 @@ impl Renderer {
FILL_COLORS_TEXTURE_HEIGHT as GLfloat);
// FIXME(pcwalton): Fill this in properly!
gl::Uniform2f(self.mask_tile_program.view_box_origin_uniform.location, 0.0, 0.0);
gl::Uniform3f(self.mask_tile_program.quad_p0_uniform.location,
built_scene.quad[0].x(),
built_scene.quad[0].y(),
built_scene.quad[0].z());
gl::Uniform3f(self.mask_tile_program.quad_p1_uniform.location,
built_scene.quad[1].x(),
built_scene.quad[1].y(),
built_scene.quad[1].z());
gl::Uniform3f(self.mask_tile_program.quad_p2_uniform.location,
built_scene.quad[2].x(),
built_scene.quad[2].y(),
built_scene.quad[2].z());
gl::Uniform3f(self.mask_tile_program.quad_p3_uniform.location,
built_scene.quad[3].x(),
built_scene.quad[3].y(),
built_scene.quad[3].z());
self.enable_blending();
self.enable_depth_test();
gl::Disable(gl::DEPTH_TEST);
self.setup_stencil_mask();
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.mask_tiles.len() as GLint);
gl::Disable(gl::BLEND);
gl::Disable(gl::STENCIL_TEST);
}
}
@ -315,28 +325,12 @@ impl Renderer {
FILL_COLORS_TEXTURE_HEIGHT as GLfloat);
// FIXME(pcwalton): Fill this in properly!
gl::Uniform2f(self.solid_tile_program.view_box_origin_uniform.location, 0.0, 0.0);
gl::Uniform3f(self.solid_tile_program.quad_p0_uniform.location,
built_scene.quad[0].x(),
built_scene.quad[0].y(),
built_scene.quad[0].z());
gl::Uniform3f(self.solid_tile_program.quad_p1_uniform.location,
built_scene.quad[1].x(),
built_scene.quad[1].y(),
built_scene.quad[1].z());
gl::Uniform3f(self.solid_tile_program.quad_p2_uniform.location,
built_scene.quad[2].x(),
built_scene.quad[2].y(),
built_scene.quad[2].z());
gl::Uniform3f(self.solid_tile_program.quad_p3_uniform.location,
built_scene.quad[3].x(),
built_scene.quad[3].y(),
built_scene.quad[3].z());
gl::Disable(gl::BLEND);
gl::DepthMask(gl::FALSE);
gl::Enable(gl::DEPTH_TEST);
gl::Disable(gl::STENCIL_TEST);
gl::Disable(gl::DEPTH_TEST);
self.setup_stencil_mask();
let count = built_scene.solid_tiles.len();
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, count as GLint);
gl::Disable(gl::STENCIL_TEST);
}
}
@ -388,6 +382,30 @@ impl Renderer {
}
}
fn draw_stencil(&self, quad_positions: &[Point3DF32]) {
self.stencil_vertex_array
.vertex_buffer
.upload(quad_positions, BufferTarget::Vertex, BufferUploadMode::Dynamic);
self.bind_draw_framebuffer();
unsafe {
gl::BindVertexArray(self.stencil_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.stencil_program.program.gl_program);
gl::ColorMask(gl::FALSE, gl::FALSE, gl::FALSE, gl::FALSE);
gl::DepthFunc(gl::LESS);
gl::Enable(gl::DEPTH_TEST);
gl::StencilFunc(gl::ALWAYS, 1, 1);
gl::StencilOp(gl::KEEP, gl::KEEP, gl::REPLACE);
gl::StencilMask(1);
gl::Enable(gl::STENCIL_TEST);
gl::Disable(gl::BLEND);
gl::DrawArrays(gl::TRIANGLE_FAN, 0, quad_positions.len() as GLint);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::Disable(gl::DEPTH_TEST);
gl::Disable(gl::STENCIL_TEST);
}
}
fn bind_draw_framebuffer(&self) {
unsafe {
if self.postprocessing_needed() {
@ -443,13 +461,17 @@ impl Renderer {
}
}
fn enable_depth_test(&self) {
fn setup_stencil_mask(&self) {
unsafe {
gl::DepthMask(gl::FALSE);
gl::Enable(gl::DEPTH_TEST);
if self.use_depth {
gl::StencilFunc(gl::EQUAL, 1, 1);
gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP);
gl::Enable(gl::STENCIL_TEST);
} else {
gl::Disable(gl::STENCIL_TEST);
}
}
}
}
#[derive(Clone, Copy, Default)]
@ -574,10 +596,6 @@ struct SolidTileProgram {
fill_colors_texture_uniform: Uniform,
fill_colors_texture_size_uniform: Uniform,
view_box_origin_uniform: Uniform,
quad_p0_uniform: Uniform,
quad_p1_uniform: Uniform,
quad_p2_uniform: Uniform,
quad_p3_uniform: Uniform,
}
impl SolidTileProgram {
@ -588,10 +606,6 @@ impl SolidTileProgram {
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
let quad_p0_uniform = Uniform::new(&program, "QuadP0");
let quad_p1_uniform = Uniform::new(&program, "QuadP1");
let quad_p2_uniform = Uniform::new(&program, "QuadP2");
let quad_p3_uniform = Uniform::new(&program, "QuadP3");
SolidTileProgram {
program,
framebuffer_size_uniform,
@ -599,10 +613,6 @@ impl SolidTileProgram {
fill_colors_texture_uniform,
fill_colors_texture_size_uniform,
view_box_origin_uniform,
quad_p0_uniform,
quad_p1_uniform,
quad_p2_uniform,
quad_p3_uniform,
}
}
}
@ -616,10 +626,6 @@ struct MaskTileProgram {
fill_colors_texture_uniform: Uniform,
fill_colors_texture_size_uniform: Uniform,
view_box_origin_uniform: Uniform,
quad_p0_uniform: Uniform,
quad_p1_uniform: Uniform,
quad_p2_uniform: Uniform,
quad_p3_uniform: Uniform,
}
impl MaskTileProgram {
@ -632,10 +638,6 @@ impl MaskTileProgram {
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
let quad_p0_uniform = Uniform::new(&program, "QuadP0");
let quad_p1_uniform = Uniform::new(&program, "QuadP1");
let quad_p2_uniform = Uniform::new(&program, "QuadP2");
let quad_p3_uniform = Uniform::new(&program, "QuadP3");
MaskTileProgram {
program,
framebuffer_size_uniform,
@ -645,10 +647,6 @@ impl MaskTileProgram {
fill_colors_texture_uniform,
fill_colors_texture_size_uniform,
view_box_origin_uniform,
quad_p0_uniform,
quad_p1_uniform,
quad_p2_uniform,
quad_p3_uniform,
}
}
}
@ -701,3 +699,35 @@ impl PostprocessVertexArray {
PostprocessVertexArray { vertex_array }
}
}
struct StencilProgram {
program: Program,
}
impl StencilProgram {
fn new(device: &Device) -> StencilProgram {
let program = device.create_program("stencil");
StencilProgram { program }
}
}
struct StencilVertexArray {
vertex_array: VertexArray,
vertex_buffer: Buffer,
}
impl StencilVertexArray {
fn new(stencil_program: &StencilProgram) -> StencilVertexArray {
let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new());
unsafe {
let position_attr = VertexAttr::new(&stencil_program.program, "Position");
gl::BindVertexArray(vertex_array.gl_vertex_array);
gl::UseProgram(stencil_program.program.gl_program);
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
position_attr.configure_float(3, gl::FLOAT, false, 4 * 4, 0, 0);
}
StencilVertexArray { vertex_array, vertex_buffer }
}
}

View File

@ -173,7 +173,7 @@ impl RenderTransform {
for point in &mut points {
*point = perspective.transform.transform_point(*point);
}
println!("... PERSPECTIVE quad={:?}", points);
//println!("... PERSPECTIVE quad={:?}", points);
// Compute depth.
let quad = [
@ -182,12 +182,7 @@ impl RenderTransform {
points[2].perspective_divide(),
points[3].perspective_divide(),
];
println!("barycentric(0, 0) = {:?}", compute_barycentric(&[
quad[0].to_2d(),
quad[1].to_2d(),
quad[2].to_2d(),
quad[3].to_2d(),
], Point2DF32::new(0.0, 0.0)));
//println!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
points = PolygonClipper3D::new(points).clip();
//println!("... CLIPPED quad={:?}", points);
@ -200,20 +195,6 @@ impl RenderTransform {
inverse_transform.transform_point(point).perspective_divide().to_2d()
}).collect();
return PreparedRenderTransform::Perspective { perspective, clip_polygon, quad };
fn compute_barycentric(quad: &[Point2DF32], point: Point2DF32) -> [f32; 4] {
let (s0, s1) = (quad[0] - point, quad[1] - point);
let (s2, s3) = (quad[2] - point, quad[3] - point);
let (a0, a1, a2, a3) = (s0.det(s1), s1.det(s2), s2.det(s3), s3.det(s0));
let (d0, d1, d2, d3) = (s0.dot(s1), s1.dot(s2), s2.dot(s3), s3.dot(s0));
let (r0, r1, r2, r3) = (s0.length(), s1.length(), s2.length(), s3.length());
let (t0, t1) = ((r0 * r1 - d0) / a0, (r1 * r2 - d1) / a1);
let (t2, t3) = ((r2 * r3 - d2) / a2, (r3 * r0 - d3) / a3);
let (u0, u1) = ((t3 + t0) / r0, (t2 + t1) / r1);
let (u2, u3) = ((t0 + t2) / r2, (t0 + t3) / r3);
let sum = u0 + u1 + u2 + u3;
[u0 / sum, u1 / sum, u2 / sum, u3 / sum]
}
}
}

View File

@ -18,10 +18,6 @@ uniform vec2 uStencilTextureSize;
uniform sampler2D uFillColorsTexture;
uniform vec2 uFillColorsTextureSize;
uniform vec2 uViewBoxOrigin;
uniform vec3 uQuadP0;
uniform vec3 uQuadP1;
uniform vec3 uQuadP2;
uniform vec3 uQuadP3;
in vec2 aTessCoord;
in vec2 aTileOrigin;
@ -32,21 +28,6 @@ out vec2 vTexCoord;
out float vBackdrop;
out vec4 vColor;
float wedge(vec2 a, vec2 b) {
return a.x * b.y - a.y * b.x;
}
// From "A Quadrilateral Rendering Primitive", Hormann and Tarini 2004.
vec4 barycentricQuad(vec2 p) {
vec2 s0 = uQuadP0.xy - p, s1 = uQuadP1.xy - p, s2 = uQuadP2.xy - p, s3 = uQuadP3.xy - p;
vec4 a = vec4(wedge(s0, s1), wedge(s1, s2), wedge(s2, s3), wedge(s3, s0));
vec4 d = vec4(dot(s0, s1), dot(s1, s2), dot(s2, s3), dot(s3, s0));
vec4 r = vec4(length(s0), length(s1), length(s2), length(s3));
vec4 t = (r * r.yzwx - d) / a;
vec4 u = (t.wxyz + t) / r;
return u / dot(u, vec4(1.0));
}
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
@ -62,21 +43,11 @@ void main() {
uint tileIndex = uint(gl_InstanceID);
vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0);
vec4 lambda = barycentricQuad(position);
//vec4 depths = vec4(uQuadP0.z, uQuadP1.z, uQuadP2.z, uQuadP3.z);
//float depth = dot(lambda, depths);
float red = lambda.x;
float green = lambda.y;
float blue = lambda.z + 1.0;
float depth = 0.0;
vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize;
vec2 colorTexCoord = computeFillColorTexCoord(aObject, uFillColorsTextureSize);
vTexCoord = texCoord / uStencilTextureSize;
vBackdrop = float(aBackdrop);
//vColor = texture(uFillColorsTexture, colorTexCoord);
vColor = vec4(red, green, blue, 1.0);
gl_Position = vec4(position, depth, 1.0);
vColor = texture(uFillColorsTexture, colorTexCoord);
gl_Position = vec4(position, 0.0, 1.0);
}

View File

@ -17,10 +17,6 @@ uniform vec2 uTileSize;
uniform sampler2D uFillColorsTexture;
uniform vec2 uFillColorsTextureSize;
uniform vec2 uViewBoxOrigin;
uniform vec3 uQuadP0;
uniform vec3 uQuadP1;
uniform vec3 uQuadP2;
uniform vec3 uQuadP3;
in vec2 aTessCoord;
in vec2 aTileOrigin;
@ -28,21 +24,6 @@ in uint aObject;
out vec4 vColor;
float wedge(vec2 a, vec2 b) {
return a.x * b.y - a.y * b.x;
}
// From "A Quadrilateral Rendering Primitive", Hormann and Tarini 2004.
vec4 barycentricQuad(vec2 p) {
vec2 s0 = uQuadP0.xy - p, s1 = uQuadP1.xy - p, s2 = uQuadP2.xy - p, s3 = uQuadP3.xy - p;
vec4 a = vec4(wedge(s0, s1), wedge(s1, s2), wedge(s2, s3), wedge(s3, s0));
vec4 d = vec4(dot(s0, s1), dot(s1, s2), dot(s2, s3), dot(s3, s0));
vec4 r = vec4(length(s0), length(s1), length(s2), length(s3));
vec4 t = (r * r.yzwx - d) / a;
vec4 u = (t.wxyz + t) / r;
return u / dot(u, vec4(1.0));
}
vec2 computeFillColorTexCoord(uint object, vec2 textureSize) {
uint width = uint(textureSize.x);
return (vec2(float(object % width), float(object / width)) + vec2(0.5)) / textureSize;
@ -51,19 +32,8 @@ vec2 computeFillColorTexCoord(uint object, vec2 textureSize) {
void main() {
vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0);
//vec4 depths = vec4(uQuadP0.z, uQuadP1.z, uQuadP2.z, uQuadP3.z);
//float depth = dot(barycentricQuad(position), depths);
vec4 lambda = barycentricQuad(position);
float red = lambda.x;
float green = lambda.y;
float blue = lambda.z;
float depth = 0.0;
vec2 colorTexCoord = computeFillColorTexCoord(aObject, uFillColorsTextureSize);
//vColor = texture(uFillColorsTexture, colorTexCoord);
vColor = vec4(red, green, blue, 1.0);
gl_Position = vec4(position, depth, 1.0);
vColor = texture(uFillColorsTexture, colorTexCoord);
gl_Position = vec4(position, 0.0, 1.0);
}

View File

@ -0,0 +1,20 @@
#version 330
// pathfinder/resources/shaders/stencil.fs.glsl
//
// Copyright © 2018 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
out vec4 oFragColor;
void main() {
// This should be color masked out.
oFragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

View File

@ -0,0 +1,19 @@
#version 330
// pathfinder/resources/shaders/stencil.vs.glsl
//
// Copyright © 2018 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
in vec3 aPosition;
void main() {
gl_Position = vec4(aPosition, 1.0);
}