Skip to content

laszlokorte/sqlite-3d-mesh

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SQLite 3D Renderer

Screenshot


Live Demo

This is a demo of projecting 3d triangles via SQL queries.

Think of SELECT project(...) as x, project(...) as y FROM model, vertex, camera, transform WHERE clockwise AND clipped IN BETWEEN -1 AND 1

SQL Schema

CREATE TABLE camera (
	id INTEGER PRIMARY KEY AUTOINCREMENT
	,tx REAL NOT NULL
	,ty REAL NOT NULL
	,tz REAL NOT NULL
	,near REAL NOT NULL
	,far REAL NOT NULL
	,fov REAL NOT NULL
	,aspect REAL NOT NULL
	) STRICT

CREATE TABLE viewport (
	id INTEGER PRIMARY KEY AUTOINCREMENT
	,width REAL NOT NULL
	,height REAL NOT NULL
	,camera_id INTEGER NOT NULL REFERENCES camera(id) ON DELETE CASCADE
	) STRICT

CREATE TABLE model (id INTEGER PRIMARY KEY AUTOINCREMENT) STRICT

CREATE TABLE model_transform (
	id INTEGER PRIMARY KEY AUTOINCREMENT
	,model_id INTEGER NOT NULL UNIQUE REFERENCES model(id) ON DELETE CASCADE
	,tx REAL NOT NULL DEFAULT 0.0
	,ty REAL NOT NULL DEFAULT 0.0
	,tz REAL NOT NULL DEFAULT 0.0
	,rx REAL NOT NULL DEFAULT 0.0
	,ry REAL NOT NULL DEFAULT 0.0
	,rz REAL NOT NULL DEFAULT 0.0
	,sx REAL NOT NULL DEFAULT 1.0
	,sy REAL NOT NULL DEFAULT 1.0
	,sz REAL NOT NULL DEFAULT 1.0
	) STRICT

CREATE TABLE vertex (
	id INTEGER PRIMARY KEY AUTOINCREMENT
	,model_id INTEGER NOT NULL REFERENCES model(id) ON DELETE CASCADE
	,x REAL NOT NULL
	,y REAL NOT NULL
	,z REAL NOT NULL
	) STRICT

CREATE VIEW model_vertex
AS
SELECT v.id AS vertex_id
	,m.id AS model_id
	,((cos(COALESCE(mt.ry, 0)) * cos(COALESCE(mt.rz, 0)) * (v.x * COALESCE(mt.sx, 1)) + (- cos(COALESCE(mt.ry, 0)) * sin(COALESCE(mt.rz, 0))) * (v.y * COALESCE(mt.sy, 1)) + sin(COALESCE(mt.ry, 0)) * (v.z * COALESCE(mt.sz, 1))) - COALESCE(mt.tx, 0)) AS x
	,((((cos(COALESCE(mt.rx, 0)) * sin(COALESCE(mt.rz, 0)) + sin(COALESCE(mt.rx, 0)) * sin(COALESCE(mt.ry, 0)) * cos(COALESCE(mt.rz, 0))) * (v.x * COALESCE(mt.sx, 1)) + (cos(COALESCE(mt.rx, 0)) * cos(COALESCE(mt.rz, 0)) - sin(COALESCE(mt.rx, 0)) * sin(COALESCE(mt.ry, 0)) * sin(COALESCE(mt.rz, 0))) * (v.y * COALESCE(mt.sy, 1)) + (- sin(COALESCE(mt.rx, 0)) * cos(COALESCE(mt.ry, 0))) * (v.z * COALESCE(mt.sz, 1)))) - COALESCE(mt.ty, 0)) AS y
	,(((sin(COALESCE(mt.rx, 0)) * sin(COALESCE(mt.rz, 0)) - cos(COALESCE(mt.rx, 0)) * sin(COALESCE(mt.ry, 0)) * cos(COALESCE(mt.rz, 0))) * (v.x * COALESCE(mt.sx, 1)) + (sin(COALESCE(mt.rx, 0)) * cos(COALESCE(mt.rz, 0)) + cos(COALESCE(mt.rx, 0)) * sin(COALESCE(mt.ry, 0)) * sin(COALESCE(mt.rz, 0))) * (v.y * COALESCE(mt.sy, 1)) + (cos(COALESCE(mt.rx, 0)) * cos(COALESCE(mt.ry, 0))) * (v.z * COALESCE(mt.sz, 1))) - COALESCE(mt.tz, 0)) AS z
