shithub: libgraphics

Download patch

ref: d3516b11559657935d70829c672f29393e857b8e
parent: 6e461add61d35d23f733cffb5064a286419b79b0
author: rodri <rgl@antares-labs.eu>
date: Mon May 20 16:20:48 EDT 2024

fix the perspective projection and add inverse xform functions.

--- a/graphics.h
+++ b/graphics.h
@@ -276,10 +276,19 @@
 
 /* render */
 Renderer *initgraphics(void);
+
+/* xform */
 Point3 model2world(Entity*, Point3);
 Point3 world2vcs(Camera*, Point3);
 Point3 vcs2clip(Camera*, Point3);
 Point3 world2clip(Camera*, Point3);
+Point3 clip2ndc(Point3);
+Point3 ndc2viewport(Framebuf*, Point3);
+Point3 viewport2ndc(Framebuf*, Point3);
+Point3 ndc2vcs(Camera*, Point3);
+Point3 viewport2vcs(Camera*, Point3);
+Point3 vcs2world(Camera*, Point3);
+Point3 viewport2world(Camera*, Point3);
 void perspective(Matrix3, double, double, double, double);
 void orthographic(Matrix3, double, double, double, double, double, double);
 
--- a/mkfile
+++ b/mkfile
@@ -6,6 +6,7 @@
 	viewport.$O\
 	render.$O\
 	clip.$O\
+	xform.$O\
 	scene.$O\
 	vertex.$O\
 	texture.$O\
--- a/render.c
+++ b/render.c
@@ -52,118 +52,6 @@
 	return sa <= 0;
 }
 
