Cube rendered

This commit is contained in:
Andrew Golovashevich 2025-03-28 05:45:32 +03:00
parent 92603d8faf
commit 6d2a0e4d04
6 changed files with 348 additions and 58 deletions

View File

@ -6,42 +6,16 @@ import org.khronos.webgl.Float32Array
import org.khronos.webgl.Int32Array
import org.khronos.webgl.WebGLRenderingContext
import org.w3c.dom.HTMLCanvasElement
import ru.landgrafhomyak.bgtu.computer_graphics1.model_builder.Matrix4x4
import ru.landgrafhomyak.bgtu.computer_graphics1.model_builder.Point2F
import ru.landgrafhomyak.bgtu.computer_graphics1.model_builder.Point3F
import ru.landgrafhomyak.bgtu.computer_graphics1.model_builder.Point4F
fun main() {
val canvas = document.getElementById("canvas")!! as HTMLCanvasElement
val gl: dynamic = canvas.getContext("webgl2")!! /*as WebGLRenderingContext*/
val modelVertexesBuffer = gl.createBuffer()
val textureVertexesBuffer = gl.createBuffer()
val textureTypesBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, modelVertexesBuffer)
gl.bufferData(
gl.ARRAY_BUFFER,
Float32Array(model.modelVertexes.toTypedArray()),
gl.STATIC_DRAW
)
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 3 * 4, 0)
gl.enableVertexAttribArray(0)
gl.bindBuffer(gl.ARRAY_BUFFER, textureVertexesBuffer)
gl.bufferData(
gl.ARRAY_BUFFER,
Float32Array(model.textureVertexes.toTypedArray()),
gl.STATIC_DRAW
)
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 2 * 4, 0)
gl.enableVertexAttribArray(1)
gl.bindBuffer(gl.ARRAY_BUFFER, textureTypesBuffer)
gl.bufferData(
gl.ARRAY_BUFFER,
Int32Array(model.textureTypes.map { t -> t.ordinal }.toTypedArray()),
gl.STATIC_DRAW
)
gl.vertexAttribIPointer(2, 2, gl.INT, false, 1 * 4, 0)
gl.enableVertexAttribArray(2)
val vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource)
@ -61,25 +35,129 @@ fun main() {
gl.attachShader(shaderProgram, fragmentShader)
gl.linkProgram(shaderProgram)
println("program compilation log: ${gl.getProgramInfoLog(shaderProgram)}")
gl.useProgram(shaderProgram)
val transformLocation = gl.getUniformLocation(shaderProgram, "transform")
val projectionLocation = gl.getUniformLocation(shaderProgram, "projection")
val screenLocation = gl.getUniformLocation(shaderProgram, "screen_scale")
val modelVertexesBuffer = gl.createBuffer()
val textureVertexesBuffer = gl.createBuffer()
val textureTypesBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, modelVertexesBuffer)
println(model.modelVertexes.joinToString())
gl.bufferData(
gl.ARRAY_BUFFER,
Float32Array(model.modelVertexes.toTypedArray()),
gl.STATIC_DRAW
)
val vpa = gl.getAttribLocation(shaderProgram, "vertex_pos")
gl.vertexAttribPointer(vpa, 3, gl.FLOAT, false, 0, 0)
gl.enableVertexAttribArray(vpa)
gl.bindBuffer(gl.ARRAY_BUFFER, textureVertexesBuffer)
gl.bufferData(
gl.ARRAY_BUFFER,
Float32Array(model.textureVertexes.toTypedArray()),
gl.STATIC_DRAW
)
val tpa = gl.getAttribLocation(shaderProgram, "texture_pos")
gl.vertexAttribPointer(tpa, 2, gl.FLOAT, false, 2 * 4, 0)
gl.enableVertexAttribArray(tpa)
gl.bindBuffer(gl.ARRAY_BUFFER, textureTypesBuffer)
gl.bufferData(
gl.ARRAY_BUFFER,
Int32Array(model.textureTypes.map { t -> t.ordinal }.toTypedArray()),
gl.STATIC_DRAW
)
val tta = gl.getAttribLocation(shaderProgram, "texture_type")
gl.vertexAttribIPointer(tta, 2, gl.INT, false, 1 * 4, 0)
gl.enableVertexAttribArray(tta)
gl.enable(gl.DEPTH_TEST)
var xAngle = 0.0f
var yAngle = 0.0f
var distance = 0.0f
val xAngleStep = 0.1f
val yAngleStep = 0.1f
val distanceStep = 0.1f
val redraw = {
val radius = ((if (canvas.width < canvas.height) canvas.width else canvas.height) * 7f / 16f);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0f, 0f, 0f, 1f);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, model.textureTypes.size / 3)
gl.clear(gl.COLOR_BUFFER_BIT or gl.DEPTH_BUFFER_BIT);
val t = Matrix4x4.shift(0f, 0f, distance) * Matrix4x4.rotateY(yAngle) * Matrix4x4.rotateX(xAngle)
val po = Matrix4x4.projectionOrtho(-2f, 2f, -2f, 2f, -2f, 2f);
val pc = Matrix4x4.projectionCentralInfinite(-2f, 2f, -2f, 2f, 1f) * Matrix4x4.shift(0f, 0f, -3f) * Matrix4x4.scale(3f, 3f, -1f);
val s: Point2F
if (canvas.width > canvas.height) {
s = Point2F(canvas.height.toFloat() / canvas.width.toFloat(), 1f)
} else {
s = Point2F(1f, canvas.width.toFloat() / canvas.height.toFloat())
}
gl.uniformMatrix4fv(transformLocation, false, t.toFloatArray())
gl.uniformMatrix4fv(projectionLocation, false, pc.toFloatArray())
gl.uniform2f(screenLocation, s.x, s.y)
gl.drawArrays(gl.TRIANGLES, 0, model.textureTypes.size)
gl.flush()
}
val p = Matrix4x4.projectionCentral(-2f, 2f, -2f, 2f, 2f, 4f);
println(p * Point4F(-1f, -1f, -2f, 1f))
println(p * Point4F(-1f, 1f, -3f, 1f))
println(p * Point4F(1f, 1f, -4f, 1f))
redraw()
window.onkeydown = { keyEvent ->
when (keyEvent.code) {
"ArrowDown" -> {
gl.clearColor(0f, 0f, 0f, 1f);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, model.textureTypes.size / 3)
xAngle += xAngleStep;
redraw()
}
"ArrowUp" -> {}
"ArrowLeft" -> {}
"ArrowRight" -> {}
"ArrowUp" -> {
xAngle -= xAngleStep;
redraw()
}
"ArrowLeft" -> {
yAngle -= yAngleStep;
redraw()
}
"ArrowRight" -> {
yAngle += yAngleStep;
redraw()
}
"PageUp" -> {
distance += distanceStep;
redraw()
}
"PageDown" -> {
distance -= distanceStep;
if (distance < 0) distance = 0f
redraw()
}
}
}
window.onresize = { _ ->
canvas.width = document.documentElement!!.clientWidth;
canvas.height = document.documentElement!!.clientHeight;
redraw()
}
window.onload = { _ ->
canvas.width = document.documentElement!!.clientWidth;
canvas.height = document.documentElement!!.clientHeight;
redraw()
}
}

