1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
<html>
<head>
<title>my very super duper cool writeup</title>
<style>
html {
background-color: black;
color:yellow;
font-family: sans-serif;
padding: 1rem;
}
a, button {
all: unset;
display: inline-block;
color:yellow;
border: 1px solid;
border-radius: 10px;
margin: .5rem 0;
margin-right: 1rem;
padding: .5rem;
}
a:hover, button:hover {
background-color: #313244;
color: #a6adc8;
cursor: pointer;
}
.trail {
position: absolute;
z-index: 9999;
pointer-events: none;
}
</style>
</head>
<body>
<h1>the writeup</h1>
<marquee>woah its a funny html file again</marquee>
<h2>overview</h2>
The project itself I would say was built quite well. It is reasonably able to render
chunks at a good enough framerate that im happy with it. I personally would of not picked
java script, mostly because of the multithreading support.
<h3>js slow</h3>
Being forced to halt rendering
so that the game can generate AND mesh chunks does cause quite noticeable lag spikes.
The best thing to do would create a render thread, and only have generation and meshing done
on its own thread, but I cannot do this in JS.
<h3>vertex data</h3>
As also described in the presentation, I do thing the vertex mesh for the chunk is not well
made. 192 bytes per quad (vec3 + vec3 + vec2 + vec3 + float) * 4, is really terrible for
gpu performance. The smaller the mesh, the quicker the gpu can process it each frame and the
high the fps. I have decided to continue this project but not in javascript, but in c, and I
have gotten it down to 4 bytes, horray!
<pre>
<code>
typedef union {
struct {
u32 x : 5;
u32 y : 5;
u32 z : 5;
u32 width : 5;
u32 height : 5;
u32 face : 3;
u32 block : 4;
};
u32 raw;
} Quad;
</code>
</pre>
Above is the struct I am not using in C for per quad data. Each quad is then instanced on the gpu, stored in a uniform buffer. Then I use the instance index to index into the uniform of "Quad"s, to render each face. It is quite a lot faster than the approach I did in JS.
You may also notice that this contains a width and height field, which allows us to use this
with greedy meshing! Horray!!!
If you would like to take a look at my C code, you can find it at <a href="https://g.freya.cat/voxel">https://g.freya.cat/voxel</a>. Yes its OpenGL, but I've done Vulkan once, and never again.
<h3>texture array</h3>
The first time i made minecraft I ran into the issue where texture atlases would get blurd and wonky when msaa or mipmapping were turned on. This ended up being because the edges of each texture in atlas would get blured (msaa'd) togeather, and the edges of blocks would look terrible. The solution to this was to use a texture array (or a 3d texture), since each layer gets sampeled differently, and such there would be no bluring between the layers.
<h3>what would i do differently</h3>
So though all the issues I ran into, what would i do differently? Well thats easy, the C code I just linked to in the previous section. It fixes alot of the issues I ran into in the
JS voxel "engine", and also adds a whole new slew of features such as frustum culling and soon will have ambient occlusion.
Frustum culling turns out is alot easier than I thought, because once can get each plane from the proj-view matrix.
I rally had a fun time writing this, and I hope you think It was a cool project :)
<h2>johnvertize</h2>
<marquee>scream into the void</marquee>
<iframe src="https://john.citrons.xyz/embed?ref=freya.cat" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe>
<div class="buttons">
<picture>
<source type="image/webp" srcset="https://freya.cat/public/buttons/eyes.webp?timestamp=1716556123" media="(prefers-reduced-motion: reduce)">
<source type="image/png" srcset="https://freya.cat/public/buttons/eyes.png?timestamp=1716556123" media="(prefers-reduced-motion: reduce)">
<source type="image/gif" srcset="https://freya.cat/public/buttons/eyes.gif?timestamp=1716556123">
<img src="https://freya.cat/public/buttons/eyes.png?timestamp=1716556123" alt="Best viewed with eyes" title="Best viewed with eyes" width="88" height="30">
</picture>
<picture>
<source type="image/webp" srcset="https://freya.cat/public/buttons/vim.webp?timestamp=1716556123" media="(prefers-reduced-motion: reduce)">
<source type="image/png" srcset="https://freya.cat/public/buttons/vim.png?timestamp=1716556123" media="(prefers-reduced-motion: reduce)">
<source type="image/gif" srcset="https://freya.cat/public/buttons/vim.gif?timestamp=1716556123">
<img src="https://freya.cat/public/buttons/vim.png?timestamp=1716556123" alt="Edited with VIM" title="Edited with VIM" width="88" height="30">
</picture>
<picture>
<source type="image/webp" srcset="https://freya.cat/public/buttons/gnu-linux.webp?timestamp=1716556123">
<source type="image/png" srcset="https://freya.cat/public/buttons/gnu-linux.png?timestamp=1716556123">
<img src="https://freya.cat/public/buttons/gnu-linux.png?timestamp=1716556123" alt="Made with GNU/Linux" title="Made with GNU/Linux" width="88" height="30">
</picture>
<script>
alert('welcome back')
// thank u ryan, very cool
var trailLength = 12;
var path = [];
var delay = 100;
var lastX = 0;
var lastY = 0;
function createMouseTrail() {
for (var i = 0; i < trailLength; i++) {
var div = document.createElement('div');
div.setAttribute('class', 'trail');
div.style.top = '-200px';
div.style.left = '-200px';
div.style.backgroundImage = 'url(https://www.rochesterapex.com/css/cursor.gif)';
div.style.backgroundSize = 'cover';
div.style.width = '11px';
div.style.height = '19px';
document.body.appendChild(div);
path.push(div);
}
}
var lastX = 0;
var lastY = 0;
function moveTrail(e) {
if (lastX !== e.pageX || lastY !== e.pageY) {
for (let i = 0; i < path.length; i++) {
setTimeout(function() {
path[i].style.top = (e.pageY) + 'px';
path[i].style.left = (e.pageX) + 'px';
}, i * delay);
}
}
lastX = e.pageX;
lastY = e.pageY;
}
document.addEventListener('mousemove', moveTrail);
createMouseTrail();
</script>
</body>
</html>
|