-/*
- * transforms p from e's reference frame into
- * the world.
- */
-Point3
-model2world(Entity *e, Point3 p)
-{
-	return invrframexform3(p, *e);
-}
-
-/*
- * transforms p from the world reference frame
- * to c's one (aka Viewing Coordinate System).
- */
-Point3
-world2vcs(Camera *c, Point3 p)
-{
-	return rframexform3(p, *c);
-}
-
-/*
- * projects p from the VCS to clip space, placing
- * p.[xyz] ∈ (-∞,-w)∪[-w,w]∪(w,∞) where [-w,w]
- * represents the visibility volume.
- *
- * the clipping planes are:
- *
- * 	|   -w   |   w   |
- *	+----------------+
- * 	| left   | right |
- * 	| bottom | top   |
- * 	| far    | near  |
- */
-Point3
-vcs2clip(Camera *c, Point3 p)
-{
-	return xform3(p, c->proj);
-}
-
-Point3
-world2clip(Camera *c, Point3 p)
-{
-	return vcs2clip(c, world2vcs(c, p));
-}
-
-/*
- * performs the perspective division, placing
- * p.[xyz] ∈ [-1,1] and p.w = 1/z
- * (aka Normalized Device Coordinates).
- *
- * p.w is kept as z⁻¹ so we can later do
- * perspective-correct attribute interpolation.
- */
-static Point3
-clip2ndc(Point3 p)
-{
-	p.w = p.w == 0? 1: 1.0/p.w;
-	p.x *= p.w;
-	p.y *= p.w;
-	p.z *= p.w;
-	return p;
-}
-
-/*
- * scales p to fit the destination viewport,
- * placing p.x ∈ [0,width], p.y ∈ [0,height],
- * p.z ∈ [0,1] and leaving p.w intact.
- */
-static Point3
-ndc2viewport(Framebuf *fb, Point3 p)
-{
-	Matrix3 view = {
-		Dx(fb->r)/2.0,             0,       0,       Dx(fb->r)/2.0,
-		0,            -Dy(fb->r)/2.0,       0,       Dy(fb->r)/2.0,
-		0,                         0, 1.0/2.0,             1.0/2.0,
-		0,                         0,       0,                   1,
-	};
-	double w;
-
-	w = p.w;
-	p.w = 1;
-	p = xform3(p, view);
-	p.w = w;
-	return p;
-}
-
-void
-perspective(Matrix3 m, double fov, double a, double n, double f)
-{
-	double cotan;
-
-	cotan = 1/tan(fov/2);
-	identity3(m);
-	m[0][0] =  cotan/a;
-	m[1][1] =  cotan;
-	m[2][2] =  (f+n)/(f-n);
-	m[2][3] = -2*f*n/(f-n);
-	m[3][2] = -1;
-}
-
-void
-orthographic(Matrix3 m, double l, double r, double b, double t, double n, double f)
-{
-	identity3(m);
-	m[0][0] =  2/(r - l);
-	m[1][1] =  2/(t - b);
-	m[2][2] = -2/(f - n);
-	m[0][3] = -(r + l)/(r - l);
-	m[1][3] = -(t + b)/(t - b);
-	m[2][3] = -(f + n)/(f - n);
-}
-
 static void
 rasterize(Rastertask *task)
 {
--- /dev/null
+++ b/xform.c
@@ -1,0 +1,167 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <geometry.h>
+#include "libobj/obj.h"
+#include "graphics.h"
+#include "internal.h"
+
+/*
+ * transforms p from e's reference frame into
+ * the world.
+ */
+Point3
+model2world(Entity *e, Point3 p)
+{
+	return invrframexform3(p, *e);
+}
+
+/*
+ * transforms p from the world reference frame
+ * to c's one (aka Viewing Coordinate System).
+ */
+Point3
+world2vcs(Camera *c, Point3 p)
+{
+	return rframexform3(p, *c);
+}
+
+/*
+ * projects p from the VCS to clip space, placing
+ * p.[xyz] ∈ (-∞,-w)∪[-w,w]∪(w,∞) where [-w,w]
+ * represents the visibility volume.
+ *
+ * the clipping planes are:
+ *
+ * 	|   -w   |   w   |
+ *	+----------------+
+ * 	| left   | right |
+ * 	| bottom | top   |
+ * 	| far    | near  |
+ */
+Point3
+vcs2clip(Camera *c, Point3 p)
+{
+	return xform3(p, c->proj);
+}
+
+Point3
+world2clip(Camera *c, Point3 p)
+{
+	return vcs2clip(c, world2vcs(c, p));
+}
+
+/*
+ * performs the perspective division, placing
+ * p.[xyz] ∈ [-1,1] and p.w = 1/z
+ * (aka Normalized Device Coordinates).
+ *
+ * p.w is kept as z⁻¹ so we can later do
+ * perspective-correct attribute interpolation.
+ */
+Point3
+clip2ndc(Point3 p)
+{
+	p.w = p.w == 0? 1: 1.0/p.w;
+	p.x *= p.w;
+	p.y *= p.w;
+	p.z *= p.w;
+	return p;
+}
+
+/*
+ * scales p to fit the destination viewport,
+ * placing p.x ∈ [0,width], p.y ∈ [0,height],
+ * p.z ∈ [0,1] and leaving p.w intact.
+ */
+Point3
+ndc2viewport(Framebuf *fb, Point3 p)
+{
+	Matrix3 view = {
+		Dx(fb->r)/2.0,             0,       0,       Dx(fb->r)/2.0,
+		0,            -Dy(fb->r)/2.0,       0,       Dy(fb->r)/2.0,
+		0,                         0, 1.0/2.0,             1.0/2.0,
+		0,                         0,       0,                   1,
+	};
+	double w;
+
+	w = p.w;
+	p.w = 1;
+	p = xform3(p, view);
+	p.w = w;
+	return p;
+}
+
+Point3
+viewport2ndc(Framebuf *fb, Point3 p)
+{
+	p.x = 2*p.x/Dx(fb->r) - 1;
+	p.y = 1 - 2*p.y/Dy(fb->r);
+	p.z = 2*p.z - 1;
+	p.w = 1;
+	return p;
+}
+
+Point3
+ndc2vcs(Camera *c, Point3 p)
+{
+	Matrix3 invproj;
+	Point3 np;
+
+	memmove(invproj, c->proj, 4*4*sizeof(double));
+	invm3(invproj);
+	np = xform3(p, invproj);
+	np.w = np.w == 0? 0: 1.0/np.w;
+	np.x *= np.w;
+	np.y *= np.w;
+	np.z *= np.w;
+	np.w = 1;
+	return np;
+}
+
+Point3
+viewport2vcs(Camera *c, Point3 p)
+{
+	return ndc2vcs(c, viewport2ndc(c->vp->getfb(c->vp), p));
+}
+
+Point3
+vcs2world(Camera *c, Point3 p)
+{
+	return invrframexform3(p, *c);
+}
+
+Point3
+viewport2world(Camera *c, Point3 p)
+{
+	return vcs2world(c, viewport2vcs(c, p));
+}
+
+void
+perspective(Matrix3 m, double fovy, double a, double n, double f)
+{
+	double cotan;
+
+	cotan = 1/tan(fovy/2);
+	identity3(m);
+	m[0][0] =  cotan/a;
+	m[1][1] =  cotan;
+	m[2][2] =  (f+n)/(f-n);
+	m[2][3] =  2*f*n/(f-n);
+	m[3][2] = -1;
+	m[3][3] = 0;
+}
+
+void
+orthographic(Matrix3 m, double l, double r, double b, double t, double n, double f)
+{
+	identity3(m);
+	m[0][0] =  2/(r-l);
+	m[1][1] =  2/(t-b);
+	m[2][2] =  2/(f-n);
+	m[0][3] = -(r+l)/(r-l);
+	m[1][3] = -(t+b)/(t-b);
+	m[2][3] = -(f+n)/(f-n);
+}