Add basic barrel distortion support for VR

This commit is contained in:
Patrick Walton 2019-03-20 13:40:48 -07:00
parent 2819a88060
commit 6ca5dc5f62
11 changed files with 1602 additions and 4 deletions

View File

@ -63,6 +63,8 @@ public class PathfinderDemoActivity extends Activity {
void setVRMode(boolean enabled) { void setVRMode(boolean enabled) {
try { try {
setVrModeEnabled(false, mVRListenerComponentName); setVrModeEnabled(false, mVRListenerComponentName);
mContentView.setStereoModeEnabled(enabled);
mContentView.setDistortionCorrectionEnabled(false);
} catch (PackageManager.NameNotFoundException exception) { } catch (PackageManager.NameNotFoundException exception) {
startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS)); startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS));
} }
@ -77,7 +79,6 @@ public class PathfinderDemoActivity extends Activity {
setContentView(R.layout.activity_pathfinder); setContentView(R.layout.activity_pathfinder);
mContentView = findViewById(R.id.fullscreen_content); mContentView = findViewById(R.id.fullscreen_content);
mContentView.setStereoModeEnabled(false);
setVRMode(false); setVRMode(false);
mContentView.setEGLContextClientVersion(3); mContentView.setEGLContextClientVersion(3);

View File

@ -21,6 +21,7 @@ use pathfinder_geometry::basic::rect::{RectF32, RectI32};
use pathfinder_geometry::basic::transform2d::Transform2DF32; use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32}; use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
use pathfinder_geometry::color::ColorU; use pathfinder_geometry::color::ColorU;
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
use pathfinder_gl::GLDevice; use pathfinder_gl::GLDevice;
use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc}; use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc};
@ -213,6 +214,11 @@ impl<W> DemoApp<W> where W: Window {
let is_first_frame = self.frame_counter == 0; let is_first_frame = self.frame_counter == 0;
let frame_count = if is_first_frame { 2 } else { 1 }; let frame_count = if is_first_frame { 2 } else { 1 };
let barrel_distortion = match self.ui.mode {
Mode::VR => Some(self.window.barrel_distortion_coefficients()),
_ => None,
};
for _ in 0..frame_count { for _ in 0..frame_count {
let viewport_count = self.ui.mode.viewport_count(); let viewport_count = self.ui.mode.viewport_count();
let render_transforms = iter::repeat(render_transform.clone()).take(viewport_count) let render_transforms = iter::repeat(render_transform.clone()).take(viewport_count)
@ -224,6 +230,7 @@ impl<W> DemoApp<W> where W: Window {
} else { } else {
None None
}, },
barrel_distortion,
})).unwrap(); })).unwrap();
} }
@ -686,6 +693,7 @@ enum MainToSceneMsg {
struct BuildOptions { struct BuildOptions {
render_transforms: Vec<RenderTransform>, render_transforms: Vec<RenderTransform>,
stem_darkening_font_size: Option<f32>, stem_darkening_font_size: Option<f32>,
barrel_distortion: Option<BarrelDistortionCoefficients>,
} }
struct SceneToMainMsg { struct SceneToMainMsg {
@ -798,6 +806,7 @@ fn build_scene(scene: &Scene,
Point2DF32::new(x, y).scale(font_size) Point2DF32::new(x, y).scale(font_size)
} }
}, },
barrel_distortion: build_options.barrel_distortion,
}; };
let built_options = render_options.prepare(scene.bounds); let built_options = render_options.prepare(scene.bounds);

View File

