mirror of
https://github.com/SleepingInsomniac/pixelfaucet
synced 2025-01-24 07:58:18 +01:00
Update clipping
This commit is contained in:
parent
926a345c9b
commit
0eb0eb2449
3 changed files with 77 additions and 36 deletions
|
@ -111,22 +111,37 @@ class ThreeDee < PF::Game
|
||||||
@depth_buffer,
|
@depth_buffer,
|
||||||
tri.color
|
tri.color
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if tri.clipped
|
||||||
|
p1 = PF::Vector[tri.p1.x.to_i, tri.p1.y.to_i]
|
||||||
|
p2 = PF::Vector[tri.p2.x.to_i, tri.p2.y.to_i]
|
||||||
|
p3 = PF::Vector[tri.p3.x.to_i, tri.p3.y.to_i]
|
||||||
|
draw_triangle(p1, p2, p3, PF::Pixel.new(255, 255, 0))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
tris = @projector.project(@model.tris)
|
tris = @projector.project(@model.tris, sort: true)
|
||||||
tris.each do |tri|
|
tris.each do |tri|
|
||||||
# Rasterize all triangles
|
# Rasterize all triangles
|
||||||
|
|
||||||
|
p1 = PF::Vector[tri.p1.x.to_i, tri.p1.y.to_i]
|
||||||
|
p2 = PF::Vector[tri.p2.x.to_i, tri.p2.y.to_i]
|
||||||
|
p3 = PF::Vector[tri.p3.x.to_i, tri.p3.y.to_i]
|
||||||
|
|
||||||
fill_triangle(
|
fill_triangle(
|
||||||
PF::Vector[tri.p1.x.to_i, tri.p1.y.to_i],
|
p1,
|
||||||
PF::Vector[tri.p2.x.to_i, tri.p2.y.to_i],
|
p2,
|
||||||
PF::Vector[tri.p3.x.to_i, tri.p3.y.to_i],
|
p3,
|
||||||
pixel: tri.color # buffer: @depth_buffer
|
pixel: tri.color # buffer: @depth_buffer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if tri.clipped
|
||||||
|
draw_triangle(p1, p2, p3, PF::Pixel.new(255, 0, 0))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
string = String.build do |io|
|
string = String.build do |io|
|
||||||
io << "Triangles: " << tris.size + cube_tris.size
|
io << "Triangles: " << cube_tris.size + tris.size
|
||||||
io << "\nPosition: "
|
io << "\nPosition: "
|
||||||
io << "x: " << @camera.position.x.round(2)
|
io << "x: " << @camera.position.x.round(2)
|
||||||
io << "y: " << @camera.position.y.round(2)
|
io << "y: " << @camera.position.y.round(2)
|
||||||
|
|
|
@ -6,18 +6,20 @@ module PF
|
||||||
getter width : Int32 | Float64
|
getter width : Int32 | Float64
|
||||||
getter height : Int32 | Float64
|
getter height : Int32 | Float64
|
||||||
property near = 0.1
|
property near = 0.1
|
||||||
property far = 1000.0
|
property far = 50.0
|
||||||
getter fov = 90.0
|
getter fov = 70.0
|
||||||
property aspect_ratio : Float64?
|
property aspect_ratio : Float64?
|
||||||
property camera : Camera
|
property camera : Camera
|
||||||
property light : Vector3(Float64) = Vector3.new(0.0, 0.0, -1.0).normalized
|
property light : Vector3(Float64) = Vector3.new(0.0, 0.0, -1.0).normalized
|
||||||
property mat_proj : Matrix(Float64, 16)?
|
property mat_proj : Matrix(Float64, 16)?
|
||||||
property clipping_plane_near : Vector3(Float64)
|
property clipping_plane_near : Vector3(Float64)
|
||||||
property near_plane_normal : Vector3(Float64) = Vector3.new(0.0, 0.0, 1.0)
|
property clipping_plane_far : Vector3(Float64)
|
||||||
|
|
||||||
@fov_rad : Float64?
|
@fov_rad : Float64?
|
||||||
|
|
||||||
def initialize(@width, @height, @camera = Camera.new)
|
def initialize(@width, @height, @camera = Camera.new)
|
||||||
@clipping_plane_near = Vector3.new(0.0, 0.0, @near)
|
@clipping_plane_near = Vector3.new(0.0, 0.0, @near)
|
||||||
|
@clipping_plane_far = Vector3.new(0.0, 0.0, @far)
|
||||||
end
|
end
|
||||||
|
|
||||||
def mat_proj
|
def mat_proj
|
||||||
|
@ -58,43 +60,51 @@ module PF
|
||||||
def project(tris : Array(Tri), camera = @camera, sort : Bool = false)
|
def project(tris : Array(Tri), camera = @camera, sort : Bool = false)
|
||||||
mat_view = camera.view_matrix
|
mat_view = camera.view_matrix
|
||||||
|
|
||||||
# only draw triangles facing the camera
|
# Only draw triangles facing the camera
|
||||||
tris = tris.select do |tri|
|
tris = tris.select do |tri|
|
||||||
tri.normal.dot(tri.p1 - camera.position) < 0.0
|
tri.normal.dot(tri.p1 - camera.position) < 0.0
|
||||||
end
|
end
|
||||||
|
|
||||||
# Iterate tris to transform into view, project, and clip
|
# Iterate tris to transform into
|
||||||
0.upto(tris.size - 1) do
|
tris = tris.map do |tri|
|
||||||
tri = tris.pop
|
|
||||||
shade = (tri.normal.dot(light) + 1.0) / 2 # light should be normalized
|
shade = (tri.normal.dot(light) + 1.0) / 2 # light should be normalized
|
||||||
tri.color = tri.color * shade
|
tri.color = tri.color * shade
|
||||||
|
tri * mat_view
|
||||||
|
end
|
||||||
|
|
||||||
tri *= mat_view
|
# Clip tris
|
||||||
|
{
|
||||||
# Clip against the near plane
|
{clipping_plane_near, Vector[0.0, 0.0, 1.0]},
|
||||||
tri.clip(plane: clipping_plane_near, plane_normal: near_plane_normal).each do |tri|
|
{clipping_plane_far, Vector[0.0, 0.0, -1.0]},
|
||||||
tri *= mat_proj
|
}.each do |clip|
|
||||||
|
0.upto(tris.size - 1) do
|
||||||
# Invert the y axis
|
tri = tris.pop
|
||||||
tri.p1.y = tri.p1.y * -1.0
|
tri.clip(plane: clip[0], plane_normal: clip[1]).each do |tri|
|
||||||
tri.p2.y = tri.p2.y * -1.0
|
|
||||||
tri.p3.y = tri.p3.y * -1.0
|
|
||||||
|
|
||||||
# scale into screen space
|
|
||||||
tri.p1 += 1.0
|
|
||||||
tri.p2 += 1.0
|
|
||||||
tri.p3 += 1.0
|
|
||||||
|
|
||||||
tri.p1.x = tri.p1.x * 0.5 * width
|
|
||||||
tri.p1.y = tri.p1.y * 0.5 * height
|
|
||||||
tri.p2.x = tri.p2.x * 0.5 * width
|
|
||||||
tri.p2.y = tri.p2.y * 0.5 * height
|
|
||||||
tri.p3.x = tri.p3.x * 0.5 * width
|
|
||||||
tri.p3.y = tri.p3.y * 0.5 * height
|
|
||||||
|
|
||||||
tris.unshift(tri)
|
tris.unshift(tri)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Project the triangles
|
||||||
|
tris = tris.map do |tri|
|
||||||
|
z = tri.z
|
||||||
|
tri *= mat_proj
|
||||||
|
tri.z = z
|
||||||
|
|
||||||
|
tri.map_points do |point|
|
||||||
|
# Invert the y axis
|
||||||
|
point.y *= -1.0
|
||||||
|
|
||||||
|
# scale into screen space
|
||||||
|
point += 1.0
|
||||||
|
point.x *= 0.5 * width
|
||||||
|
point.y *= 0.5 * height
|
||||||
|
|
||||||
|
point
|
||||||
|
end
|
||||||
|
|
||||||
|
tri
|
||||||
|
end
|
||||||
|
|
||||||
# sort triangles, no need to do this if using a depth buffer
|
# sort triangles, no need to do this if using a depth buffer
|
||||||
tris.sort! { |a, b| b.z <=> a.z } if sort
|
tris.sort! { |a, b| b.z <=> a.z } if sort
|
||||||
|
|
|
@ -12,14 +12,15 @@ module PF
|
||||||
property t2 : Vector3(Float64) = Vector[0.0, 0.0, 0.0]
|
property t2 : Vector3(Float64) = Vector[0.0, 0.0, 0.0]
|
||||||
property t3 : Vector3(Float64) = Vector[0.0, 0.0, 0.0]
|
property t3 : Vector3(Float64) = Vector[0.0, 0.0, 0.0]
|
||||||
|
|
||||||
property color : PF::Pixel
|
property color : Pixel
|
||||||
|
|
||||||
|
getter clipped : Bool = false
|
||||||
setter normal : Vector3(Float64)?
|
setter normal : Vector3(Float64)?
|
||||||
|
|
||||||
def initialize(@p1 : Vector3(Float64), @p2 : Vector3(Float64), @p3 : Vector3(Float64), @color = PF::Pixel::White, @normal = nil)
|
def initialize(@p1 : Vector3(Float64), @p2 : Vector3(Float64), @p3 : Vector3(Float64), @color = PF::Pixel::White, @normal = nil, @clipped = false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(@p1, @p2, @p3, @t1, @t2, @t3, @color = PF::Pixel::White)
|
def initialize(@p1, @p2, @p3, @t1, @t2, @t3, @color = PF::Pixel::White, @clipped = false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return the normal assuming clockwise pointing winding
|
# Return the normal assuming clockwise pointing winding
|
||||||
|
@ -46,6 +47,18 @@ module PF
|
||||||
(@p1.z + @p2.z + @p3.z) / 3.0
|
(@p1.z + @p2.z + @p3.z) / 3.0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def z=(value : Float64)
|
||||||
|
@p1.z = value
|
||||||
|
@p2.z = value
|
||||||
|
@p3.z = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def map_points
|
||||||
|
@p1 = yield @p1
|
||||||
|
@p2 = yield @p2
|
||||||
|
@p3 = yield @p3
|
||||||
|
end
|
||||||
|
|
||||||
# Multiply all points by a *Matrix*, returning a new *Tri*
|
# Multiply all points by a *Matrix*, returning a new *Tri*
|
||||||
def *(mat : Matrix)
|
def *(mat : Matrix)
|
||||||
# The transform function returns a w, which is the 4th component of the vertex
|
# The transform function returns a w, which is the 4th component of the vertex
|
||||||
|
@ -119,7 +132,8 @@ module PF
|
||||||
Tri.new(
|
Tri.new(
|
||||||
inside_points[0], clip_p1, clip_p2,
|
inside_points[0], clip_p1, clip_p2,
|
||||||
inside_texts[0], int_t1, int_t2,
|
inside_texts[0], int_t1, int_t2,
|
||||||
color: @color
|
color: @color,
|
||||||
|
clipped: true
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -141,14 +155,16 @@ module PF
|
||||||
Tri.new(
|
Tri.new(
|
||||||
inside_points[0], inside_points[1], clip_p1,
|
inside_points[0], inside_points[1], clip_p1,
|
||||||
inside_texts[0], inside_texts[1], int_t1,
|
inside_texts[0], inside_texts[1], int_t1,
|
||||||
color: @color
|
color: @color,
|
||||||
|
clipped: true
|
||||||
),
|
),
|
||||||
# The second triangle will have the second inside point, the second intersection, then the first intersection
|
# The second triangle will have the second inside point, the second intersection, then the first intersection
|
||||||
# This order preserves clockwise winding
|
# This order preserves clockwise winding
|
||||||
Tri.new(
|
Tri.new(
|
||||||
inside_points[1], clip_p2, clip_p1,
|
inside_points[1], clip_p2, clip_p1,
|
||||||
inside_texts[1], int_t2, int_t1,
|
inside_texts[1], int_t2, int_t1,
|
||||||
color: @color
|
color: @color,
|
||||||
|
clipped: true
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue