https://github.com/lesnitsky/webgl-month
🎓 Daily WebGL tutorials
https://github.com/lesnitsky/webgl-month
3d-rendering beginner code-samples javascript tutorials webgl
Last synced: 12 months ago
JSON representation
🎓 Daily WebGL tutorials
- Host: GitHub
- URL: https://github.com/lesnitsky/webgl-month
- Owner: lesnitsky
- Created: 2019-07-01T12:18:08.000Z (almost 7 years ago)
- Default Branch: dev
- Last Pushed: 2024-08-28T07:21:47.000Z (over 1 year ago)
- Last Synced: 2025-04-02T13:58:06.389Z (about 1 year ago)
- Topics: 3d-rendering, beginner, code-samples, javascript, tutorials, webgl
- Language: JavaScript
- Homepage: https://dev.to/lesnitsky
- Size: 922 KB
- Stars: 224
- Watchers: 10
- Forks: 14
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
- awesome-webgl - WebGL Month
README
# WebGL month
Hi 👋 My name is Andrei. I have some fun experience with WebGL and I want to share it. I'm starting a month of WebGL, each day I will post a WebGL related tutorial. Not Three.js, not pixi.js, WebGL API itself.
[Follow me on twitter](https://twitter.com/lesnitsky_a) to get WebGL month updates or [join WebGL month mailing list](http://eepurl.com/gwiSeH)
## Day 1. Intro
This is a series of blog posts related to WebGL. New post will be available every day
[Subscribe](https://twitter.com/lesnitsky_a) for updates or [join mailing list](http://eepurl.com/gwiSeH)
[Soruce code available here](https://github.com/lesnitsky/webgl-month)

> Built with [GitTutor](https://github.com/lesnitsky/git-tutor)
Welcome to day 1 of WebGL month. In this article we'll get into high level concepts of rendering which are improtant to understand before approaching actual WebGL API.
WebGL API is often treated as 3D rendering API, which is a wrong assumption. So what WebGL does?
To answer this question let's try to render smth with canvas 2d.
We'll need simple html
📄 index.html
```html
WebGL Month
```
and canvas
📄 index.html
```diff
WebGL Month
-
+
+
+
+
-
+
-
+
```
Now we can read body dimensions
📄 src/texture.js
```diff
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
+ const width = document.body.offsetWidth;
+ const height = document.body.offsetHeight;
+
const vShader = gl.createShader(gl.VERTEX_SHADER);
const fShader = gl.createShader(gl.FRAGMENT_SHADER);
```
And set canvas dimensions
📄 src/texture.js
```diff
const width = document.body.offsetWidth;
const height = document.body.offsetHeight;
+ canvas.width = width;
+ canvas.height = height;
+
const vShader = gl.createShader(gl.VERTEX_SHADER);
const fShader = gl.createShader(gl.FRAGMENT_SHADER);
```
Ok, canvas size changed, but our picture isn't full screen, why?
Turns out that changing canvas size isn't enought, we also need to specify a viwport. Treat viewport as a rectangle which will be used as drawing area and interpolate it to `[-1...1]` clipspace
📄 src/texture.js
```diff
gl.uniform2fv(programInfo.uniformLocations.resolution, [canvas.width, canvas.height]);
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
gl.drawElements(gl.TRIANGLES, indexBuffer.data.length, gl.UNSIGNED_BYTE, 0);
});
```
Now our picture fills the whole document, but it is a bit blurry. Obvious reason – our texture is not big enough, so it should be stretched and loses quality. That's correct, but there is another reason.
Modern displays fit higher amount of actual pixels in a physical pixel size (apple calls it retina). There is a global variable `devicePixelRatio` which might help us.
📄 src/texture.js
```diff
const width = document.body.offsetWidth;
const height = document.body.offsetHeight;
- canvas.width = width;
- canvas.height = height;
+ canvas.width = width * devicePixelRatio;
+ canvas.height = height * devicePixelRatio;
const vShader = gl.createShader(gl.VERTEX_SHADER);
const fShader = gl.createShader(gl.FRAGMENT_SHADER);
```
Ok, now our canvas has an appropriate size, but it is bigger than body on retina displays. How do we fix it?
We can downscale canvas to a physical size with css `width` and `height` property
📄 src/texture.js
```diff
canvas.width = width * devicePixelRatio;
canvas.height = height * devicePixelRatio;
+ canvas.style.width = `${width}px`;
+ canvas.style.height = `${height}px`;
+
const vShader = gl.createShader(gl.VERTEX_SHADER);
const fShader = gl.createShader(gl.FRAGMENT_SHADER);
```
Just to summarize, `width` and `height` attributes of canvas specify actual size in pixels, but in order to make picture sharp on highdpi displays we need to multiply width and hegiht on `devicePixelRatio` and downscale canvas back with css
Now we can alos make our canvas resizable
📄 src/texture.js
```diff
gl.drawElements(gl.TRIANGLES, indexBuffer.data.length, gl.UNSIGNED_BYTE, 0);
});
+
+
+ window.addEventListener('resize', () => {
+ const width = document.body.offsetWidth;
+ const height = document.body.offsetHeight;
+
+ canvas.width = width * devicePixelRatio;
+ canvas.height = height * devicePixelRatio;
+
+ canvas.style.width = `${width}px`;
+ canvas.style.height = `${height}px`;
+
+ gl.viewport(0, 0, canvas.width, canvas.height);
+ });
```
Oops, canvas clears after resize. Turns out that modification of `width` or `height` attribute forces browser to clear canvas (the same for `2d` context), so we need to issue a draw call again.
📄 src/texture.js
```diff
canvas.style.height = `${height}px`;
gl.viewport(0, 0, canvas.width, canvas.height);
+
+ gl.drawElements(gl.TRIANGLES, indexBuffer.data.length, gl.UNSIGNED_BYTE, 0);
});
```
That's it for today, see you tomorrow 👋


[Join mailing list](http://eepurl.com/gwiSeH) to get new posts right to your inbox
[Source code available here](https://github.com/lesnitsky/webgl-month)
Built with
[](https://github.com/lesnitsky/git-tutor)
## Day 13. Simple animation
This is a series of blog posts related to WebGL. New post will be available every day


[Join mailing list](http://eepurl.com/gwiSeH) to get new posts right to your inbox
[Source code available here](https://github.com/lesnitsky/webgl-month)
Built with
[](https://github.com/lesnitsky/git-tutor)
Hey 👋 Welcome to WebGL month.
All previous tutorials where based on static images, let's add some motion!
We'll need a simple vertex shader
📄 src/shaders/rotating-square.v.glsl
```glsl
attribute vec2 position;
uniform vec2 resolution;
void main() {
gl_Position = vec4(position / resolution * 2.0 - 1.0, 0, 1);
}
```
fragment shader
📄 src/shaders/rotating-square.f.glsl
```glsl
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
```
New entry point
📄 index.html
```diff
-
+
-
+
-
+