Created
March 8, 2015 18:35
-
-
Save runnerpack/6d51f5b40eff1bf1107a to your computer and use it in GitHub Desktop.
Ashton problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Idea: use GLSL shaders in Gosu/Ashton to draw stereoscopic graphics | |
# Technologies (to be) supported: | |
# * Row interleaved | |
# * Over/under | |
# * Side-by-side | |
# * Anaglyph (Red/cyan, Green/magenta, Yellow/blue, and grayscale versions of those) | |
# * Rift-style HMDs(?) | |
# On FPR displays (like my Asus VG23AH) it works without special mode changes, expensive drivers, or fancy cables! | |
begin; require 'rubygems'; rescue LoadError; end | |
# $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__)) | |
require "ashton" | |
module Gosu3D | |
class Point2D | |
# Stores a 2D point | |
attr_accessor :x, :y, :c | |
def initialize(ix = 0, iy = 0, ic = 0xFFFFFFFF) | |
@x = ix | |
@y = iy | |
@c = ic | |
end | |
end # Point2D class | |
class Point3D | |
# Stores a 3D point and provides parallax-shifted and | |
# stereoscopic format-displaced values of the x and | |
# y coordinates, on-demand. | |
attr_reader :win, :lx, :rx, :ly, :ry, :x, :y, :z | |
attr_accessor :c | |
def initialize(win, ix = 0, iy = 0, iz = 0, ic = 0xFFFFFFFF) | |
@win = win | |
@x = ix | |
@y = iy | |
@z = iz | |
@c = ic | |
self.recalculate | |
end | |
def x= (nx) | |
@x = nx | |
recalculate | |
end | |
def y= (ny) | |
@y = ny | |
recalculate | |
end | |
def z= (nz) | |
@z = nz | |
recalculate | |
end | |
def win= (nwin) | |
@win = nwin | |
recalculate | |
end | |
def recalculate | |
if @win.tech == :sxs | |
@lx = (@x - (@z * 0.5)) * 0.5 | |
@ly = @y | |
@rx = (@x + (@z * 0.5)) * 0.5 + @win.height * 0.5 | |
@ry = @y | |
else | |
@lx = @x - (@z * 0.5) | |
@ly = @y * 0.5 | |
@rx = @x + (@z * 0.5) | |
@ry = @y * 0.5 + @win.height * 0.5 | |
end | |
end | |
def left; Point2D.new(@lx, @ly, @c); end | |
def right; Point2D.new(@rx, @ry, @c); end | |
end # Point3D class | |
W = 960 | |
H = 540 | |
FS = false | |
# W = 1920 | |
# H = 1080 | |
# FS = true | |
class Window3D < Gosu::Window | |
def near_file(path); File.expand_path "#{path}", File.dirname(__FILE__) end | |
attr_reader :tech | |
def initialize(w, h, fs = true, t = :hint) | |
super w, h, fs | |
self.caption = "Hardware-accelerated stereoscopy? Yes, please!" | |
@points = Array.new(10) { | |
color = Gosu::Color.rgba(255, 0, 0, 255) | |
color.hue = rand(360) | |
Gosu3D::Point3D.new(self, rand(W), rand(H), rand(30) - 15, color) | |
} | |
self.tech = t | |
end | |
def tech= (t) | |
# TODO: Input checking/filtering/fall-back | |
@tech = t | |
# Load the specified fragment shader | |
@shader = Ashton::Shader.new frag: near_file( "%s.glsl" % @tech.to_s ) | |
end | |
def button_down(id) | |
if id == Gosu::KbEscape | |
close | |
elsif id == Gosu::KbTab | |
# | |
elsif id == Gosu::MsWheelUp | |
# | |
elsif id == Gosu::MsWheelDown | |
# | |
end | |
end | |
def draw | |
if button_down?(Gosu::KbTab) | |
# Convert the half-over/under image to the desired stereo output format | |
post_process (@shader) { | |
draw_3d | |
} | |
else | |
draw_3d | |
end | |
end | |
def draw_3d | |
(-1...@points.length - 1).each { |n| | |
line_3d(@points[n], @points[n + 1]) | |
} | |
end | |
def line_3d(p1, p2, mode = :default) | |
l1 = p1.left | |
r1 = p1.right | |
l2 = p2.left | |
r2 = p2.right | |
z = [p1.z, p2.z].max | |
# Draw the left-eye line | |
draw_line(l1.x, l1.y, l1.c, l2.x, l2.y, l2.c, z, mode) | |
# Draw the right-eye line | |
draw_line(r1.x, r1.y, r1.c, r2.x, r2.y, r2.c, z, mode) | |
end | |
def triangle_3d(p1, p2, p3, mode = :default) | |
end | |
def quad_3d(p1, p2, p3, p4, mode = :default) | |
end | |
end # Window3D class | |
# class Image3D | |
# def initialize(win, src, tileable = false, stereo = true) | |
# @win = win | |
# @stereo = stereo | |
# if stereo | |
# @pair = Gosu::Image.load_tiles(win, src, -2, 1, tileable) | |
# @image = nil | |
# else | |
# @pair = nil | |
# @image = Gosu::Image.new(win, src, tileable) | |
# end | |
# end | |
# def draw(x, y, z, factor_x = 1, factor_y = 1, color = 0xffffffff, mode = :default) | |
# if @stereo | |
# l = @pair[1] | |
# r = @pair[0] | |
# else | |
# l = r = @image | |
# end | |
# l.draw(x - (z * 0.5), y * 0.5, z, factor_x, factor_y * 0.5, color, mode) | |
# r.draw(x + (z * 0.5), y * 0.5 + @win.height * 0.5, z, factor_x, factor_y * 0.5, color, mode) | |
# end | |
# def draw_as_quad(*args) | |
# puts "Warning: Drawing a stereo pair as a random quadrilateral may damage someone's eyeballs!" | |
# end | |
# def draw_rot(*args) | |
# puts "Warning: Drawing a stereo pair rotated may damage someone's eyeballs!" | |
# end | |
# end # Image3D class | |
Window3D.new(W, H, FS).show | |
end # Gosu3D module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Convert a half-over/under stereo pair to a horizontally-interleaved stereo pair | |
uniform int in_WindowHeight; | |
uniform sampler2D in_Texture; | |
varying vec2 var_TexCoord; | |
// Algorithm: | |
// Save a copy of the destination pixel's coordinates with the Y value halved. | |
// Convert the destination pixel's Y coordinate to an integer, and test it. | |
// If it's even, add 0.5 to the saved Y coordinate to get the pixel from the bottom half of the texture. | |
void main() | |
{ | |
vec2 texel = vec2(var_TexCoord.x, var_TexCoord.y / 2.0); | |
if (mod(floor(var_TexCoord.y * float(in_WindowHeight)), 2.0) < 0.01) | |
texel.y += 0.5; | |
gl_FragColor = texture2D(in_Texture, texel); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
(Sorry about the clutter...)
Desired output:
When tab is held down, the top and bottom halves of the window should be interlaced, pixel-by-pixel.
Actual output:
The first time tab is pressed, you can see that it seems to work for one frame, then everything goes black. Even when tab is released, the window stays black.