View File

@ -24,14 +24,12 @@ val model = ModelTriangles.fromPolygons(
Polygon.PolygonVertex(1f, 1f, 0f, rot_n(240, 1)),
Polygon.PolygonVertex(1f, 0f, 1f, rot_n(120, 1))
),
Polygon(
TextureType.HSV,
Polygon.PolygonVertex(-1f, -1f, 1f, rot_n(60, 2)),
Polygon.PolygonVertex(-1f, 1f, 1f, rot_n(0, 2)),
Polygon.PolygonVertex(0f, 1f, 1f, rot_n(0, 1))
),
Polygon(
TextureType.HSV,
Polygon.PolygonVertex(-1f, -1f, 1f, rot_n(60, 2)),
@ -45,14 +43,12 @@ val model = ModelTriangles.fromPolygons(
Polygon.PolygonVertex(1f, 0f, 1f, rot_n(120, 1)),
Polygon.PolygonVertex(1f, -1f, 1f, rot_n(120, 1))
),
Polygon(
TextureType.HSV,
Polygon.PolygonVertex(1f, -1f, -1f, rot_n(180, 2)),
Polygon.PolygonVertex(1f, 1f, -1f, rot_n(240, 2)),
Polygon.PolygonVertex(1f, 1f, 0f, rot_n(240, 1))
),
Polygon(
TextureType.HSV,
Polygon.PolygonVertex(1f, -1f, -1f, rot_n(180, 2)),
@ -66,14 +62,12 @@ val model = ModelTriangles.fromPolygons(
Polygon.PolygonVertex(1f, 0f, 1f, rot_n(120, 1)),
Polygon.PolygonVertex(1f, -1f, 1f, rot_n(120, 2))
),
Polygon(
TextureType.HSV,
Polygon.PolygonVertex(-1f, 1f, -1f, rot_n(300, 2)),
Polygon.PolygonVertex(1f, 1f, -1f, rot_n(240, 2)),
Polygon.PolygonVertex(1f, 1f, 0f, rot_n(240, 1))
),
Polygon(
TextureType.HSV,
Polygon.PolygonVertex(-1f, 1f, -1f, rot_n(300, 2)),
@ -87,6 +81,7 @@ val model = ModelTriangles.fromPolygons(
Polygon.PolygonVertex(0f, 1f, 1f, rot_n(0, 1)),
Polygon.PolygonVertex(-1f, 1f, 1f, rot_n(0, 2))
),
Polygon(
TextureType.WHITE_TRANSPARENCY,
Polygon.PolygonVertex(-1f, -1f, 1f, 0f, 0f),
@ -126,5 +121,5 @@ val model = ModelTriangles.fromPolygons(
Polygon.PolygonVertex(-1f, -1f, -1f, 1f, 1f),
Polygon.PolygonVertex(-1f, -1f, 1f, 0f, 1f),
Polygon.PolygonVertex(1f, -1f, -1f, 1f, 0f)
),
)
)

View File

@ -0,0 +1,162 @@
package ru.landgrafhomyak.bgtu.computer_graphics1.model_builder
import kotlin.math.cos
import kotlin.math.sin
class Matrix4x4 private constructor(
private val v00: Float,
private val v01: Float,
private val v02: Float,
private val v03: Float,
private val v10: Float,
private val v11: Float,
private val v12: Float,
private val v13: Float,
private val v20: Float,
private val v21: Float,
private val v22: Float,
private val v23: Float,
private val v30: Float,
private val v31: Float,
private val v32: Float,
private val v33: Float
) {
private inline fun _foldMatrix(other: Matrix4x4, operator: (rowIndex: Int, columnIndex: Int, self: Float, other: Float) -> Float): Matrix4x4 = Matrix4x4(
operator(0, 0, this.v00, other.v00), operator(0, 1, this.v01, other.v01), operator(0, 2, this.v02, other.v02), operator(0, 3, this.v03, other.v03),
operator(1, 0, this.v10, other.v10), operator(1, 1, this.v11, other.v11), operator(1, 2, this.v12, other.v12), operator(1, 3, this.v13, other.v13),
operator(2, 0, this.v20, other.v20), operator(2, 1, this.v21, other.v21), operator(2, 2, this.v22, other.v22), operator(2, 3, this.v23, other.v23),
operator(3, 0, this.v30, other.v30), operator(3, 1, this.v31, other.v31), operator(3, 2, this.v32, other.v32), operator(3, 3, this.v33, other.v33),
)
operator fun get(row: Int, column: Int) = when (row * 4 + column) {
0 -> this.v00
1 -> this.v01
2 -> this.v02
3 -> this.v03
4 -> this.v10
5 -> this.v11
6 -> this.v12
7 -> this.v13
8 -> this.v20
9 -> this.v21
10 -> this.v22
11 -> this.v23
12 -> this.v30
13 -> this.v31
14 -> this.v32
15 -> this.v33
else -> throw IllegalArgumentException()
}
operator fun times(other: Matrix4x4): Matrix4x4 =
this._foldMatrix(other) { y, x, _, _ ->
return@_foldMatrix this[y, 0] * other[0, x] + this[y, 1] * other[1, x] + this[y, 2] * other[2, x] + this[y, 3] * other[3, x];
}
fun toFloatArray() = floatArrayOf(
this.v00, this.v01, this.v02, this.v03,
this.v10, this.v11, this.v12, this.v13,
this.v20, this.v21, this.v22, this.v23,
this.v30, this.v31, this.v32, this.v33
)
fun transposed() = Matrix4x4(
this.v00, this.v10, this.v20, this.v30,
this.v01, this.v11, this.v21, this.v31,
this.v02, this.v12, this.v22, this.v32,
this.v03, this.v13, this.v23, this.v33,
)
operator fun times(p: Point3F) = Point3F(
x = this.v00 * p.x + this.v01 * p.y + this.v02 * p.z + this.v03,
y = this.v10 * p.x + this.v11 * p.y + this.v12 * p.z + this.v13,
z = this.v20 * p.x + this.v21 * p.y + this.v22 * p.z + this.v23,
)
operator fun times(p: Point4F) = Point4F(
x = this.v00 * p.x + this.v01 * p.y + this.v02 * p.z + this.v03,
y = this.v10 * p.x + this.v11 * p.y + this.v12 * p.z + this.v13,
z = this.v20 * p.x + this.v21 * p.y + this.v22 * p.z + this.v23,
w = this.v30 * p.x + this.v31 * p.y + this.v32 * p.z + this.v33,
)
companion object {
val I = Matrix4x4(
1f, 0f, 0f, 0f,
0f, 1f, 0f, 0f,
0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f
)
fun scale(x: Float, y: Float, z: Float) = Matrix4x4(
x, 0f, 0f, 0f,
0f, y, 0f, 0f,
0f, 0f, z, 0f,
0f, 0f, 0f, 1f
)
fun scale(s: Float) = this.scale(s, s, s)
fun rotateX(rad: Float): Matrix4x4 {
val c = cos(rad)
val s = sin(rad)
return Matrix4x4(
1f, 0f, 0f, 0f,
0f, c, -s, 0f,
0f, s, c, 0f,
0f, 0f, 0f, 1f
)
}
fun rotateY(rad: Float): Matrix4x4 {
val c = cos(rad)
val s = sin(rad)
return Matrix4x4(
c, 0f, s, 0f,
0f, 1f, 0f, 0f,
-s, 0f, c, 0f,
0f, 0f, 0f, 1f
)
}
fun rotateZ(rad: Float): Matrix4x4 {
val c = cos(rad)
val s = sin(rad)
return Matrix4x4(
c, -s, 0f, 0f,
s, c, 0f, 0f,
0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f
)
}
fun shift(x: Float, y: Float, z: Float) = Matrix4x4(
1f, 0f, 0f, x,
0f, 1f, 0f, y,
0f, 0f, 1f, z,
0f, 0f, 0f, 1f
)
fun projectionOrtho(l: Float, r: Float, b: Float, t: Float, n: Float, f: Float) = Matrix4x4(
2f / (r - l), 0f, 0f, -(r + l) / (r - l),
0f, 2f / (t - b), 0f, -(t + b) / (t - b),
0f, 0f, 2f / (f - n), -(f + n) / (f - n),
0f, 0f, 0f, 1f
)
fun projectionCentral(l: Float, r: Float, b: Float, t: Float, n: Float, f: Float) = Matrix4x4(
2f * n / (r - l), 0f, (r + l) / (r - l), 0f,
0f, 2f * n / (t - b), (t + b) / (t - b), 0f,
0f, 0f, -(f + n) / (f - n), -2f * n * f / (f - n),
0f, 0f, -1f, 0f
)
fun projectionCentralInfinite(l: Float, r: Float, b: Float, t: Float, n: Float) = Matrix4x4(
2f * n / (r - l), 0f, (r + l) / (r - l), 0f,
0f, 2f * n / (t - b), (t + b) / (t - b), 0f,
0f, 0f, -1f, -2f * n,
0f, 0f, -1f, 0f
)
}
}

View File

@ -0,0 +1,16 @@
package ru.landgrafhomyak.bgtu.computer_graphics1.model_builder
class Point4F(
val x: Float,
val y: Float,
val z: Float,
val w: Float,
) {
operator fun component1(): Float = this.x
operator fun component2(): Float = this.y
operator fun component3(): Float = this.z
operator fun component4(): Float = this.w
override fun toString(): String =
"<point 4f x=${this.x} y=${this.y} z=${this.z} w=${this.w}>"
}

View File

@ -6,14 +6,19 @@ internal val vertexShaderSource = """
#version 300 es
uniform mat4 transform;
layout(location = 0) in vec3 vertex_pos;
layout(location = 1) in vec2 texture_pos;
layout(location = 2) in int texture_type;
uniform mat4 projection;
uniform vec2 screen_scale;
in vec3 vertex_pos;
in vec2 texture_pos;
in int texture_type;
out vec2 texture_pos_v2f;
flat out int texture_type_v2f;
void main() {
gl_Position = vec4(vertex_pos.xyz, 1) * transform;
gl_Position = vec4(vertex_pos, 1.0);
gl_Position *= transform;
gl_Position *= projection;
gl_Position.xy *= screen_scale;
texture_pos_v2f = texture_pos;
texture_type_v2f = texture_type;
}
@ -21,27 +26,61 @@ internal val vertexShaderSource = """
internal val fragmentShaderSource = """
#version 300 es
#define PI 3.1415926535897932384626433832795
precision mediump float;
in vec2 texture_pos_v2f;
flat in int texture_type_v2f;
out vec4 color;
out vec4 FragColor;
vec3 hsv2rgb(float, float, float);
vec3 hsv_texture(float, float);
void main() {
switch (texture_type_v2f) {
case ${TextureType.WHITE_TRANSPARENCY.ordinal}:
color = vec4(255, 255, 255, 127);
FragColor = vec4(1.0, 1.0, 1.0, 0.5);
break;
case ${TextureType.CHESS.ordinal}:
if (int( round(floor(texture_pos_v2f.x / 0.1)) + round(floor(texture_pos_v2f.y / 0.1)) ) % 2 == 0) {
color = vec4(0, 0, 0, 255);
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
color = vec4(255, 255, 255, 255);
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
break;
case ${TextureType.HSV.ordinal}:
FragColor = vec4(hsv_texture(texture_pos_v2f.x, texture_pos_v2f.y), 1.0);
break;
default:
color = vec4(0, 0, 0, 0);
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
}
vec3 hsv_texture(float x, float y) {
float angle = atan(y, x);
return hsv2rgb(mod(mod(angle / PI * 180.0, 360.0) + 360.0, 360.0), 1.0, 1.0);
}
vec3 hsv2rgb(float hue, float saturation, float value) {
int hi = int(floor(hue / 60.0)) % 6;
float f = hue / 60.0 - floor(hue / 60.0);
float v = value;
float p = value * (1.0 - saturation);
float q = value * (1.0 - f * saturation);
float t = value * (1.0 - (1.0 - f) * saturation);
switch (hi) {
case 0:
return vec3(v, t, p);
case 1:
return vec3(q, v, p);
case 2:
return vec3(p, v, t);
case 3:
return vec3(p, q, v);
case 4:
return vec3(t, p, v);
default:
return vec3(v, p, q);
}
}
""".trimIndent()

View File

@ -5,7 +5,7 @@
<title>Title</title>
</head>
<body>
<canvas style="left: 0; top: 0; right: 0; bottom:0; position: fixed" id="canvas"></canvas>
<canvas style="left: 0; top: 0; right: 0; bottom:0; position: fixed; width: 100%;image-rendering: pixelated;" id="canvas"></canvas>
<script src="computer-graphics-1.js"></script>
</body>