WebGL trying to draw multiple points - webgl

I'm trying to draw curve lines using Bezier, I try to do all in void main() and try to do with buffer, but it's wrong everywhere, and I don't understand where:
1) All in main()
var VSHADER_SOURCE =
'attribute vec2 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = 10.0;\n' +
'}\n';
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if (!gl)
{
console.log('Failed to retrieve the <canvas> element');
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE))
{
console.log('Failed to intialize shaders.');
return;
}
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT );
w=(192*4);
d=(w/1920);
x=0.8;
y=0.9
var M = new Float32Array([-x,-y,-x+d,y,-x+2*d,-y,-x+3*d,y,-x+4*d,-y,]);
var vertices=[];
for (var i=0;i<6;i+=2)
{
for (var t=0 ;t<1;t+=0.01)
{
vertices.push((1-t)^2*M(i)+2*(1-t)*t*M(i+2)+t^2*M(i+4));
vertices.push((1-t)^2*M(i+1)+2*(1-t)*t*M(i+3)+t^2*M(i+5));
}
}
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0)
{
console.log('Failed to get the storage location of a_Position');
return -1;
}
for(var l = 0; l < lenght(nx)/2-1; l+=1)
{
gl.vertexAttrib2f(a_Position, vertices[l], vertices[l+1]);
gl.drawArrays(gl.POINTS, 0, 1);
}
gl.enableVertexAttribArray(a_Position);
}
And second method I can't write because space is limited.

