Why WebGL in this code doesn't render a outlined rectangle? - javascript

I'm noob to WebGL and tried to make outlined rectangle but in same time with using shaders that i mixed them :)
The problem is the code doesn't give errors, But doesn't render outlined rectangle with clearing, It's just clear and rectangle not rendered...
Here is vertex shader...
// VERTEX SHADER
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_translation;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
vec2 zeroToOne = (a_position + u_translation) / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_texCoord = a_texCoord;
}
Here is fragment shader...
// FRAGMENT SHADER
precision mediump float;
uniform sampler2D u_image;
uniform vec4 u_color;
uniform int u_mode;
varying vec2 v_texCoord;
void main(void) {
if (u_mode == 1) { gl_FragColor = u_color; }
if (u_mode == 2) { gl_FragColor = texture2D(u_image, v_texCoord); }
if (u_mode == 3) { gl_FragColor = u_color + texture2D(u_image, v_texCoord); }
}
Oh...And here is HTML file...
<!DOCTYPE html>
<html>
<head>
<title>POLYGL Test</title>
</head>
<body>
<canvas width="600" height="600"></canvas>
<script>
// Get context
var gl = document.getElementsByTagName("canvas")[0].getContext("webgl");
// Create buffers for rectangle
var x = 100, y = 100, w = 50, h = 50;
var rect = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, rect);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x, -y,
x + w, -y,
x + w, -(y + h),
x, -(y + h),
]), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create shaders and assign GLSL code for them...
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, `
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_translation;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
vec2 zeroToOne = (a_position + u_translation) / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_texCoord = a_texCoord;
}`);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, `
precision mediump float;
uniform sampler2D u_image;
uniform vec4 u_color;
uniform int u_mode;
varying vec2 v_texCoord;
void main(void) {
if (u_mode == 1) { gl_FragColor = u_color; }
if (u_mode == 2) { gl_FragColor = texture2D(u_image, v_texCoord); }
if (u_mode == 3) { gl_FragColor = u_color + texture2D(u_image, v_texCoord); }
}`);
gl.compileShader(fs);
// Create program and link all
var p = gl.createProgram();
gl.attachShader(p, vs);
gl.attachShader(p, fs);
gl.linkProgram(p);
gl.useProgram(p);
// Delete shaders and program after being used...
gl.deleteShader(vs);
gl.deleteShader(fs);
gl.deleteProgram(p);
// Clear to black and set viewport
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Set color, resolution, And translation...
// Set mode to 1 so it only renders with gl_FragColor
gl.uniform1i(gl.getUniformLocation(p, "u_mode"), 1);
gl.uniform4f(gl.getUniformLocation(p, "u_color"), Math.random(), Math.random(), Math.random(), 1);
gl.uniform2f(gl.getUniformLocation(p, "u_resolution"), gl.canvas.width, gl.canvas.height);
gl.uniform2f(gl.getUniformLocation(p, "u_translation"), 0, 0);
// Bind rectangle buffer
// Enable vertex attribute and assign buffer to shaders...
gl.bindBuffer(gl.ARRAY_BUFFER, rect);
gl.vertexAttribPointer(gl.getAttribLocation(p, "a_position"), 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(gl.getAttribLocation(p, "a_position"));
// Draw!
gl.drawArrays(gl.LINE_LOOP, 0, 4);
</script>
</body>
</html>
I tried even to remove deletions of programs but looks like it doesn't help...
Can anyone help me?

Solved, The indices aren't right cause height is negative, Fixed!
<!DOCTYPE html>
<html>
<head>
<title>POLYGL Test</title>
</head>
<body>
<canvas width="600" height="600"></canvas>
<script>
var gl = document.getElementsByTagName("canvas")[0].getContext("webgl");
var x = 100, y = 100, w = 50, h = 50;
var rect = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, rect);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x, y,
x + w, y,
x + w, y + h,
x, y + h,
]), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, `
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_translation;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
vec2 zeroToOne = (a_position + u_translation) / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_texCoord = a_texCoord;
}`);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, `
precision mediump float;
uniform sampler2D u_image;
uniform vec4 u_color;
uniform int u_mode;
varying vec2 v_texCoord;
void main(void) {
if (u_mode == 1) { gl_FragColor = u_color; }
if (u_mode == 2) { gl_FragColor = texture2D(u_image, v_texCoord); }
if (u_mode == 3) { gl_FragColor = u_color + texture2D(u_image, v_texCoord); }
}`);
gl.compileShader(fs);
var p = gl.createProgram();
gl.attachShader(p, vs);
gl.attachShader(p, fs);
gl.linkProgram(p);
gl.useProgram(p);
gl.deleteShader(vs);
gl.deleteShader(fs);
gl.deleteProgram(p);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.uniform1i(gl.getUniformLocation(p, "u_mode"), 1);
gl.uniform4f(gl.getUniformLocation(p, "u_color"), Math.random(), Math.random(), Math.random(), 1);
gl.uniform2f(gl.getUniformLocation(p, "u_resolution"), gl.canvas.width, gl.canvas.height);
gl.uniform2f(gl.getUniformLocation(p, "u_translation"), 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, rect);
gl.vertexAttribPointer(gl.getAttribLocation(p, "a_position"), 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(gl.getAttribLocation(p, "a_position"));
gl.drawArrays(gl.LINE_LOOP, 0, 4);
</script>
</body>
</html>

Related

How do I pass the canvas as a texture to a shader?

I want to manipulate the canvas with a shader, but I am stuck with how to pass the current canvas to the shader? I assume I use sampler2D.
Why doesn't this code invert the canvas? Instead it's just a blank white screen.
image(cnvs) works perfectly fine.
script.js
let cnvs;
let shdr;
function preload() {
shdr = loadShader("shaders/shader.vert", "shaders/shader.frag");
}
function setup() {
cnvs = createCanvas(500, 500, WEBGL);
}
function draw() {
fill(255, 0, 0);
square(0, 0, width / 2);
shdr.setUniform("u_resolution", [width, height]);
shdr.setUniform("u_texture", cnvs);
shader(shdr);
fill(0);
rect(0, 0, width, height);
resetShader();
noLoop();
}
shader.frag
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform sampler2D u_texture;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
st.y = 1.0 - st.y;
vec4 tex = texture2D(u_texture, st);
gl_FragColor = tex;
}
shader.vert
#ifdef GL_ES
precision mediump float;
#endif
attribute vec3 aPosition;
void main() {
vec4 positionVec4 = vec4(aPosition, 1.0); // Copy the position data into a vec4, adding 1.0 as the w parameter
positionVec4.xy = positionVec4.xy * 2.0 - 1.0; // Scale to make the output fit the canvas.
gl_Position = positionVec4;
}