@ -11,6 +11,7 @@
//! A minimal cross-platform windowing layer. //! A minimal cross-platform windowing layer.
use pathfinder_geometry::basic::point::Point2DI32; use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
use pathfinder_gl::GLVersion; use pathfinder_gl::GLVersion;
use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::resources::ResourceLoader;
use std::path::PathBuf; use std::path::PathBuf;
@ -24,6 +25,11 @@ pub trait Window {
fn push_user_event(message_type: u32, message_data: u32); fn push_user_event(message_type: u32, message_data: u32);
fn present_open_svg_dialog(&mut self); fn present_open_svg_dialog(&mut self);
fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()>; fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()>;
#[inline]
fn barrel_distortion_coefficients(&self) -> BarrelDistortionCoefficients {
BarrelDistortionCoefficients::default()
}
} }
pub enum Event { pub enum Event {

View File

@ -0,0 +1,67 @@
// pathfinder/geometry/src/distortion.rs
//
// Copyright © 2019 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.
use crate::basic::point::{Point2DF32, Point2DI32};
use crate::outline::{self, Contour};
#[derive(Clone, Copy, Debug)]
pub struct BarrelDistortionCoefficients {
pub k0: f32,
pub k1: f32,
}
impl Default for BarrelDistortionCoefficients {
// Matches Google Daydream (Cardboard v2.2).
#[inline]
fn default() -> BarrelDistortionCoefficients {
BarrelDistortionCoefficients { k0: 0.34, k1: 0.55 }
}
}
pub struct ContourBarrelDistorter<'a> {
contour: &'a mut Contour,
window_size: Point2DI32,
coefficients: BarrelDistortionCoefficients,
}
impl<'a> ContourBarrelDistorter<'a> {
pub fn new(contour: &'a mut Contour,
coefficients: BarrelDistortionCoefficients,
window_size: Point2DI32)
-> ContourBarrelDistorter<'a> {
ContourBarrelDistorter { contour, window_size, coefficients }
}
pub fn distort(&mut self) {
let one = Point2DF32::splat(1.0);
let window_size = self.window_size.to_f32();
let inv_window_size = Point2DF32(window_size.0.approx_recip());
let BarrelDistortionCoefficients { k0, k1 } = self.coefficients;
let point_count = self.contour.len();
for point_index in 0..point_count {
// Convert from window coordinates to NDC.
let mut position = self.contour.position_of(point_index);
position = position.scale_xy(inv_window_size).scale(2.0) - one;
// Apply distortion.
let r2 = position.square_length();
let scaling = 1.0 + k0 * r2 + k1 * r2 * r2;
position = position.scale(1.0 / scaling);
// Convert back to window coordinates.
position = (position + one).scale(0.5).scale_xy(window_size);
// Store resulting point.
self.contour.points[point_index as usize] = position;
outline::union_rect(&mut self.contour.bounds, position, point_index == 0);
}
}
}

View File

@ -18,6 +18,7 @@ extern crate bitflags;
pub mod basic; pub mod basic;
pub mod clip; pub mod clip;
pub mod color; pub mod color;
pub mod distortion;
pub mod monotonic; pub mod monotonic;
pub mod orientation; pub mod orientation;
pub mod outline; pub mod outline;

View File