Did you even attempt to debug this yourself? Like open the JavaScript console and look for errors?
The code you posted isn't remotely runnable.
First off your shader
attribute vec2 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 10.0;
}
won't compile and your framework (or whatever you call initShaders) should have printed an error that gl_Position (a vec4) can not be assigned by a_Position, a vec2. Change a_Position to a vec4.
Next up is these lines
vertices.push((1-t)^2*M(i)+2*(1-t)*t*M(i+2)+t^2*M(i+4));
vertices.push((1-t)^2*M(i+1)+2*(1-t)*t*M(i+3)+t^2*M(i+5));
M is not a function. I'm guessing you meant to use M[expression] not M(expression)
vertices.push((1-t)^2*M[i]+2*(1-t)*t*M[i+2]+t^2*M[i+4]);
vertices.push((1-t)^2*M[i+1]+2*(1-t)*t*M[i+3]+t^2*M[i+5]);
^ is not the raise to a power operator in JavaScript it's the bitwise xor operator. To raise a number to a power you use Math.pow. So you probably wanted this
vertices.push(Math.pow(1-t,2)*M[i]+2*(1-t)*t*M[i+2]+Math.pow(t,2)*M[i+4]);
vertices.push(Math.pow(1-t,2)*M[i+1]+2*(1-t)*t*M[i+3]+Math.pow(t,2)*M[i+5]);
Then this line
for(var l = 0; l < lenght(nx)/2-1; l+=1)
There is no function lenght nor is there a function length in JavaScript nor did you declare a variable called nx
It seems like you wanted
for(var l = 0; l < vertices.length; l += 2)
You probably also want to use multiline template literals for your shaders and your initShader function is very poorly written based on the fact that looking at your code you're accessnig gl.program which is not a thing.
At the end of the code you posted you have this line
gl.enableVertexAttribArray(a_Position);
But that line only makes sense if you're using a buffer for your data. You're not. You're instead drawing one point at a time. You should use a buffer as it would be much much faster than calling gl.drawArrays once for each point
Might I suggest some other WebGL tutorials?
Here's a working? version.
var VSHADER_SOURCE = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 10.0;
}
`;
var FSHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
function main() {
var canvas = document.getElementById('webgl');
var gl = canvas.getContext("webgl");
if (!gl)
{
console.log('Failed to retrieve the <canvas> element');
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE))
{
console.log('Failed to intialize shaders.');
return;
}
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT);
var w=(192*4);
var d=(w/1920);
var x=0.8;
var y=0.9;
var M = new Float32Array([-x,-y,-x+d,y,-x+2*d,-y,-x+3*d,y,-x+4*d,-y,]);
var vertices=[];
for (var i=0;i<6;i+=2)
{
for (var t=0;t<1;t+=0.01)
{
vertices.push(Math.pow(1-t,2)*M[i]+2*(1-t)*t*M[i+2]+Math.pow(t,2)*M[i+4]);
vertices.push(Math.pow(1-t,2)*M[i+1]+2*(1-t)*t*M[i+3]+Math.pow(t,2)*M[i+5]);
}
}
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0)
{
console.log('Failed to get the storage location of a_Position');
return -1;
}
for(var l = 0; l < vertices.length; l+=2)
{
gl.vertexAttrib2f(a_Position, vertices[l], vertices[l+1]);
gl.drawArrays(gl.POINTS, 0, 1);
}
}
// THIS IS A POORLY WRITTEN FUNCTION!!!!
// Normal WebGL pages use multiple shader programs
// therefore you should **NEVER** assign values to
// the gl object!!!
function initShaders(gl, vsrc, fsrc) {
gl.program = twgl.createProgram(gl, [vsrc, fsrc]);
gl.useProgram(gl.program);
return !!gl.program;
}
main();
canvas { width: 384px; height: 216px; }
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
<canvas id="webgl" width="1920" height="1080"></canvas>

Related

Webgl fragment shader transparency on pixel that has already been colored

I just learned about Webgl a few days ago, and I am still a bit confused about transparency behavior. I am trying to draw some circles inside a triangle using a fragment shader. Everything appears to be working alright until I have two triangles overlapping. My fragment shader determines if the point is in the circle or not, and then sets the color to either (1.,0.,0.,1.) if it is inside, or (1.,0.,0.,0.) if it is not.
The behavior I am expecting is that when the fragment shader sets a pixel to (1.,0.,0.,0.) that has already been colored (1.,0.,0.,1.), it will appear as (1.,0.,0.,1.). However, it appears colored the same color as the background.
I have tried to turn on blend mode with the following, but it still doesn't seem to be working:
gl.enable( gl.BLEND );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
I have attached my code below.
const vertexShader = `
attribute vec4 aPosition;
attribute vec4 aCenter;
varying vec4 pos;
varying vec4 center;
void main() {
center=aCenter;
pos=aPosition;
gl_Position = aPosition;
}
`;
const fragmentShader = `
precision mediump float;
varying vec4 pos;
varying vec4 center;
void main() {
float inside = pow(pos.x - center.x, 2.0) + pow(pos.y - center.y, 2.0);
float val=max(sign(pow(center.z, 2.0)-inside),0.);
vec4 color=vec4(1.,0.,0.,val);
gl_FragColor = color;
}
`;
const DEG_TO_RAD = 0.0174532925;
const TRI_HEIGHT_MOD = 2;
// build simple circle
var points = [];
var centers = [];
function buildCircle(center, r) {
let angles=[0,120,240];
for(let k=0;k<angles.length;k++){
centers.push(center[0]);
centers.push(center[1]);
centers.push(r);
var x=r * TRI_HEIGHT_MOD * Math.cos(angles[k] * DEG_TO_RAD) + center[0];
var y=r * TRI_HEIGHT_MOD * Math.sin(angles[k] * DEG_TO_RAD) + center[1];
points.push(x);
points.push(y);
}
}
buildCircle([-.3,0],.5);
buildCircle([0,0],.5);
function loadShadersFromString(gl,vertexSource,fragmentSource){
// first compile the vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader,vertexSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(vertexShader));
return null;
}
// now compile the fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader,fragmentSource);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(fragmentShader));
return null;
}
// OK, we have a pair of shaders, we need to put them together
// into a "shader program" object
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
return shaderProgram;
}
function loadScene() {
// Get A WebGL context
/** #type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl");
if(!gl){return;}
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// gl.drawElements(gl.LINES, given_animal.vertex_indices_buffer.numItems, gl.UNSIGNED_SHORT, 0);
// gl.lineWidth(width);
// setup GLSL program
// var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
var program = loadShadersFromString(gl,vertexShader,fragmentShader);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "aPosition");
var centerLocation = gl.getAttribLocation(program, "aCenter");
// Create a buffer to put positions in
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(points),gl.STATIC_DRAW);
var centerBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(centers),gl.STATIC_DRAW);
drawScene();
function drawScene() {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas AND the depth buffer.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Turn on culling. By default backfacing triangles
// will be culled.
gl.enable(gl.CULL_FACE);
// Enable the depth buffer
gl.enable(gl.DEPTH_TEST);
gl.enable( gl.BLEND );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Turn on the position attribute
gl.enableVertexAttribArray(positionLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 3 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);
gl.enableVertexAttribArray(centerLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 3; // 3 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(centerLocation, size, type, normalize, stride, offset);
// Draw the geometry.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = points.length/2;
gl.drawArrays(primitiveType,offset,count);
// Call drawScene again next frame
requestAnimationFrame(drawScene);
}
}
loadScene();
body {
margin: 0;
background-color: wheat;
}
#html{
background-color: wheat;
}
canvas {
margin: 0;
position: absolute;
width: 90vw;
height: 90vh;
left: 5vw;
top: 5vh;
display: block;
}
<canvas id="canvas"></canvas>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
Blending can only work if the Depth Test is not enabled:
gl.enable(gl.DEPTH_TEST);
When the depth test is enabled, the fragments may be discarded by the depth test, before they can be blended.

get current pixel position on webGL2 fragment shader

I created a simple webGL script, it apply pixel color depending on (x,y) pixel position
What I get:
here's what I did:
#ifdef GL_ES
precision mediump float;
#endif
uniform float width;
uniform float height;
uniform float time;
void main() {
vec2 u_resolution = vec2(width, height);
vec2 st = gl_FragCoord.xy / u_resolution;
gl_FragColor = vec4(st.x, st.y, 0.5, 1.0);
}
Codepen: Hello WebGL
I'm trying to convert it to webGL2 but I don't know how to get current pixel position.
here's what I tried:
#version 300 es
#ifdef GL_ES
precision mediump float;
#endif
uniform float width;
uniform float height;
uniform float time;
out vec4 color;
void main() {
vec2 u_resolution = vec2(width, height);
vec2 st = color.xy / u_resolution;
color = vec4(st.x, st.y, 0.5, 1.0);
}
Codepen: Hello WebGL2
How to get current pixel position in webgl2?
gl_FragCoord is still the correct way in WebGL2
var canvas = document.body.appendChild(document.createElement("canvas"));
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var gl = canvas.getContext("webgl2");
//************** Shader sources **************
var vertexSource = `
#version 300 es
in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
var fragmentSource = `
#version 300 es
#ifdef GL_ES
precision mediump float;
#endif
uniform float width;
uniform float height;
uniform float time;
out vec4 color;
void main() {
vec2 u_resolution = vec2(width, height);
vec2 st = gl_FragCoord.xy / u_resolution;
color = vec4(st.x, st.y, 0.5, 1.0);
}`;
window.addEventListener("resize", onWindowResize, false);
function onWindowResize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
gl.uniform1f(widthHandle, window.innerWidth);
gl.uniform1f(heightHandle, window.innerHeight);
}
//Compile shader and combine with source
function compileShader(shaderSource, shaderType) {
var shader = gl.createShader(shaderType);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw "Shader compile failed with: " + gl.getShaderInfoLog(shader);
}
return shader;
}
//From https://codepen.io/jlfwong/pen/GqmroZ
//Utility to complain loudly if we fail to find the attribute/uniform
function getAttribLocation(program, name) {
var attributeLocation = gl.getAttribLocation(program, name);
if (attributeLocation === -1) {
throw "Cannot find attribute " + name + ".";
}
return attributeLocation;
}
function getUniformLocation(program, name) {
var attributeLocation = gl.getUniformLocation(program, name);
if (attributeLocation === -1) {
throw "Cannot find uniform " + name + ".";
}
return attributeLocation;
}
//************** Create shaders **************
//Create vertex and fragment shaders
var vertexShader = compileShader(vertexSource.trim(), gl.VERTEX_SHADER);
var fragmentShader = compileShader(fragmentSource.trim(), gl.FRAGMENT_SHADER);
//Create shader programs
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
//Set up rectangle covering entire canvas
var vertexData = new Float32Array([
-1.0,
1.0, // top left
-1.0,
-1.0, // bottom left
1.0,
1.0, // top right
1.0,
-1.0 // bottom right
]);
//Create vertex buffer
var vertexDataBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
// Layout of our data in the vertex buffer
var positionHandle = getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionHandle);
gl.vertexAttribPointer(
positionHandle,
2, // position is a vec2 (2 values per component)
gl.FLOAT, // each component is a float
false, // don't normalize values
2 * 4, // two 4 byte float components per vertex (32 bit float is 4 bytes)
0 // how many bytes inside the buffer to start from
);
//Set uniform handle
var timeHandle = getUniformLocation(program, "time");
var widthHandle = getUniformLocation(program, "width");
var heightHandle = getUniformLocation(program, "height");
gl.uniform1f(widthHandle, window.innerWidth);
gl.uniform1f(heightHandle, window.innerHeight);
function draw() {
//Send uniforms to program
gl.uniform1f(timeHandle, performance.now());
//Draw a triangle strip connecting vertices 0-4
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(draw);
}
draw();
html {
overflow: hidden;
}
canvas {
display: block;
}
Some other random tips.
These ifdefs are irrelevant
#ifdef GL_ES
precision mediump float;
#endif
Just
precision mediump float;
is fine.
I'm guessing this obvious but why pass in width and height separate?
How about just
uniform vec2 u_resolution;
No reason to call performance.now. The time is passed to your requestAnimationFrame callback
function draw(time) {
//Send uniforms to program
gl.uniform1f(timeHandle, time);
...
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
The code checks for compile errors but not link errors
You should check for link errors
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw "Program link failed with: " + gl.getProgramInfoLog(program);
}
There will be link errors if your varyings don't match and further the spec doesn't require compiling to ever fail even on bad shaders. Rather it only requires if they were bad to fail to link.
window.innerWidth
see: this
gl.getUniformLocation returns null if the uniform does not exist
The code is checking for -1 which is correct for attributes but not for uniforms.
throwing on attributes and uniforms not existing
Of course it's helpful to know they don't exist but it's common to debug shaders by commenting things out or editing. For example lets say nothing appears on the screen. If it was me the first thing I'd do is change the fragment shader to this
const fragmentSource = `
#version 300 es
precision mediump float;
uniform vec2 u_resolution;
uniform float time;
out vec4 color;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
color = vec4(st.x, st.y, 0.5, 1.0);
color = vec4(1, 0, 0, 1); // <----------------------
}`;
Just output a solid color to check if the issue is in the fragment shader or the vertex shader. The moment I do that most WebGL implentations will optimize out u_resolution and the code that throws when looking up locations effectively makes the program undebuggable.
In fact the code only runs currently because of the previous bug checking for -1 instead of null. With that bug fixed the code crashes beacuse time is optimized out.
var canvas = document.body.appendChild(document.createElement("canvas"));
var gl = canvas.getContext("webgl2");
//************** Shader sources **************
var vertexSource = `
#version 300 es
in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
var fragmentSource = `
#version 300 es
precision mediump float;
uniform vec2 u_resolution;
uniform float time;
out vec4 color;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
color = vec4(st.x, st.y, 0.5, 1.0);
}`;
function resize() {
if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
gl.uniform2f(resHandle, canvas.width, canvas.height);
}
}
//Compile shader and combine with source
function compileShader(shaderSource, shaderType) {
var shader = gl.createShader(shaderType);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw "Shader compile failed with: " + gl.getShaderInfoLog(shader);
}
return shader;
}
//From https://codepen.io/jlfwong/pen/GqmroZ
//Utility to complain loudly if we fail to find the attribute/uniform
function getAttribLocation(program, name) {
var attributeLocation = gl.getAttribLocation(program, name);
if (attributeLocation === -1) {
console.warn("Cannot find attribute", name);
}
return attributeLocation;
}
function getUniformLocation(program, name) {
var uniformLocation = gl.getUniformLocation(program, name);
if (uniformLocation === null) {
console.warn("Cannot find uniform", name);
}
return uniformLocation;
}
//************** Create shaders **************
//Create vertex and fragment shaders
var vertexShader = compileShader(vertexSource.trim(), gl.VERTEX_SHADER);
var fragmentShader = compileShader(fragmentSource.trim(), gl.FRAGMENT_SHADER);
//Create shader programs
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw "Program link failed with: " + gl.getProgramInfoLog(program);
}
gl.useProgram(program);
//Set up rectangle covering entire canvas
var vertexData = new Float32Array([
-1.0,
1.0, // top left
-1.0,
-1.0, // bottom left
1.0,
1.0, // top right
1.0,
-1.0 // bottom right
]);
//Create vertex buffer
var vertexDataBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
// Layout of our data in the vertex buffer
var positionHandle = getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionHandle);
gl.vertexAttribPointer(
positionHandle,
2, // position is a vec2 (2 values per component)
gl.FLOAT, // each component is a float
false, // don't normalize values
2 * 4, // two 4 byte float components per vertex (32 bit float is 4 bytes)
0 // how many bytes inside the buffer to start from
);
//Set uniform handle
var timeHandle = getUniformLocation(program, "time");
var resHandle = getUniformLocation(program, "u_resolution");
function draw(time) {
resize();
//Send uniforms to program
gl.uniform1f(timeHandle, time);
//Draw a triangle strip connecting vertices 0-4
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
html,body {
height: 100%;
margin: 0;
}
canvas {
width: 100%;
height: 100%;
display: block;
}

Why is rendering blurred in WebGL?

I'm very new to WebGL. I tried copying and pasting code from a WebGL tutorial https://webglfundamentals.org/webgl/lessons/webgl-fundamentals.html to render randomly sized and randomly colored rectangles, but found that the rectangles were very blurry in my browser (Firefox 67.0.4).
I've pasted the screenshot below. Because the image below is much smaller, the blurriness isn't as apparent as when viewed in my browser, but you can still see that it's blurry.
Does anyone know why it's coming out blurry in my browser, and how to fix?
Below I've re-pasted in its entirety the code for the WebGL program:
<canvas id="canvas"></canvas>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script>
//MAIN JAVASCRIPT CODE FOLLOWS HERE
"use strict";
function main() {
// Get A WebGL context
/** #type {HTMLCanvasElement} */
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
if (!gl) {
return;
}
// setup GLSL program
var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
// look up where the vertex data needs to go.
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// look up uniform locations
var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");
var colorUniformLocation = gl.getUniformLocation(program, "u_color");
// Create a buffer to put three 2d clip space points in
var positionBuffer = gl.createBuffer();
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Turn on the attribute
gl.enableVertexAttribArray(positionAttributeLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
// set the resolution
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
// draw 50 random rectangles in random colors
for (var ii = 0; ii < 50; ++ii) {
// Setup a random rectangle
// This will write to positionBuffer because
// its the last thing we bound on the ARRAY_BUFFER
// bind point
setRectangle(
gl, randomInt(300), randomInt(300), randomInt(300), randomInt(300));
// Set a random color.
gl.uniform4f(colorUniformLocation, Math.random(), Math.random(), Math.random(), 1);
// Draw the rectangle.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
gl.drawArrays(primitiveType, offset, count);
}
}
// Returns a random integer from 0 to range - 1.
function randomInt(range) {
return Math.floor(Math.random() * range);
}
// Fill the buffer with the values that define a rectangle.
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2,
]), gl.STATIC_DRAW);
}
main();
</script>
<style>
#import url("https://webglfundamentals.org/webgl/resources/webgl-tutorials.css");
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
</style>
The reason is is because you put the style section at the end. Things get executed in order so first the script executes. At that time there is no style so the canvas is the default 300x150. The script draws. Then the <style> section comes and tells the browser to display that 300x150 texture the full size of the window. Move the style section before the script or ideally to the top.
Still the sample only renders one time. If you resize the page it does not re-render so even if you move the <style> above the <script> if the window starts small and you resize the window larger you'll still get blur.
To handle resizing you'd need to render the rectangles again. To draw the same rectangles you'd need to save the positions, sizes, and colors used. It would be up to you to decide if they should stay the same size relative to the window or not, the same aspect or not.
You might find this article useful.
The code below picks 50 random rectangles and colors
// pick 50 random rectangles and their colors
const rectangles = [];
for (let ii = 0; ii < 50; ++ii) {
rectangles.push({
rect: [randomInt(300), randomInt(300), randomInt(300), randomInt(300)],
color: [Math.random(), Math.random(), Math.random(), 1],
});
}
It then draws the previously picked rectangles in a render function
function render() {
...
for (const rectangle of rectangles) {
// This will write to positionBuffer because
// its the last thing we bound on the ARRAY_BUFFER
// bind point
setRectangle(
gl, ...rectangle.rect);
// Set the color.
gl.uniform4f(colorUniformLocation, ...rectangle.color);
// Draw the rectangle.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
gl.drawArrays(primitiveType, offset, count);
}
}
finally it calls render when the page resizes
window.addEventListener('resize', render);
"use strict";
function main() {
// Get A WebGL context
/** #type {HTMLCanvasElement} */
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
if (!gl) {
return;
}
// setup GLSL program
var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
// look up where the vertex data needs to go.
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// look up uniform locations
var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");
var colorUniformLocation = gl.getUniformLocation(program, "u_color");
// Create a buffer to put three 2d clip space points in
var positionBuffer = gl.createBuffer();
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// pick 50 random rectangles and their colors
const rectangles = [];
for (let ii = 0; ii < 50; ++ii) {
rectangles.push({
rect: [randomInt(300), randomInt(300), randomInt(300), randomInt(300)],
color: [Math.random(), Math.random(), Math.random(), 1],
});
}
function render() {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Turn on the attribute
gl.enableVertexAttribArray(positionAttributeLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
// set the resolution
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
for (const rectangle of rectangles) {
// This will write to positionBuffer because
// its the last thing we bound on the ARRAY_BUFFER
// bind point
setRectangle(
gl, ...rectangle.rect);
// Set the color.
gl.uniform4f(colorUniformLocation, ...rectangle.color);
// Draw the rectangle.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
gl.drawArrays(primitiveType, offset, count);
}
}
render();
window.addEventListener('resize', render);
}
// Returns a random integer from 0 to range - 1.
function randomInt(range) {
return Math.floor(Math.random() * range);
}
// Fill the buffer with the values that define a rectangle.
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2,
]), gl.STATIC_DRAW);
}
main();
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="canvas"></canvas>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>

Why is not WebGL drawing point?

I can't understand what I do wrong, my mind going to blow
I just pushing value to list and want to draw point using this list like vertices(0)=x,vertices(1)=y and what to do if I have much point like
vertices(0)=x1,vertices(1)=y1,vertices(2)=x2,vertices(3)=y2 (about 600 points)?
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n'+'void main() {\n'+' gl_Position = a_Position;\n' + ' gl_PointSize = 10.0;\n' + '}\n';
var FSHADER_SOURCE='void main() {\n'+'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + '}\n';
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if (!gl) {console.log('Failed to get the rendering context for WebGL');
return;}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.'); return; }
var n = initVertexBuffers(gl);
if (n < 0) {console.log('Failed to set the positions of the vertices');
return;}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, n);
}
var vertices = [];
function initVertexBuffers(gl) {vertices.push(0.1);vertices.push(0.3);
var n = vertices.length/2; var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) { console.log('Failed to create the buffer object');
return -1; }
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {console.log('Failed to get the storage location of a_Position'); return -1; }
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position); return n; }
And file
initVertexBuffers
function initShaders(gl, vshader, fshader) {
var program = createProgram(gl, vshader, fshader);
if (!program) {
console.log('Failed to create program');
return false;
} gl.useProgram(program);gl.program = program;return true; }
function createProgram(gl, vshader, fshader) {
var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
if (!vertexShader || !fragmentShader) { return null;}
var program = gl.createProgram();
if (!program) {return null;}
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
var error = gl.getProgramInfoLog(program);
console.log('Failed to link program: ' + error);
gl.deleteProgram(program);
gl.deleteShader(fragmentShader);
gl.deleteShader(vertexShader);
return null;
} return program;}
function loadShader(gl, type, source) {
var shader = gl.createShader(type);
if (shader == null) {console.log('unable to create shader');
return null;}
gl.shaderSource(shader, source);
gl.compileShader(shader);
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {var error = gl.getShaderInfoLog(shader);
console.log('Failed to compile shader: ' + error);
gl.deleteShader(shader);return null;}return shader;}
function getWebGLContext(canvas, opt_debug) {
var gl = WebGLUtils.setupWebGL(canvas);
if (!gl) return null;
if (arguments.length < 2 || opt_debug) {
gl = WebGLDebugUtils.makeDebugContext(gl);
} return gl; }
At a glance this code
var vertices = [];
function initVertexBuffers(gl) {
vertices.push(0.1);
vertices.push(0.3);
var n = vertices.length/2;
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
won't work because gl.bufferData does not take JavaScript native arrays. It only takes typed arrays.
You probably want this
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var VSHADER_SOURCE = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 10.0;
}
`;
var FSHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
function main() {
var canvas = document.getElementById('webgl');
var gl = canvas.getContext("webgl");
if (!gl)
{
console.log('Failed to retrieve the <canvas> element');
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE))
{
console.log('Failed to intialize shaders.');
return;
}
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT);
var n = initVertexBuffers(gl);
if (n < 0) {console.log('Failed to set the positions of the vertices');
return;}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, n);
}
var vertices = [];
function initVertexBuffers(gl) {
vertices.push(0.1);
vertices.push(0.3);
var n = vertices.length/2;
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
return n;
}
// THIS IS A POORLY WRITTEN FUNCTION!!!!
// Normal WebGL pages use multiple shader programs
// therefore you should **NEVER** assign values to
// the gl object!!!
function initShaders(gl, vsrc, fsrc) {
gl.program = twgl.createProgram(gl, [vsrc, fsrc]);
gl.useProgram(gl.program);
return !!gl.program;
}
main();
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
<canvas id="webgl"></canvas>