Can't manage to make a shader running on three.js from shaderfrom

I would like to import that shader on my project:
https://shaderfrog.com/app/view/2447
This is my fragment shader:
<script id="fragmentShader" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
uniform sampler2D texture1;
// Example varyings passed from the vertex shader
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vec3 color = vec3(texture2D(texture1, vUv));
vec3 outcolor=color;
float v = u_time + (vUv.x*0.5 + vUv.y*0.5);
vec2 Uv2 = vec2(color.r+color.b+v,color.g+color.b+v);
outcolor = vec3(texture2D(texture1, Uv2));
gl_FragColor = vec4( outcolor, 1.0 );
}
</script>
And this is my vertex shader:
<script id="vertexShader" type="x-shader/x-vertex">
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vNormal = normal;
vUv = uv;
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
My shader is compiling, but I don't have the same result, I only have a highly frozen contrasted image. Plus, I do increment my uniform u_time value on a requestAnimationFrame function.
I can't see what I'm doing wrong?
I've simplified your code and made it work with the latest revision (r96).
Pay attention to the settings of the texture.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 2);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var tex = new THREE.TextureLoader().load("https://threejs.org/examples/textures/UV_Grid_Sm.jpg");
tex.wrapS = THREE.RepeatWrapping;
tex.wrapT = THREE.RepeatWrapping;
var geo = new THREE.PlaneBufferGeometry(2, 2);
var mat = new THREE.ShaderMaterial({
uniforms:{
time: {value: 0},
texture1: {value: tex}
},
vertexShader:`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`,
fragmentShader: `
uniform float time;
uniform sampler2D texture1;
varying vec2 vUv;
void main() {
vec3 c = vec3(texture2D(texture1, vUv));
float v = time + (vUv.x*0.5 + vUv.y*0.5);
vec2 Uv2 = vec2(c.r + c.b+v, c.g + c.b + v);
vec3 outcolor = vec3(texture2D(texture1, Uv2));
gl_FragColor = vec4( outcolor, 1.0 );
}
`
});
var plane = new THREE.Mesh(geo, mat);
scene.add(plane);
var clock = new THREE.Clock();
var time = 0;
render();
function render(){
requestAnimationFrame(render);
time += clock.getDelta();
mat.uniforms.time.value = time;
renderer.render(scene, camera);
}
body{
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>

How to blend textures with different size in webgl

I have 2 pictures with different sizes. Say the bgImage is 300*200 and the modelImage is 50*20. It can be described below, where the x and y can be (100, 50)
There is my glsl code:
vs:
attribute vec4 a_position;
attribute vec2 a_texCoord;
uniform float u_flipY;
varying vec2 v_texCoord;
void main() {
gl_Position = a_position * vec4(1.0, u_flipY, 0.0, 1.0);
v_texCoord = a_texCoord;
}
fs:
precision mediump float;
uniform sampler2D u_bgImage;
uniform sampler2D u_modelImage;
varying vec2 v_texCoord;
vec3 compose(vec4 bgRGBA, vec4 modelRGBA) {
vec3 bgRGB = bgRGBA.rgb;
float alpha = modelRGBA.a;
vec3 modelRGB = modelRGBA.rgb;
return modelRGB + bgRGB * (1.0 - alpha);
}
void main() {
vec4 bgRGBA = texture2D(u_bgImage, v_texCoord);
vec4 modelRGBA = texture2D(u_coverImage, v_texCoord);
gl_FragColor = vec4(compose(bgRGBA, modelRGBA), 1.0);
}
It seems like that when the webgl render, bgImage and modelImage will always have same size. So how to blend textures with different size?

GLSL shader to support coloring and texturing

Im trying to write a shader that support both color and texture.
For some reason I can make it work.
No errors threw and each of them work perfect separately,
get location:
shaderProgram.useTextureUniform = gl.getUniformLocation(shaderProgram, "uUseTexture");
when drawing I change the value like this:
var uUseTexture=false;
gl.uniform1f(shaderProgram.useTextureUniform, uUseTexture);
And the GLSL itself:
fragment:
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
varying vec4 vColor;
uniform bool uUseTexture;
void main(void) {
vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
vec4 texColor = vec4(textureColor.rgb, textureColor.a);
vec4 vertexColor = vColor;
if (!uUseTexture){
gl_FragColor = vertexColor;
}
else{
gl_FragColor = texColor;
}
}
vertex:
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
varying vec2 vTextureCoord;
varying vec4 vColor;
void main(void){
vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * mvPosition;
vTextureCoord = aTextureCoord;
vColor = aVertexColor;}
Before I tell you how to make your shader work you arguably should not do it that way. You should either
Make 2 shaders
Make one shader that uses a texture and a different shader that uses vertex colors. This is what nearly all professional game engines would do.
Make a shader that multiplies both colors and set one to white
If you have
gl_FragColor = vertexColor * textureColor;
Then if textureColor is 1,1,1,1 that means you're multiplying by 1
and so the result is just vertexColor. Similarly if vertexColor
is 1,1,1,1 then you're multiplying by 1 and so the result is just
textureColor
You can get a white texture by making just a single pixel white texture
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA,
gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]));
Then anytime you just want vertex colors bind that texture to a texture
unit and tell the sampler which unit it you put it in
You might also want to turn off texture coordinates
gl.disableVertexAttribArray(texcoordLocation);
When you want just texture color then you can do this
// turn off the attribute
gl.disableVertexAttribArray(aVertexColorLocation);
// set the attribute's constant value
gl.vertexAttrib4f(aVertexColorLocation, 1, 1, 1, 1);
This method has the added benefit that you can also use both texture colors and vertex colors together to modify the texture color or to tint the texture color. Many game engines would do this as well specifically to take advantage of that ability to blend the colors.
Pauli mentions another option which is to use mix
uniform float u_mixAmount;
gl_FragColor = mix(textureColor, vertexColor, u_mixAmount);
This would also work as you can set u_mixAmount to 0.0 when you want
textureColor and to 1.0 when you want vertexColor but unlike your
boolean example you can also fade between the 2 colors with values
between 0.0 and 1.0. For example 0.3 is 30% of vertexColor and 70%
of textureColor
A few other things
This line
vec4 texColor = vec4(textureColor.rgb, textureColor.a);
Is no different than
vec4 texColor = textureColor;
Just trying your shader it seems to work as is which suggests the issue is not your shader but some other part of your code.
var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;
var arrays = {
aVertexPosition: [
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0,
],
aVertexNormal: [
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
],
aTextureCoord: [
0, 0,
1, 0,
0, 1,
1, 1,
],
aVertexColor: [
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
1, 0, 1, 1,
],
indices: [
0, 1, 2,
2, 1, 3,
],
};
var tex = twgl.createTexture(gl, {
format: gl.LUMINANCE,
mag: gl.NEAREST,
src: [224, 64, 128, 192],
});
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var programInfo = twgl.createProgramInfo(gl, ['vs', 'fs']);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
for (var i = 0; i < 2; ++i) {
twgl.setUniforms(programInfo, {
uMVMatrix: m4.identity(),
uPMatrix: m4.scale(m4.translation([i === 0 ? -0.5 : 0.5, 0, 0]), [0.5, 1, 1]),
uNMatrix: m4.identity(),
uSampler: tex,
uUseTexture: i === 1,
});
twgl.drawBufferInfo(gl, bufferInfo);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script>
<script id="fs" type="not-js">
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
varying vec4 vColor;
uniform bool uUseTexture;
void main(void) {
vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
vec4 texColor = vec4(textureColor.rgb, textureColor.a);
vec4 vertexColor = vColor;
if (!uUseTexture){
gl_FragColor = vertexColor;
}
else{
gl_FragColor = texColor;
}
}
</script>
<script id="vs" type="not-js">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
varying vec2 vTextureCoord;
varying vec4 vColor;
void main(void){
vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * mvPosition;
vTextureCoord = aTextureCoord;
vColor = aVertexColor;}
</script>
<canvas></canvas>

WebGl memory notation for matrices

Since webGL derives from openGL the coordinate system should be right handed, but as I'm trying to rotate a model by hand-writing the rotation matrix the visual output is the opposite of what I'd expect.
OpenGL needed matrices written in column-major format, and this is the way i'm handwriting a 90° counter-clockwise rotation matrix (assuming we're using a right handed coordinate system) around the y axis:
var rot = new glMatrix.ARRAY_TYPE(16);
//I indexed the array this way to edit those values as if I
were editing rows instead of columns
rot[0] = 0;
rot[4] = 0;
rot[8] = -1;
rot[12] = 0;
rot[1] = 0;
rot[5] = 1;
rot[9] = 0;
rot[13] = 0;
rot[2] = 1;
rot[6] = 0;
rot[10] = 0;
rot[14] = 0;
rot[3] = 0;
rot[7] = 0;
rot[11] = 0;
rot[15] = 1;
gl.uniformMatrix4fv(Program.model, false, rot);
I'd expect a 90° ccw rotation around the y axis but i'm getting a cw one instead. The transpose works as expected which means either the math is wrong or that I'm missing something else
Storage is orthogonal to how matrices are used. You can store them column major or row major. How they get used in multiplication is unrelated to their storage.
To make that clear I could store the matrix like this
// storage format 1
[xaxis-x, xaxis-y, xaxis-z, 0,
yaxis-x, yaxis-y, yaxis-z, 0,
zaxis-x, zazis-y, xaxis-z, 0,
trans-x, trans-y, trans-z, 1]
Or I could store it like this
// storage format 2
[xaxis-x, yaxis-x, zaxis-x, trans-x,
xaxis-y, yaxis-y, zaxis-y, trans-y,
xaxis-z, yazis-z, zaxis-z, trans-z,
0, 0, 0, 1]
I can then write all of these functions
columnMajorMutliplyUsingStorageFormat1(matrix, vector)
columnMajorMutliplyUsingStorageFormat2(matrix, vector)
rowMajorMutliplyUsingStorageFormat1(matrix, vector)
rowMajorMutliplyUsingStorageFormat2(matrix, vector)
You can imagine how those functions would be written. The point is storage format is separate from usage.
In any case pretty much all WebGL and OpenGL programs a matrix almost always takes storage format 1
// storage format 1
[xaxis-x, xaxis-y, xaxis-z, 0,
yaxis-x, yaxis-y, yaxis-z, 0,
zaxis-x, zazis-y, xaxis-z, 0,
trans-x, trans-y, trans-z, 1]
You can verify this in OpenGL 1.0.
glMatrixMode(GL_MODELVIEW);
glTranslatef(1.0f, 2.0f, 3.0f);
float mat[16];
glGetFloatv(GL_MODELVIEW, &mat[0]);
printf("%f %f %f %f\n", mat[0], mat[1], mat[2], mat[3]);
printf("%f %f %f %f\n", mat[4], mat[5], mat[6], mat[7]);
printf("%f %f %f %f\n", mat[8], mat[9], mat[10], mat[11]);
printf("%f %f %f %f\n", mat[12], mat[13], mat[14], mat[15]);
Will print something like
1 0 0 0
0 1 0 0
0 0 1 0
1 2 3 1
In other words if you want to set the translation set elements 12, 13, 14. If you want to set xaxis set elements 0, 1, 2
Here's the typical example with translation in elements 12, 13, 14
The canonical example of usage would be
gl_Position = worldViewProjectionMatrix * position;
"use strict";
twgl.setDefaults({attribPrefix: "a_"});
var m4 = twgl.m4;
var gl = document.getElementById("c").getContext("webgl")
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 2);
var tex = twgl.createTexture(gl, {
min: gl.NEAREST,
mag: gl.NEAREST,
src: [
255, 255, 255, 255,
192, 192, 192, 255,
192, 192, 192, 255,
255, 255, 255, 255,
],
});
var uniforms = {
u_lightWorldPos: [1, 8, -10],
u_lightColor: [0.4, 0.8, 0.8, 1],
u_ambient: [0, 0, 0, 1],
u_specular: [1, 1, 1, 1],
u_shininess: 50,
u_specularFactor: 1,
u_diffuse: tex,
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var projection = m4.perspective(30 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.5, 10);
var eye = [1, 4, -6];
var target = [0, 0, 0];
var up = [0, 1, 0];
var camera = m4.lookAt(eye, target, up);
var view = m4.inverse(camera);
var viewProjection = m4.multiply(view, projection);
var world = m4.rotationY(time);
uniforms.u_viewInverse = camera;
uniforms.u_world = world;
uniforms.u_worldInverseTranspose = m4.transpose(m4.inverse(world));
uniforms.u_worldViewProjection = m4.multiply(world, viewProjection);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script id="vs" type="notjs">
uniform mat4 u_worldViewProjection;
uniform vec3 u_lightWorldPos;
uniform mat4 u_world;
uniform mat4 u_viewInverse;
uniform mat4 u_worldInverseTranspose;
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec2 a_texcoord;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
v_texCoord = a_texcoord;
v_position = (u_worldViewProjection * a_position);
v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
v_surfaceToLight = u_lightWorldPos - (u_world * a_position).xyz;
v_surfaceToView = (u_viewInverse[3] - (u_world * a_position)).xyz;
gl_Position = v_position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
uniform vec4 u_lightColor;
uniform vec4 u_ambient;
uniform sampler2D u_diffuse;
uniform vec4 u_specular;
uniform float u_shininess;
uniform float u_specularFactor;
vec4 lit(float l ,float h, float m) {
return vec4(1.0,
max(l, 0.0),
(l > 0.0) ? pow(max(0.0, h), m) : 0.0,
1.0);
}
void main() {
vec4 diffuseColor = texture2D(u_diffuse, v_texCoord);
vec3 a_normal = normalize(v_normal);
vec3 surfaceToLight = normalize(v_surfaceToLight);
vec3 surfaceToView = normalize(v_surfaceToView);
vec3 halfVector = normalize(surfaceToLight + surfaceToView);
vec4 litR = lit(dot(a_normal, surfaceToLight),
dot(a_normal, halfVector), u_shininess);
vec4 outColor = vec4((
u_lightColor * (diffuseColor * litR.y + diffuseColor * u_ambient +
u_specular * litR.z * u_specularFactor)).rgb,
diffuseColor.a);
gl_FragColor = outColor;
}
</script>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<canvas id="c"></canvas>
and here's the opposite example with translation in elements 3, 7, 11
In this case the math in the shader has been changed to
gl_Position = position * worldViewProjectionMatrix;
"use strict";
twgl.setDefaults({attribPrefix: "a_"});
var m4 = twgl.m4;
var gl = document.getElementById("c").getContext("webgl")
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 2);
var tex = twgl.createTexture(gl, {
min: gl.NEAREST,
mag: gl.NEAREST,
src: [
255, 255, 255, 255,
192, 192, 192, 255,
192, 192, 192, 255,
255, 255, 255, 255,
],
});
var uniforms = {
u_lightWorldPos: [1, 8, -10],
u_lightColor: [0.4, 0.8, 0.8, 1],
u_ambient: [0, 0, 0, 1],
u_specular: [1, 1, 1, 1],
u_shininess: 50,
u_specularFactor: 1,
u_diffuse: tex,
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var projection = m4.perspective(30 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.5, 10);
var eye = [1, 4, -6];
var target = [0, 0, 0];
var up = [0, 1, 0];
var camera = m4.lookAt(eye, target, up);
var view = m4.inverse(camera);
var viewProjection = m4.multiply(view, projection);
var world = m4.rotationY(time);
uniforms.u_viewInverse = m4.transpose(camera);
uniforms.u_world = m4.transpose(world);
uniforms.u_worldInverseTranspose = m4.transpose(m4.transpose(m4.inverse(world)));
uniforms.u_worldViewProjection = m4.transpose(m4.multiply(world, viewProjection));
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script id="vs" type="notjs">
uniform mat4 u_worldViewProjection;
uniform vec3 u_lightWorldPos;
uniform mat4 u_world;
uniform mat4 u_viewInverse;
uniform mat4 u_worldInverseTranspose;
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec2 a_texcoord;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
v_texCoord = a_texcoord;
v_position = (a_position * u_worldViewProjection);
v_normal = (vec4(a_normal, 0) * u_worldInverseTranspose).xyz;
v_surfaceToLight = u_lightWorldPos - (a_position * u_world).xyz;
v_surfaceToView = (u_viewInverse[3] - (a_position * u_world)).xyz;
gl_Position = v_position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
uniform vec4 u_lightColor;
uniform vec4 u_ambient;
uniform sampler2D u_diffuse;
uniform vec4 u_specular;
uniform float u_shininess;
uniform float u_specularFactor;
vec4 lit(float l ,float h, float m) {
return vec4(1.0,
max(l, 0.0),
(l > 0.0) ? pow(max(0.0, h), m) : 0.0,
1.0);
}
void main() {
vec4 diffuseColor = texture2D(u_diffuse, v_texCoord);
vec3 a_normal = normalize(v_normal);
vec3 surfaceToLight = normalize(v_surfaceToLight);
vec3 surfaceToView = normalize(v_surfaceToView);
vec3 halfVector = normalize(surfaceToLight + surfaceToView);
vec4 litR = lit(dot(a_normal, surfaceToLight),
dot(a_normal, halfVector), u_shininess);
vec4 outColor = vec4((
u_lightColor * (diffuseColor * litR.y + diffuseColor * u_ambient +
u_specular * litR.z * u_specularFactor)).rgb,
diffuseColor.a);
gl_FragColor = outColor;
}
</script>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<canvas id="c"></canvas>

Categories

Resources