mirror of
https://github.com/SleepingInsomniac/pixelfaucet
synced 2024-11-16 07:47:36 +01:00
Correct for perspective in texturing
This commit is contained in:
parent
0e599fbe94
commit
bab69ad5f5
7 changed files with 63 additions and 17 deletions
7
spec/line_spec.cr
Normal file
7
spec/line_spec.cr
Normal file
|
@ -0,0 +1,7 @@
|
|||
require "./spec_helper"
|
||||
require "../src/line"
|
||||
|
||||
include PF
|
||||
|
||||
describe Line do
|
||||
end
|
|
@ -70,6 +70,11 @@ describe Vector do
|
|||
v1 = Vector[5, 5]
|
||||
(v1 // 2).should eq(Vector[2, 2])
|
||||
end
|
||||
|
||||
it "applies exponents" do
|
||||
v = Vector[2, 2] ** 5
|
||||
v.should eq(Vector[32, 32])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#-" do
|
||||
|
@ -80,6 +85,13 @@ describe Vector do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#sum" do
|
||||
it "returns all components added together" do
|
||||
v = Vector[1, 2, 3]
|
||||
v.sum.should eq(6)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#abs" do
|
||||
it "returns the absolute value" do
|
||||
v = Vector[-1, -1]
|
||||
|
|
|
@ -23,12 +23,17 @@ module PF
|
|||
parts = line.split(/\s+/)
|
||||
|
||||
case parts[0]
|
||||
when "o"
|
||||
puts "Object: #{parts[1]}"
|
||||
# TODO: This is when a new mesh starts
|
||||
when "mtllib"
|
||||
# TODO This is where we need to load texture and material information
|
||||
when "v"
|
||||
w = parts[4]?.try { |n| n.to_f64 }
|
||||
verticies << Vector3.new(x: parts[1].to_f64, y: parts[2].to_f64, z: parts[3].to_f64)
|
||||
when "vt"
|
||||
v = parts[2]?.try { |n| n.to_f64 } || 0.0
|
||||
w = parts[3]?.try { |n| n.to_f64 } || 0.0
|
||||
w = parts[3]?.try { |n| n.to_f64 } || 1.0
|
||||
texture_verticies << Vector3.new(parts[1].to_f64, v, w)
|
||||
when "vn"
|
||||
if use_normals
|
||||
|
@ -67,9 +72,13 @@ module PF
|
|||
tris << tri
|
||||
|
||||
# Split a square into triangles
|
||||
# TODO: Handle texture points
|
||||
if face_verts.size > 3
|
||||
tri = Tri.new(face_verts[0], face_verts[2], face_verts[3], normal: normal)
|
||||
unless face_tex.empty?
|
||||
tri.t1 = face_tex[0]
|
||||
tri.t2 = face_tex[2]
|
||||
tri.t3 = face_tex[3]
|
||||
end
|
||||
tris << tri
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,15 +48,19 @@ module PF
|
|||
|
||||
# Multiply all points by a *Matrix*, returning a new *Tri*
|
||||
def *(mat : Matrix)
|
||||
# The transform function returns a w, which is the 4th component of the vertex
|
||||
# this is the perspective information that we can use to apply textures
|
||||
pp1, w1 = Transform3d.apply(@p1, mat)
|
||||
pp2, w2 = Transform3d.apply(@p2, mat)
|
||||
pp3, w3 = Transform3d.apply(@p3, mat)
|
||||
|
||||
pt1 = @t1 / w1
|
||||
pt2 = @t2 / w2
|
||||
pt3 = @t3 / w3
|
||||
|
||||
Tri.new(
|
||||
pp1, pp2, pp3,
|
||||
@t1,
|
||||
@t2,
|
||||
@t3,
|
||||
pt1, pt2, pt3,
|
||||
@color
|
||||
)
|
||||
end
|
||||
|
|
12
src/line.cr
12
src/line.cr
|
@ -2,9 +2,9 @@ require "./vector"
|
|||
|
||||
module PF
|
||||
struct Line(T)
|
||||
property p1 : Vector2(T), p2 : Vector2(T)
|
||||
property p1 : T, p2 : T
|
||||
|
||||
def initialize(@p1 : Vector2(T), @p2 : Vector2(T))
|
||||
def initialize(@p1 : T, @p2 : T)
|
||||
end
|
||||
|
||||
def rise
|
||||
|
@ -66,16 +66,18 @@ module PF
|
|||
(@p2 - @p1) * t + @p1
|
||||
end
|
||||
|
||||
# Return the length of the line
|
||||
def length
|
||||
Math.sqrt((run.abs * 2) + (rise.abs * 2))
|
||||
Math.sqrt(((@p2 - @p1) ** 2).sum)
|
||||
end
|
||||
|
||||
def /(n : (Float | Int))
|
||||
Line.new(@p1 / n, @p2 / n)
|
||||
end
|
||||
|
||||
def to_point
|
||||
Vector[run, rise]
|
||||
# Convert this line into a normalized vector
|
||||
def to_vector
|
||||
(@p2 - @p1).normalized
|
||||
end
|
||||
|
||||
# Find the normal axis to this line
|
||||
|
|
|
@ -61,7 +61,7 @@ module PF
|
|||
end
|
||||
|
||||
# Draw a textured triangle
|
||||
def fill_triangle(p1 : Vector2, p2 : Vector2, p3 : Vector2, t1 : Vector2, t2 : Vector2, t3 : Vector2, sprite : Sprite, color : Pixel = Pixel.white)
|
||||
def fill_triangle(p1 : Vector2, p2 : Vector2, p3 : Vector2, t1 : Vector3, t2 : Vector3, t3 : Vector3, sprite : Sprite, color : Pixel = Pixel.white)
|
||||
# Sort points from top to bottom
|
||||
p1, p2, t1, t2 = p2, p1, t2, t1 if p2.y < p1.y
|
||||
p1, p3, t1, t3 = p3, p1, t3, t1 if p3.y < p1.y
|
||||
|
@ -114,6 +114,7 @@ module PF
|
|||
|
||||
# Get the normalized t value for this height level
|
||||
ty = height > 0 ? y / height : 0.0
|
||||
|
||||
# LERP both texture edges at the y position to create a new line
|
||||
tyl =
|
||||
if switch_left
|
||||
|
@ -148,10 +149,14 @@ module PF
|
|||
x_left.upto(x_right) do |x|
|
||||
# LERP the line between the texture edges
|
||||
t = scan_size == 0 ? 0.0 : (x - x_left) / scan_size
|
||||
# Multiply the point by the size of the sprite to get the final texture point
|
||||
sample_point = texture_line.lerp(t) * sprite.size
|
||||
pixel = sprite.sample((sample_point + 0.5).to_i)
|
||||
texture_point = texture_line.lerp(t)
|
||||
|
||||
# Get the x and y of the texture coords, divide by z for perspective, then
|
||||
# multiply the point by the size of the sprite to get the final texture point
|
||||
sample_point = Vector[texture_point.x / texture_point.z, texture_point.y / texture_point.z] * sprite.size
|
||||
pixel = sprite.sample(sample_point.to_i)
|
||||
|
||||
# Blend the pixel sample with the provided color
|
||||
pixel.r = (pixel.r * (color.r / 255)).to_u8
|
||||
pixel.g = (pixel.g * (color.g / 255)).to_u8
|
||||
pixel.b = (pixel.b * (color.b / 255)).to_u8
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require "./matrix"
|
||||
|
||||
module PF
|
||||
module Vector
|
||||
abstract struct Vector
|
||||
# Creates a new `Vector` with the given *args*
|
||||
#
|
||||
# ```
|
||||
|
@ -18,7 +18,7 @@ module PF
|
|||
|
||||
{% for i in 2..4 %}
|
||||
{% vars = %w[x y z w] %}
|
||||
struct Vector{{i}}(T)
|
||||
struct Vector{{i}}(T) < Vector
|
||||
{% for arg in 0...i %}
|
||||
property {{vars[arg].id}} : T
|
||||
{% end %}
|
||||
|
@ -64,7 +64,7 @@ module PF
|
|||
end
|
||||
{% end %}
|
||||
|
||||
{% for op in %w[* / // + - %] %}
|
||||
{% for op in %w[* / // + - % **] %}
|
||||
# Applies `{{op.id}}` to all component of this vector with the corresponding component of *other*
|
||||
def {{ op.id }}(other : Vector{{i}})
|
||||
Vector[{% for arg in 0...i %} @{{vars[arg].id}} {{op.id}} other.{{vars[arg].id}}, {% end %}]
|
||||
|
@ -76,6 +76,13 @@ module PF
|
|||
end
|
||||
{% end %}
|
||||
|
||||
# Add all components together
|
||||
def sum
|
||||
{% for arg in 0...i %}
|
||||
@{{vars[arg].id}} {% if arg != i - 1 %} + {% end %}
|
||||
{% end %}
|
||||
end
|
||||
|
||||
# The length or magnitude of the vector calculated by the Pythagorean theorem
|
||||
def magnitude
|
||||
Math.sqrt({% for arg in 0...i %} @{{vars[arg].id}} ** 2 {% if arg != i - 1 %} + {% end %}{% end %})
|
||||
|
|
Loading…
Reference in a new issue