Added isometric projection

This commit is contained in:
Maciej Samborski 2024-12-26 19:02:14 +01:00
parent ab532a2608
commit bdde494b5b
6 changed files with 286 additions and 73 deletions

View File

@ -70,6 +70,9 @@ class Vec3 {
this.y -= other.y;
this.z -= other.z;
}
splatToArray() {
return [this.x, this.y, this.z];
}
}
class Vec4 {
x;
@ -146,6 +149,22 @@ class Mat4 {
]);
return new Mat4(data);
}
static isometric() {
//let m = new Mat4(new Float32Array([
// Math.sqrt(3), 0, -Math.sqrt(3), 0,
// 1, 2, 1, 0,
// Math.sqrt(2), -Math.sqrt(2), Math.sqrt(2), 0,
// 0, 0, 0, 1,
//]));
//m.multScalar(1 / Math.sqrt(6));
let m = new Mat4(new Float32Array([
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
return m;
}
static rotation_x(angle) {
let data = new Float32Array([
1, 0, 0, 0,
@ -218,7 +237,7 @@ class Mat4 {
vec.w = w;
return vec;
}
mult(other) {
multNew(other) {
let m = new Mat4(0);
for (let i = 0; i < 4; ++i) {
for (let j = 0; j < 4; ++j) {
@ -230,5 +249,10 @@ class Mat4 {
}
return m;
}
multScalar(scalar) {
for (let i = 0; i < this.data.length; ++i) {
this.data[i] *= scalar;
}
}
}
export { initializeContext, Mat4, Vec2, Vec3, Vec4 };

View File

@ -91,6 +91,10 @@ class Vec3 {
this.y -= other.y;
this.z -= other.z;
}
splatToArray(): Array<number> {
return [this.x, this.y, this.z];
}
}
class Vec4 {
@ -193,6 +197,26 @@ class Mat4 {
return new Mat4(data);
}
static isometric(): Mat4 {
//let m = new Mat4(new Float32Array([
// Math.sqrt(3), 0, -Math.sqrt(3), 0,
// 1, 2, 1, 0,
// Math.sqrt(2), -Math.sqrt(2), Math.sqrt(2), 0,
// 0, 0, 0, 1,
//]));
//m.multScalar(1 / Math.sqrt(6));
let m = new Mat4(new Float32Array([
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
return m;
}
static rotation_x(angle: number): Mat4 {
let data = new Float32Array([
@ -285,7 +309,7 @@ class Mat4 {
return vec;
}
mult(other: Mat4): Mat4 {
multNew(other: Mat4): Mat4 {
let m = new Mat4(0);
for (let i = 0; i < 4; ++i) {
@ -299,6 +323,12 @@ class Mat4 {
return m;
}
multScalar(scalar: number) {
for (let i = 0; i < this.data.length; ++i) {
this.data[i] *= scalar;
}
}
}
export { initializeContext, Mat4, Vec2, Vec3, Vec4, Color };

View File

@ -1,6 +1,6 @@
import { Vec2 } from "./common.js";
import { Vec3, Vec2 } from "./common.js";
import { Texture } from "./graphics.js";
function drawTriangle(gfx, positions, color) {
export function drawTriangle(gfx, positions, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
@ -17,13 +17,13 @@ function drawTriangle(gfx, positions, color) {
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawTriangleExts(gfx, position, exts, color) {
export function drawTriangleExts(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
];
const colors = [
color,
@ -34,15 +34,15 @@ function drawTriangleExts(gfx, position, exts, color) {
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawRectangle(gfx, position, exts, color) {
export function drawRectangle(gfx, corners, color) {
const a_position = gfx.getAttribute("a_position");
const points = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
position.x + exts.x, position.y + exts.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
corners[0].x, corners[0].y, corners[0].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
corners[2].x, corners[2].y, corners[2].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
];
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
@ -69,7 +69,71 @@ function drawRectangle(gfx, position, exts, color) {
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
function drawCircle(gfx, position, radius, color) {
export function drawIsometricCube(gfx, position, exts, color) {
let points = [
position,
new Vec3(position.x, position.y + exts.y, position.z),
new Vec3(position.x + exts.x, position.y, position.z),
new Vec3(position.x + exts.x, position.y + exts.y, position.z),
new Vec3(position.x + 1.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
];
drawRectangle(gfx, [
points[0],
points[1],
points[3],
points[2],
], color);
drawRectangle(gfx, [
points[3],
points[2],
points[4],
points[5],
], color);
drawRectangle(gfx, [
points[0],
points[2],
points[4],
points[6],
], color);
}
export function drawRectangleExts(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const points = [
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
position.x + exts.x, position.y + exts.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
];
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
color.bind(gfx);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
color.unbind(gfx);
}
else {
const a_color = gfx.getAttribute("a_color");
const colors = new Array(6);
colors.fill(color);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
export function drawCircle(gfx, position, radius, color) {
const points = new Array();
const precision = 40;
const angle = 2.0 * Math.PI / precision;
@ -87,7 +151,7 @@ function drawCircle(gfx, position, radius, color) {
drawTriangle(gfx, [center, center.addNew(current), center.addNew(next)], color);
}
}
function drawLine(gfx, A, B, color) {
export function drawLine(gfx, A, B, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
let points = [
@ -102,4 +166,3 @@ function drawLine(gfx, A, B, color) {
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.LINES, 0, 2);
}
export { drawTriangle, drawTriangleExts, drawRectangle, drawCircle, drawLine };

View File

@ -1,7 +1,7 @@
import { Vec2, Color } from "./common.js"
import { Vec3, Vec2, Color } from "./common.js"
import { Graphics, Texture } from "./graphics.js";
function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) {
export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
@ -22,14 +22,14 @@ function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawTriangleExts(gfx: Graphics, position: Vec2, exts: Vec2, color: Color) {
export function drawTriangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points: Array<number> = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
]
const colors: Array<number[]> = [
@ -43,17 +43,18 @@ function drawTriangleExts(gfx: Graphics, position: Vec2, exts: Vec2, color: Colo
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawRectangle(gfx: Graphics, position: Vec2, exts: Vec2, color: Color | Texture) {
export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3], color: Color | Texture) {
const a_position = gfx.getAttribute("a_position");
const points: Array<number> = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
position.x + exts.x, position.y + exts.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
corners[0].x, corners[0].y, corners[0].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
corners[2].x, corners[2].y, corners[2].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
]
if (color instanceof Texture) {
@ -86,7 +87,92 @@ function drawRectangle(gfx: Graphics, position: Vec2, exts: Vec2, color: Color |
}
function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Color) {
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: Color) {
let points = [
position,
new Vec3(position.x, position.y + exts.y, position.z),
new Vec3(position.x + exts.x, position.y, position.z),
new Vec3(position.x + exts.x, position.y + exts.y, position.z),
new Vec3(position.x + 1.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
];
drawRectangle(
gfx,
[
points[0],
points[1],
points[3],
points[2],
],
color);
drawRectangle(
gfx,
[
points[3],
points[2],
points[4],
points[5],
],
color);
drawRectangle(
gfx,
[
points[0],
points[2],
points[4],
points[6],
],
color);
}
export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Color | Texture) {
const a_position = gfx.getAttribute("a_position");
const points: Array<number> = [
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
position.x + exts.x, position.y + exts.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
]
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv: Array<number> = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
color.bind(gfx);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
color.unbind(gfx);
} else {
const a_color = gfx.getAttribute("a_color");
const colors: Array<number[]> = new Array(6);
colors.fill(color);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Color) {
const points: Array<Vec2> = new Array<Vec2>();
const precision = 40;
@ -107,7 +193,7 @@ function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Color)
}
}
function drawLine(gfx: Graphics, A: Vec2, B: Vec2, color: Color) {
export function drawLine(gfx: Graphics, A: Vec2, B: Vec2, color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
@ -125,5 +211,3 @@ function drawLine(gfx: Graphics, A: Vec2, B: Vec2, color: Color) {
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.LINES, 0, 2);
}
export { drawTriangle, drawTriangleExts, drawRectangle, drawCircle, drawLine }

View File

@ -1,10 +1,10 @@
import { initializeContext, Vec2, Mat4 } from "./common.js";
import { initializeContext, Vec3, Mat4 } from "./common.js";
import { Graphics, fullscreenCanvas, Texture } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
const vertexShader = `#version 300 es
in vec2 a_position;
in vec3 a_position;
in vec2 a_tex_position;
in vec4 a_color;
out vec2 v_tex_position;
@ -13,7 +13,7 @@ const vertexShader = `#version 300 es
uniform bool u_isTex;
void main() {
vec4 transformed = u_matrix * vec4(a_position.xy, 0.0, 1.0);
vec4 transformed = u_matrix * vec4(a_position.xyz, 1.0);
gl_Position = transformed;
@ -45,19 +45,29 @@ const fragmentShader = `#version 300 es
`;
function draw(gfx, angle, tex) {
gfx.clear(0, 0, 0, 0);
let left = 0;
let right = gfx.ctx.canvas.width;
let bottom = 0;
let left = 0;
let top = gfx.ctx.canvas.height;
let near = -1;
let far = 1;
let m = Mat4.orthographic(left, right, bottom, top, near, far);
m = m.mult(Mat4.rotation_x(angle));
m = m.mult(Mat4.rotation_y(angle));
m = m.mult(Mat4.rotation_z(angle));
let bottom = 0;
let near = -100;
let far = 100;
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mi = Mat4.isometric();
let m = mi.multNew(mo);
//m = m.multNew(Mat4.rotation_x(angle));
//m = m.multNew(Mat4.rotation_y(angle));
//m = m.multNew(Mat4.rotation_z(angle));
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
drawing.drawRectangle(gfx, new Vec2(gfx.ctx.canvas.width / 2 - 200, gfx.ctx.canvas.height / 2 - 200), new Vec2(400, 400), tex);
drawing.drawRectangle(gfx, new Vec2(100, 100), new Vec2(100, 100), [Math.sin(angle), Math.cos(angle), -Math.sin(angle), 1]);
let exts = new Vec3(50, 50, 20);
for (let i = 0; i < 10; ++i) {
for (let j = 0; j < 10; ++j) {
//drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [Math.sin(angle * i + j), Math.cos(angle * i + j), -Math.sin(angle * i + j), 1]);
if ((i + j) % 2)
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 1, 1]);
else
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [0, 0, 0, 1]);
}
}
}
(async () => {
const canvasId = "game";
@ -67,7 +77,7 @@ function draw(gfx, angle, tex) {
const gfx = new Graphics(ctx, vertexShader, fragmentShader);
fullscreenCanvas(gfx, canvasId);
const a_position = gfx.createAttribute("a_position");
a_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
a_position.format(3, gfx.ctx.FLOAT, false, 0, 0);
const a_color = gfx.createAttribute("a_color");
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
const a_tex_position = gfx.createAttribute("a_tex_position");

View File

@ -1,4 +1,4 @@
import { initializeContext, Vec2, Mat4 } from "./common.js";
import { initializeContext, Vec2, Vec3, Mat4 } from "./common.js";
import { Graphics, fullscreenCanvas, Texture } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
@ -6,7 +6,7 @@ import * as wasm from "./wasm.js";
const vertexShader =
`#version 300 es
in vec2 a_position;
in vec3 a_position;
in vec2 a_tex_position;
in vec4 a_color;
out vec2 v_tex_position;
@ -15,7 +15,7 @@ const vertexShader =
uniform bool u_isTex;
void main() {
vec4 transformed = u_matrix * vec4(a_position.xy, 0.0, 1.0);
vec4 transformed = u_matrix * vec4(a_position.xyz, 1.0);
gl_Position = transformed;
@ -53,17 +53,19 @@ const fragmentShader =
function draw(gfx: Graphics, angle: number, tex: Texture) {
gfx.clear(0, 0, 0, 0);
let left = 0;
let right = gfx.ctx.canvas.width;
let bottom = 0;
let left = 0;
let top = gfx.ctx.canvas.height;
let near = -1;
let far = 1;
let bottom = 0;
let near = -100;
let far = 100;
let m = Mat4.orthographic(left, right, bottom, top, near, far);
m = m.mult(Mat4.rotation_x(angle));
m = m.mult(Mat4.rotation_y(angle));
m = m.mult(Mat4.rotation_z(angle));
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mi = Mat4.isometric();
let m = mi.multNew(mo);
//m = m.multNew(Mat4.rotation_x(angle));
//m = m.multNew(Mat4.rotation_y(angle));
//m = m.multNew(Mat4.rotation_z(angle));
gfx.ctx.uniformMatrix4fv(
gfx.getUniform("u_matrix"),
@ -71,17 +73,17 @@ function draw(gfx: Graphics, angle: number, tex: Texture) {
m.splat()
);
drawing.drawRectangle(
gfx,
new Vec2(gfx.ctx.canvas.width / 2 - 200, gfx.ctx.canvas.height / 2 - 200),
new Vec2(400, 400),
tex);
drawing.drawRectangle(
gfx,
new Vec2(100, 100),
new Vec2(100, 100),
[Math.sin(angle), Math.cos(angle), -Math.sin(angle), 1]);
let exts = new Vec3(50, 50, 20);
for (let i = 0; i < 10; ++i) {
for (let j = 0; j < 10; ++j) {
//drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [Math.sin(angle * i + j), Math.cos(angle * i + j), -Math.sin(angle * i + j), 1]);
if ((i + j) % 2)
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 1, 1]);
else
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [0, 0, 0, 1]);
}
}
}
(async () => {
@ -93,7 +95,7 @@ function draw(gfx: Graphics, angle: number, tex: Texture) {
fullscreenCanvas(gfx, canvasId);
const a_position = gfx.createAttribute("a_position");
a_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
a_position.format(3, gfx.ctx.FLOAT, false, 0, 0);
const a_color = gfx.createAttribute("a_color");
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);