 So let's get started. So sorry, I changed the title a bit. So now I changed it to create your own WebGL with JavaScript, basically the same thing. So it's going to be a very different topic today. And it's different, but I think it's also very fun. We're not going to talk about how to use WebGL, but today we're going to talk about how to create your own version of WebGL. So first, just quick overview of what's WebGL. So just a quick survey here. Anyone here use WebGL before for any projects? It doesn't have to be a very complicated one, a single one like this rotating cube will also count. So not too many. But for WebGL, what it does is basically you define some geometry data, and then there is a set of APIs that you can call. So you pass this data to these APIs, and then the graphics card will help you render this 3D image for you. So things like bind buffer, draw elements, for developers, they are like a black box. You don't really know what's happening there, but you know if you pass this data to them, they will render an image for you. So today this session will help you to understand what is happening there, to help you reveal the magic happening in the graphics card. So first, I just want to give you guys a very quick example of what we tried to achieve here. This is a 3D model. Let me open it. So this is a 3D model, a chip. And if we open the same model with the text file editor, you'll see that it's actually a list of vertices, 3D vertices, basically x, y, z coordinates. And these coordinates define this chip card. And what the graphics card is doing is you give this list of coordinates, it will render this chip card for you. And this is what we try to do here today. To create something that's like WebGL, it renders image for you in 3D. And that's what we try to do. OK, so just to recap what we want to do here, we want to create a system that can render 3D image from a list of 3D coordinates. And we're not using any libraries, not WebGL, not OpenGL. And we just need a function to write a pixel on screen. That's the only thing we need to do. And we want to support rotating the view. Meaning you can see a chip model there, keep rotating. And we want to support textures as well. It's not just black and white. It's actually very colorful. And we want to support perspective projection as well. Meaning, I'd say you have two items. One item is very far away from you. And the other one is nearer to you. And the far away item should be smaller. It should look smaller than the near one. So that's basically perspective projection. And to start, let's not start with drawing a Jeep car, because it looks very complicated. So let's begin with something simpler, maybe a sphere. So let's say if we want to draw a sphere, what we can do. So there are actually two ways. First is we create a function that can render a sphere. But then if, say, later, we want to render a cone, we want to render something else, then there's so many shapes in this world. We cannot have so many functions. It's endless. So that's actually not a good idea. So maybe you can start running something even simpler than this. So this is a screenshot from the 3GS editor. It's a sphere. And if we take a closer look at it, you will see that it's actually not a sphere. It's actually a group of triangles. And the good part about this is we actually just need to have a function to draw a triangle. Then we can pretty much draw everything we have in the world. As long as the triangle is small enough and we have a good number of triangles, we can use it to represent anything in the world. And I won't go through this list. So basically there are a lot of good reasons we should use a triangle. And graphic cards are basically circuits. And on circuit, it's very hard to do very complicated logic there. It won't be good for them to have very complicated logic there. So triangles are very easy to render. So we have a function to draw a triangle. We can do everything we want. And another thing is, although the triangles are actually in 3D, but our screen is actually in 2D. So which means we don't need to support a function to render a 3D triangle. We just need one to draw a 2D triangle. That's all we need. And the figure here. So as you can see from here, triangles can draw everything, actually, as long as we have enough numbers of triangles. So the first thing we want to do is to have a function to draw a 2D triangle, which sounds very simple, actually. And the solution is also quite simple. So what we try to do is we first get a bounding box out of this triangle, the blue ones, the blue one. And then we have some kind of follow to look through all the pixels inside this box. And if that pixel is inside this triangle, then maybe we can put the pixel value here as the black one. And if it's not inside the triangle, we just don't do anything. So with this, we can have a way to render a 2D triangle on your screen. And this way doesn't sound very efficient, actually. But the reason a lot of hardware are using this, because if you take another look at it, the implementation can be very simple. And it can work in parallel as well. For GPUs, there's a lot of processes on it. So for GPUs, actually, this kind of way to draw a triangle is more faster to GPUs, the hardware. So we are using the same way here today. And another question, maybe it burns. I mean, the question might sound very obvious, but how do we know if a pixel is inside a triangle? So actually, we can do something like this. This is called barycentric coordinates. So each point on this plan, we can make it into the location of point A plus U times vector AB and B times vector AC. So if the direction of these vectors are like this, and if one of them is in the negative direction, then it's outside. Or if these two values add up together, it's greater than one, it's also outside. So this is a very simple way to determine if a pixel is inside a triangle. And with this, we now have a function to draw a 2D triangle. And so what else we need to do? So we now have already done step two, which is to draw 2D triangles. We also need to do the first step, because in 3D, everything is x, y, z, 3, x, z, right? So how do we find a way to map the 3D triangle to a 2D one? Actually, it's even simpler than the previous question. So we can just drop the z axis, actually. So now we have x and y axis there, which can be mapped to a 2D screen. And we can just drop the z axis. And another thing is to keep things easier. Let's assume that all the vectors we have are within a normalized space, which means the vectors are all within this space. The left here is minus 1. The right here is 1. And let's say if the screen we have is 800 by 600. And for this point here, which is 1, mapped to here should be 800. So with the y axis here, actually for canvas in HTML, the y axis is not here. It's actually going down. So that's why we can add an active y here, so it will correct the direction. And with all that, we can get something like this. So basically what I did is we wanted to draw a triangle with. This is the triangle we have. And we run it to this canvas. And it's not a black and white triangle. You see there's some shading there. The pixel value I put for each pixel is actually the z value for that pixel. So it will help us to understand if it's rendered correctly. And this point here is near to us, which is the z value is 0.3. So it looks darker. And these two points here, which are far away from us, so they look brighter. And this is just one triangle. Let's say if we have a list of triangles, then this is the input. So a lot of triangles, which is too hard. And we get something like this. It looks like a jpeg car now. But here it's weird, actually, because like I mentioned, if the object is near to you, it should be darker. If it's far away from you, it should be brighter. But here there are two wheels here. One is very bright, and another one is very dark. So something is wrong here. We'll talk about that later. But first, let's do some cool stuff. Let's add some rotations. So actually adding a rotation is also very simple. I'll skip the mask here. So basically, you have rotation matrix. And you multiply a matrix with a vector. You get the rotated vector. So that's idea. OK, that's idea. And so after rotation, what we'll see is something like this. It is rotating. And you'll see it's not looking correct. It's definitely not correct. It's so weird, actually. And the reason it's weird is because I know we have two objects, but we don't know which one is near to you, which one is far away from you. So the object that's near to you might be draw first. And later, another object which is far away from you is rendered. So that one overlaps with the previous one. So that's what happened here. So the solution to this problem is you create a depth buffer like this one. So this object is near to you, so it looks darker. And this one is far away from you. It's brighter. So if we add a depth checking here, we can make sure that the objects won't overlap with the ones in the front. With depth testing, it looks much better now. These two are pretty bright. And the staff on the back is pretty dark. And we add back the rotation. So now we have something like this. So now it looks correct. With that testing, the pixels won't get overlapped. So now it's looking much better now. OK. So I have one minute left. So then this car is a black and white car. So how do we turn this one into this one, which has a texture? So there's something called texture mapping. So basically for each vertex here, we also assign it with a UV coordinates, which is assigned to a bitmap. So with that, when you run it, you can interpret these values here with values from here. So then you get the texture. Basically, a texture is a bitmap that looks like this. And this part of this, you get one with a texture. And perspective projection as well. So again, it's a matrix. So you just multiply it with projection matrix. So it's pretty like that. Yeah, all together, we will have something like this. It is a car. And you can notice that the wheel that's near to you is bigger than the ones far away from you. And it has texture. It is rotating. It's very slow, actually, because everything is done in JavaScript. There's no hardware helping us to do any magic. We did everything by ourselves. And this is the talk for me. I'm also working on the open-source 3D CAD tool. So if you guys are interested in 3D and stuff like that, you can also check this out. It's open-source. It's called casual. So basically, you can pretty much draw everything from here. It's very intuitive. You don't need to learn anything. But you can sketch your model directly. Yeah, so pretty cool. So let's check it out. Yeah, it's called casual. That's all from me. Thank you, guys. You used your tool, actually, to build up the Jeep. Because when you showed this endless kind of lines of coordinates, I'm pretty sure you didn't type your name. Of course not. So basically, there is a 3DS as editor. You import models there, and you can export a race out. So that's what I did. Yeah, you don't need to manually handle all these numbers. For the final version, did you code that by hand or using library? No libraries or by hand. It's fully all those major things. Yeah, really. Can you improve the performance by running all the information on GPU? Yeah, yes, for sure. So a graphic card I designed for this kind of task. So if we find a way to run it on GPU, then definitely it will run faster. But again, the idea for this is to talk about how the GPU cards are working. So the idea is the same. So if you translate this JavaScript code into a circuit, you'll get the graphics card. So basically, it's like that. OK, thank you.