FROM vertex v
INNER JOIN model m ON m.id = v.model_id
INNER JOIN model_transform mt ON mt.model_id = m.id

CREATE VIEW camera_vertex
AS
SELECT v.vertex_id AS vertex_id
	,c.id AS camera_id
	,(v.x - c.tx) AS x
	,(v.y - c.ty) AS y
	,(v.z - c.tz) AS z
FROM model_vertex v
	,camera c

CREATE VIEW perspective_vertex
AS
SELECT v.vertex_id AS vertex_id
	,v.camera_id AS camera_id
	,(v.x / tan(c.fov / 2) * c.aspect) AS x
	,(v.y / tan(c.fov / 2)) AS y
	,(- v.z * ((c.far + c.near) / (c.far - c.near)) - ((2 * c.far * c.near) / (c.far - c.near))) AS z
	,- v.z AS w
FROM camera_vertex v
INNER JOIN camera c ON c.id = v.camera_id

CREATE VIEW ndc_vertex
AS
SELECT v.vertex_id AS vertex_id
	,v.camera_id AS camera_id
	,(v.x / v.w) AS x
	,(v.y / v.w) AS y
	,(v.z / v.w) AS z
	,v.w AS w
FROM perspective_vertex v

CREATE VIEW ndc_edge
AS
SELECT edge.id AS id
	,a.camera_id AS camera_id
	,(a.x / a.w) AS x1
	,(a.y / a.w) AS y1
	,(a.z / a.w) AS z1
	,(a.w / a.w) AS w1
	,(b.x / b.w) AS x2
	,(b.y / b.w) AS y2
	,(b.z / b.w) AS z2
	,b.w AS w2
FROM edge
INNER JOIN perspective_vertex a ON a.vertex_id = edge.start_vertex_id
INNER JOIN perspective_vertex b ON b.vertex_id = edge.end_vertex_id
WHERE a.camera_id = b.camera_id

CREATE VIEW projected_vertex
AS
SELECT vp.id AS viewport_id
	,v.vertex_id AS vertex_id
	,v.camera_id AS camera_id
	,vp.width * (0.5 + 0.5 * v.x) AS x
	,vp.height * (0.5 + 0.5 * v.y) AS y
	,v.z AS z
	,v.w AS w
FROM ndc_vertex v
INNER JOIN viewport vp ON vp.camera_id = v.camera_id
WHERE abs(v.x) < 1
	AND abs(v.y) < 1
	AND abs(v.z) < 1

CREATE VIEW projected_edge
AS
SELECT vp.id AS viewport_id
	,e.id AS edge_id
	,e.camera_id AS camera_id
	,vp.width * (0.5 + 0.5 * e.x1) AS x1
	,vp.height * (0.5 + 0.5 * e.y1) AS y1
	,e.z1 AS z1
	,e.w1 AS w1
	,vp.width * (0.5 + 0.5 * e.x2) AS x2
	,vp.height * (0.5 + 0.5 * e.y2) AS y2
	,e.z2 AS z2
	,e.w2 AS w2
FROM ndc_edge e
INNER JOIN viewport vp ON vp.camera_id = e.camera_id
WHERE abs(e.x1) < 1
	AND abs(e.y1) < 1
	AND abs(e.z1) < 1
	AND abs(e.x2) < 1
	AND abs(e.y2) < 1
	AND abs(e.z2) < 1