@ -11,12 +11,13 @@
//! A compressed in-memory representation of paths. //! A compressed in-memory representation of paths.
use crate::basic::line_segment::LineSegmentF32; use crate::basic::line_segment::LineSegmentF32;
use crate::basic::point::Point2DF32; use crate::basic::point::{Point2DF32, Point2DI32};
use crate::basic::rect::RectF32; use crate::basic::rect::RectF32;
use crate::basic::transform2d::Transform2DF32; use crate::basic::transform2d::Transform2DF32;
use crate::basic::transform3d::Perspective; use crate::basic::transform3d::Perspective;
use crate::clip::{self, ContourPolygonClipper, ContourRectClipper}; use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
use crate::dilation::ContourDilator; use crate::dilation::ContourDilator;
use crate::distortion::{BarrelDistortionCoefficients, ContourBarrelDistorter};
use crate::orientation::Orientation; use crate::orientation::Orientation;
use crate::segment::{Segment, SegmentFlags, SegmentKind}; use crate::segment::{Segment, SegmentFlags, SegmentKind};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
@ -135,6 +136,17 @@ impl Outline {
self.bounds = self.bounds.dilate(amount); self.bounds = self.bounds.dilate(amount);
} }
pub fn barrel_distort(&mut self,
coefficients: BarrelDistortionCoefficients,
window_size: Point2DI32) {
let mut new_bounds = None;
for contour in &mut self.contours {
contour.barrel_distort(coefficients, window_size);
contour.update_bounds(&mut new_bounds);
}
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
}
pub fn prepare_for_tiling(&mut self, view_box: RectF32) { pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box)); self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box));
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default()); self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
@ -419,6 +431,12 @@ impl Contour {
self.bounds = self.bounds.dilate(amount); self.bounds = self.bounds.dilate(amount);
} }
pub fn barrel_distort(&mut self,
coefficients: BarrelDistortionCoefficients,
window_size: Point2DI32) {
ContourBarrelDistorter::new(self, coefficients, window_size).distort();
}
fn prepare_for_tiling(&mut self, view_box: RectF32) { fn prepare_for_tiling(&mut self, view_box: RectF32) {
// Snap points to the view box bounds. This mops up floating point error from the clipping // Snap points to the view box bounds. This mops up floating point error from the clipping
// process. // process.
@ -667,7 +685,7 @@ impl<'a> Iterator for ContourIter<'a> {
} }
#[inline] #[inline]
fn union_rect(bounds: &mut RectF32, new_point: Point2DF32, first: bool) { pub(crate) fn union_rect(bounds: &mut RectF32, new_point: Point2DF32, first: bool) {
if first { if first {
*bounds = RectF32::from_points(new_point, new_point); *bounds = RectF32::from_points(new_point, new_point);
} else { } else {

View File

@ -20,6 +20,7 @@ use pathfinder_geometry::basic::rect::{RectF32, RectI32};
use pathfinder_geometry::basic::transform2d::Transform2DF32; use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::Perspective; use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::clip::PolygonClipper3D; use pathfinder_geometry::clip::PolygonClipper3D;
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
use std::iter; use std::iter;
use std::u16; use std::u16;
@ -126,6 +127,7 @@ impl SceneBuilder {
pub struct RenderOptions { pub struct RenderOptions {
pub transform: RenderTransform, pub transform: RenderTransform,
pub dilation: Point2DF32, pub dilation: Point2DF32,
pub barrel_distortion: Option<BarrelDistortionCoefficients>,
} }
impl RenderOptions { impl RenderOptions {
@ -133,6 +135,7 @@ impl RenderOptions {
PreparedRenderOptions { PreparedRenderOptions {
transform: self.transform.prepare(bounds), transform: self.transform.prepare(bounds),
dilation: self.dilation, dilation: self.dilation,
barrel_distortion: self.barrel_distortion,
} }
} }
} }
@ -201,6 +204,7 @@ impl RenderTransform {
pub struct PreparedRenderOptions { pub struct PreparedRenderOptions {
pub transform: PreparedRenderTransform, pub transform: PreparedRenderTransform,
pub dilation: Point2DF32, pub dilation: Point2DF32,
pub barrel_distortion: Option<BarrelDistortionCoefficients>,
} }
impl PreparedRenderOptions { impl PreparedRenderOptions {
@ -218,4 +222,3 @@ pub enum PreparedRenderTransform {
Transform2D(Transform2DF32), Transform2D(Transform2DF32),
Perspective { perspective: Perspective, clip_polygon: Vec<Point2DF32>, quad: [Point3DF32; 4] } Perspective { perspective: Perspective, clip_polygon: Vec<Point2DF32>, quad: [Point3DF32; 4] }
} }

View File

@ -116,6 +116,11 @@ impl Scene {
outline = (*original_outline).clone(); outline = (*original_outline).clone();
outline.clip_against_polygon(clip_polygon); outline.clip_against_polygon(clip_polygon);
outline.apply_perspective(perspective); outline.apply_perspective(perspective);
// TODO(pcwalton): Support this in 2D too.
if let Some(barrel_distortion) = options.barrel_distortion {
outline.barrel_distort(barrel_distortion, perspective.window_size);
}
} }
} }
PreparedRenderTransform::Transform2D(ref transform) => { PreparedRenderTransform::Transform2D(ref transform) => {

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 192 KiB

View File

@ -31,6 +31,11 @@ impl F32x4 {
// Basic operations // Basic operations
#[inline]
pub fn approx_recip(self) -> F32x4 {
F32x4([1.0 / self[0], 1.0 / self[1], 1.0 / self[2], 1.0 / self[3]])
}
#[inline] #[inline]
pub fn min(self, other: F32x4) -> F32x4 { pub fn min(self, other: F32x4) -> F32x4 {
F32x4([ F32x4([

View File

@ -37,6 +37,11 @@ impl F32x4 {
// Basic operations // Basic operations
#[inline]
pub fn approx_recip(self) -> F32x4 {
unsafe { F32x4(x86_64::_mm_rcp_ps(self.0)) }
}
#[inline] #[inline]
pub fn min(self, other: F32x4) -> F32x4 { pub fn min(self, other: F32x4) -> F32x4 {
unsafe { F32x4(x86_64::_mm_min_ps(self.0, other.0)) } unsafe { F32x4(x86_64::_mm_min_ps(self.0, other.0)) }