Multiple Shader Programs to give different textures

little lost here. trying to set different textures on different vertices. WebGL makes this extremely unnecessarily difficult. Basically I have a text file with matrices of the vertices I want, which works. (example here: http://jdmdev.net/Foundation/index.html)
But to now set different textures I would need to do something called 'texture atlassing' which there is absolutely zero documentation on how to implement that online... anywhere.
I am very new to WebGL but have an extensive programming background so I am able to understand any concepts given to me.. if I can just see something working or at the very least some documentation on it.
So I think texture atlassing is out of the picture. However, if I am understadning the WebGL pipeline as well as I think I am. Can't I just create multiple shader/vertex programs? If so, how can I go about that? I don't need a direct example, but just some code will do wonders. I just need to see this one time and I will get it, but it's impossible to find any useful stuff on the web, due to this being so new. I appreciate any help given.
Not sure how any code would help with answering this question, but here's my code that I basically used from learningwebgltutorials.com
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform sampler2D uSampler2;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script>
<script id="shader2-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform sampler2D uSampler2;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
</script>
<script id="shader2-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script>
<script type="text/javascript">
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}
function handleLoadedTexture(texture) {
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.bindTexture(gl.TEXTURE_2D, null);
}
var mudTexture;
var rockTexture;
function initTexture() {
mudTexture = gl.createTexture();
mudTexture.image = new Image();
mudTexture.image.onload = function () {
handleLoadedTexture(mudTexture)
}
mudTexture.image.src = "mud.gif";
rockTexture = gl.createTexture();
rockTexture.image = new Image();
rockTexture.image.onload = function () {
handleLoadedTexture(rockTexture)
}
rockTexture.image.src = "rockstar.gif";
}
var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();
function mvPushMatrix() {
var copy = mat4.create();
mat4.set(mvMatrix, copy);
mvMatrixStack.push(copy);
}
function mvPopMatrix() {
if (mvMatrixStack.length == 0) {
throw "Invalid popMatrix!";
}
mvMatrix = mvMatrixStack.pop();
}
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
var currentlyPressedKeys = {};
function handleKeyDown(event) {
currentlyPressedKeys[event.keyCode] = true;
}
function handleKeyUp(event) {
currentlyPressedKeys[event.keyCode] = false;
}
var pitch = 0;
var pitchRate = 0;
var yaw = 0;
var yawRate = 0;
var xPos = 10;
var yPos = 0.4;
var zPos = 10;
var speed = 0;
function handleKeys() {
if (currentlyPressedKeys[33]) {
// Page Up
pitchRate = 0.1;
} else if (currentlyPressedKeys[34]) {
// Page Down
pitchRate = -0.1;
} else {
pitchRate = 0;
}
if (currentlyPressedKeys[37] || currentlyPressedKeys[65]) {
// Left cursor key or A
yawRate = 0.1;
} else if (currentlyPressedKeys[39] || currentlyPressedKeys[68]) {
// Right cursor key or D
yawRate = -0.1;
} else {
yawRate = 0;
}
if (currentlyPressedKeys[38] || currentlyPressedKeys[87]) {
// Up cursor key or W
speed = 0.01;
} else if (currentlyPressedKeys[40] || currentlyPressedKeys[83]) {
// Down cursor key
speed = -0.01;
} else {
speed = 0;
}
}
var worldVertexPositionBuffer = null;
var worldVertexTextureCoordBuffer = null;
function handleLoadedWorld(data) {
var lines = data.split("\n");
var vertexCount = 0;
var vertexPositions = [];
var vertexTextureCoords = [];
for (var i in lines) {
var vals = lines[i].replace(/^\s+/, "").split(/\s+/);
if (vals.length == 6 && vals[0] != "//") {
// It is a line describing a vertex; get X, Y and Z first
vertexPositions.push(parseFloat(vals[0]));
vertexPositions.push(parseFloat(vals[1]));
vertexPositions.push(parseFloat(vals[2]));
//document.write(vertexPositions[0]);
// And then the texture coords
vertexTextureCoords.push(parseFloat(vals[3]));
vertexTextureCoords.push(parseFloat(vals[4]));
//document.write(vals[4]) + "<br/>");
vertexCount += 1;
}
}
worldVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositions), gl.STATIC_DRAW);
worldVertexPositionBuffer.itemSize = 3;
worldVertexPositionBuffer.numItems = vertexCount;
worldVertexTextureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexTextureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexTextureCoords), gl.STATIC_DRAW);
worldVertexTextureCoordBuffer.itemSize = 2;
worldVertexTextureCoordBuffer.numItems = vertexCount;
document.getElementById("loadingtext").textContent = "";
}
function loadWorld() {
var request = new XMLHttpRequest();
request.open("GET", "world.txt");
request.onreadystatechange = function () {
if (request.readyState == 4) {
handleLoadedWorld(request.responseText);
}
}
request.send();
}
function loadTextureValues() {
var request = new XMLHttpRequest();
request.open("GET", "world.txt");
request.onreadystatechange = function () {
if (request.readyState == 4) {
getCorrectTexture(request.responseText);
}
}
request.send();
}
var matchWithTexture = {};
function getCorrectTexture(data)
{
var lines = data.split("\n");
var vertexCount = 0;
var vertexTextureValueCoords = [];
for (var i in lines) {
var vals = lines[i].replace(/^\s+/, "").split(/\s+/);
if (vals.length == 6 && vals[0] != "//")
{
//document.write(vertexTextureValueCoords.push(parseFloat(vals[1])) + "</br>");
vertexTextureValueCoords.push(parseFloat(vals[5]));
matchWithTexture[vertexCount] = vertexTextureValueCoords[vertexCount];
vertexCount++;
}
}
}
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (worldVertexTextureCoordBuffer == null || worldVertexPositionBuffer == null) {
return;
}
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.rotate(mvMatrix, degToRad(-pitch), [1, 0, 0]);
mat4.rotate(mvMatrix, degToRad(-yaw), [0, 1, 0]);
mat4.translate(mvMatrix, [-xPos, -yPos, -zPos]);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, mudTexture);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, rockTexture);
loadTextureValues();
for(var key in matchWithTexture)
{
//document.write(matchWithTexture[key] + "<br/>");
if(matchWithTexture[key] == 1)
{
gl.uniform1i(shaderProgram.samplerUniform, 0);
}
else {
gl.uniform1i(shaderProgram.samplerUniform, 1);
}
}
gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexTextureCoordBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, worldVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, worldVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, worldVertexPositionBuffer.numItems);
}
var lastTime = 0;
// Used to make us "jog" up and down as we move forward.
var joggingAngle = 0;
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
if (speed != 0) {
xPos -= Math.sin(degToRad(yaw)) * speed * elapsed;
zPos -= Math.cos(degToRad(yaw)) * speed * elapsed;
joggingAngle += elapsed * 0.6; // 0.6 "fiddle factor" - makes it feel more realistic :-)
yPos = Math.sin(degToRad(joggingAngle)) / 20 + 0.4
}
yaw += yawRate * elapsed;
pitch += pitchRate * elapsed;
}
lastTime = timeNow;
}
function tick() {
requestAnimFrame(tick);
handleKeys();
drawScene();
animate();
}
function webGLStart() {
var canvas = document.getElementById("lesson10-canvas");
initGL(canvas);
initShaders();
initTexture();
loadWorld();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp;
tick();
}
</script>
So all I did was create a 2nd shader/vertex program, and it still works. So how can I go about implementing them with different information from the first shader/vertex programs?
And a last question would be: would it just be worth it more to use a library instead of trying to do everything in webgl? I mean, with all the google searches I have done on webgl, most of all the examples/tutorials are all done using three.js, or babylon.js..etc. I'm just wondering if it's even worth it to try to do what I am doing. I guess what the question would be is, would professional settings want me to do straight up webgl, or would I (most likely) be using a library? I don't ever even plan on programming webgl, but just to know if it ever comes up in an interview.
SOLUTION VIA NO-TEXTURE ALIASING
https://github.com/jordmax12/WebGL/blob/master/Foundation%205/foundation_2.js
Since I was already parsing information from a text file for vertices and texture coordinates, there MUST be a way to do this for the texture itself (without texture aliasing).
You can use different textures and shaders on different vertices if you draw them one by one. The problem is that this is quite inefficient. So for good performance, I don't think there is a way around atlasing -- that's why everybody is doing this.
I am not aware of any three.js util to simplify atlasing (but I am not very familiar with three.js).
It should be straight forward to implement a utility that draws the textures to a big canvas, creating the atlas on the fly at runtime and keeping track of the coordinates. After setup, the tool would basically transform coordinates and texture names or ids to a pure coordinate array (including texture coordinates).
Whether you should use a library really depends on what you plan to do. If a retained mode API works for your use case, it's probably a good idea and more convenient to use three.js.

Resources