CREATE VIEW projected_face
AS
SELECT fv.model_id AS model_id
	,v.viewport_id AS viewport_id
	,

IF (
		face_area.area_twice > 0
		,"blue"
		,"red"
		) AS clockcolor
	,face_area.area_twice > 0 AS clockwise
	,face.id AS face_id
	,v.vertex_id AS vertex_id
	,GROUP_CONCAT(CONCAT (
			v.x
			,", "
			,v.y
			), ' ') AS points FROM face INNER JOIN face_projected_signed_area face_area ON face_area.face_id = face.id INNER JOIN face_vertex fv ON fv.face_id = face.id INNER JOIN projected_vertex v ON v.vertex_id = fv.vertex_id GROUP BY fv.face_id
	,fv.model_id ORDER BY face_area.area_twice ASC
	,MIN(v.z) DESC
	CREATE TABLE edge (
		id INTEGER PRIMARY KEY AUTOINCREMENT
		,model_id INTEGER NOT NULL REFERENCES model(id) ON DELETE CASCADE
		,start_vertex_id INTEGER NOT NULL REFERENCES vertex(id) ON DELETE CASCADE
		,end_vertex_id INTEGER NOT NULL REFERENCES vertex(id) ON DELETE CASCADE
		) STRICT

CREATE TABLE face (
	id INTEGER PRIMARY KEY AUTOINCREMENT
	,model_id INTEGER NOT NULL REFERENCES model(id) ON DELETE CASCADE
	) STRICT

CREATE TABLE face_vertex (
	id INTEGER PRIMARY KEY AUTOINCREMENT
	,model_id INTEGER NOT NULL REFERENCES model(id) ON DELETE CASCADE
	,face_id INTEGER NOT NULL REFERENCES face(id) ON DELETE CASCADE
	,vertex_id INTEGER NOT NULL REFERENCES vertex(id) ON DELETE CASCADE
	,sort INTEGER
	) STRICT

CREATE VIEW face_vertex_neighbor
AS
SELECT face_vertex.*
	,LEAD(face_vertex.vertex_id) OVER w AS next_vertex_id
	,LAG(face_vertex.vertex_id) OVER w AS prev_vertex_id
FROM face_vertex WINDOW w AS (
		PARTITION BY face_vertex.face_id ORDER BY sort
		)

CREATE VIEW face_vertex_neighbor_wrapped
AS
SELECT
INNER.face_id AS face_id
	,
INNER.vertex_id AS vertex_id
	,COALESCE(next_vertex_id, first_id) AS id_next
	,COALESCE(prev_vertex_id, last_id) AS id_prev
FROM (
	SELECT fv.*
		,fvn.next_vertex_id AS next_vertex_id
		,fvn.prev_vertex_id AS prev_vertex_id
		,FIRST_VALUE(fvn.vertex_id) OVER (
			PARTITION BY fvn.face_id ORDER BY fvn.sort
			) AS first_id
		,FIRST_VALUE(fvn.vertex_id) OVER (
			PARTITION BY fvn.face_id ORDER BY - fvn.sort
			) AS last_id
	FROM face_vertex_neighbor fvn
	INNER JOIN face_vertex fv ON fv.id = fvn.id
	) AS
INNER

CREATE VIEW face_projected_signed_area
AS
SELECT fvw.face_id AS face_id
	,SUM((v1.x * v2.y) - (v2.x * v1.y)) AS area_twice
FROM face_vertex_neighbor_wrapped fvw
INNER JOIN projected_vertex v1 ON v1.vertex_id = fvw.vertex_id
INNER JOIN projected_vertex v2 ON v2.vertex_id = fvw.id_next
GROUP BY fvw.face_id

Data

INSERT INTO viewport (id,camera_id,width,height)
VALUES (1,1,1280,1080);

INSERT INTO camera (id,tx,ty,tz,near,far,fov,aspect)
VALUES (1,0,0,50,0.1,100,1,1);

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published