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

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;
}

Related

How to have distortion effect on image using Javascript?

I'm trying to build a simple image distortion effect on mouse hover same as in this link.
I am expecting to have same output as this, the output is working, but there are 2 issues:
I want to have idle animation, but I could not find the way to
implement it in documentation.
I want to change depth of mouse when hover over image.
EDIT:
I tried to re-implement same effect using Javascript library:
body {
margin: 0;
background: #fff;
padding: 0;
}
.container {
position: relative;
}
/* canvas */
#canvas {
position: fixed;
top: 0;
right: 0;
left: 0;
height: 100vh;
z-index: 10;
}
#flowmap {
width: 100%;
height: 100vh;
}
#flowmap img {
display: none;
}
<div class="container">
<div id="canvas"></div>
<div id="flowmap">
<img src="https://i.imgur.com/wATUVc1.jpeg" alt="" data-sampler="planeTexture" />
</div>
</div>
<script>
// flowmap shaders
const flowmapVs = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
// default mandatory variables
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
// custom variables
varying vec3 vVertexPosition;
varying vec2 vTextureCoord;
void main() {
vec3 vertexPosition = aVertexPosition;
gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);
// varyings
vTextureCoord = aTextureCoord;
vVertexPosition = vertexPosition;
}
`;
const flowmapFs = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
varying vec3 vVertexPosition;
varying vec2 vTextureCoord;
uniform sampler2D uFlowMap;
uniform vec2 uMousePosition;
uniform float uFalloff;
uniform float uAlpha;
uniform float uDissipation;
uniform float uCursorGrow;
uniform vec2 uVelocity;
uniform float uAspect;
void main() {
vec2 textCoords = vTextureCoord;
/*** comment this whole block for a regular mouse flow effect ***/
// convert to -1 -> 1
textCoords = textCoords * 2.0 - 1.0;
// make the cursor grow with time
textCoords /= uCursorGrow;
// adjust cursor position based on its growth
textCoords += uCursorGrow * uMousePosition / (1.0 / (uCursorGrow - 1.0) * pow(uCursorGrow, 2.0));
// convert back to 0 -> 1
textCoords = (textCoords + 1.0) / 2.0;
/*** end of whole block commenting for a regular mouse flow effect ***/
vec4 color = texture2D(uFlowMap, textCoords) * uDissipation;
//vec4 color = vec4(0.0, 0.0, 0.0, 1.0) * uDissipation;
vec2 mouseTexPos = (uMousePosition + 1.0) * 0.5;
vec2 cursor = vTextureCoord - mouseTexPos;
cursor.x *= uAspect;
vec3 stamp = vec3(uVelocity * vec2(1.0, -1.0), 1.0 - pow(1.0 - min(1.0, length(uVelocity)), 3.0));
float falloff = smoothstep(uFalloff, 0.0, length(cursor)) * uAlpha;
color.rgb = mix(color.rgb, stamp, vec3(falloff));
// handle premultiply alpha
color.rgb = color.rgb * color.a;
gl_FragColor = color;
}
`;
const displacementVs = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
// default mandatory variables
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 planeTextureMatrix;
// custom variables
varying vec3 vVertexPosition;
varying vec2 vPlaneTextureCoord;
varying vec2 vTextureCoord;
void main() {
vec3 vertexPosition = aVertexPosition;
gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);
// varyings
vTextureCoord = aTextureCoord;
vPlaneTextureCoord = (planeTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;
vVertexPosition = vertexPosition;
}
`;
const displacementFs = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
varying vec3 vVertexPosition;
varying vec2 vPlaneTextureCoord;
varying vec2 vTextureCoord;
uniform sampler2D planeTexture;
uniform sampler2D uFlowTexture;
// the uniform we declared inside our javascript
uniform float uTime;
void main() {
// our flowmap
vec4 flowTexture = texture2D(uFlowTexture, vTextureCoord);
// distort our image texture based on the flowmap values
vec2 distortedCoords = vPlaneTextureCoord;
distortedCoords -= (flowTexture.xy * 0.1);
// get our final texture based on the displaced coords
vec4 texture = texture2D(planeTexture, distortedCoords);
// get a B&W version of our image texture
vec4 textureBW = vec4(1.4);
textureBW.rgb = vec3(texture.r * 0.3 + texture.g * 0.59 + texture.b * 0.11);
// mix the BW image and the colored one based on our flowmap color values
float mixValue = clamp((abs(flowTexture.r) + abs(flowTexture.g) + abs(flowTexture.b)) * 1.5, 0.0, 0.0);
texture = mix(texture, textureBW, mixValue);
// switch between this 2 lines to see what we have drawn onto our flowmap
//gl_FragColor = flowTexture;
gl_FragColor = texture;
}
`;
</script>
<script type="module">
// add cdn of curtainsjs
import {
Curtains,
Plane,
Vec2,
PingPongPlane,
} from "https://cdn.jsdelivr.net/npm/curtainsjs#7.2.0/src/index.mjs";
window.addEventListener("load", () => {
// set up webGl contetxt or set up curtiansjs
const curtains = new Curtains({
container: "canvas",
pixelRatio: Math.min(1.5, window.devicePixelRatio),
});
// mouse/touch move
const ww = window.innerWidth;
const wh = window.innerHeight;
const mouse = new Vec2(ww / 5, wh / 5);
const lastMouse = mouse.clone();
const velocity = new Vec2();
function onMouseMove(e) {
lastMouse.copy(mouse);
// touch event
if (e.targetTouches) {
mouse.set(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
} else {
mouse.set(e.clientX, e.clientY);
}
velocity.set((mouse.x - lastMouse.x) / 16, (mouse.y - lastMouse.y) / 16);
// update the velocity
updateVelocity = true;
}
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", onMouseMove, {
passive: true,
});
// create planeElement
const planeElement = document.getElementById("flowmap");
// parameters
const flowMapParams = {
sampler: "uFlowMap",
vertexShader: flowmapVs,
fragmentShader: flowmapFs,
texturesOptions: {
floatingPoint: "half-float",
},
uniforms: {
mousePosition: {
name: "uMousePosition",
type: "2f",
value: mouse,
},
fallOff: {
name: "uFalloff",
type: "1f",
value: ww > wh ? ww / 10000 : wh / 10000,
// we can change what i want here
},
time: {
name: "uTime", // uniform name that will be passed to our shaders
type: "1f", // this means our uniform is a float
value: 0,
},
cursorGrow: {
name: "uCursorGrow",
type: "1f",
value: 1.15,
},
// alpha of the cursor
alpha: {
name: "uAlpha",
type: "1f",
value: 1.14,
},
dissipation: {
name: "uDissipation",
type: "1f",
value: 0.925,
},
velocity: {
name: "uVelocity",
type: "2f",
value: velocity,
},
aspect: {
name: "uAspect",
type: "1f",
value: ww / wh,
},
},
};
// create ping pong plane
const flowMap = new PingPongPlane(curtains, planeElement, flowMapParams);
flowMap.onRender(() => {
flowMap.uniforms.time.value++;
// update mouse position
flowMap.uniforms.mousePosition.value = flowMap.mouseToPlaneCoords(mouse);
flowMap.uniforms.velocity.value = new Vec2(
curtains.lerp(velocity.x, 0.5, 1.5),
curtains.lerp(velocity.y, 0.5, 1.5)
);
});
// add displacements shader
const params = {
vertexShader: displacementVs,
fragmentShader: displacementFs,
};
// create plane
const plane = new Plane(curtains, planeElement, params);
// create a texture that will hold our flowmap
const flowTexture = plane.createTexture({
sampler: "uFlowTexture",
fromTexture: flowMap.getTexture(), // set it based on our PingPongPlane flowmap plane's texture
});
});
</script>

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

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>

How to use GLSL scale and position together with VideoContext?

I have an interesting problem with the VideoContext library.
I am trying to apply glsl Scale to media, which works ok, but when I then subsequently use a Position effect, I find that the media is then "cut off" at the top, revealing the black background color, making a sort of "black bar" at the top of the media. Please see the problem area circled in red here:
This seems like strange behavior to me, since I had already scaled up the media.
I have made a CodePen demonstrating the problem here:
https://codepen.io/kingpalethe/pen/xeVYLr?editors=0010
Here is all the JS of this codepen:
const exampleMediaFile = {
url: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/2831288/cars-4T1c8aZiOWDDZ-1N8KxDX49.mp4",
width: 1280,
height: 720,
}
const canvasDescription = {
width: 1280,
height: 720,
}
// scale effect
const scaleDescription = {
title: "AAF Video Scale Effect",
description: "A scale effect based on the AAF spec.",
vertexShader: `
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(vec2(2.0,2.0)*a_position-vec2(1.0, 1.0), 0.0, 1.0);
v_texCoord = a_texCoord;
}`,
fragmentShader: `
precision mediump float;
uniform sampler2D u_image;
uniform float scaleX;
uniform float scaleY;
varying vec2 v_texCoord;
varying float v_progress;
void main(){
vec2 pos = vec2(v_texCoord[0]*1.0/scaleX - (1.0/scaleX/2.0 -0.5), v_texCoord[1]*1.0/scaleY - (1.0/scaleY/2.0 -0.5));
vec4 color = texture2D(u_image, pos);
if (pos[0] < 0.0 || pos[0] > 1.0 || pos[1] < 0.0 || pos[1] > 1.0){
color = vec4(0.0,0.0,0.0,0.0);
}
gl_FragColor = color;
}`,
properties: {
scaleX: { type: "uniform", value: 1.0 },
scaleY: { type: "uniform", value: 1.0 }
},
inputs: ["u_image"]
};
/// position effect
const positionDescription = {
title: "AAF Video Position Effect",
description: "A position effect based on the AAF spec.",
vertexShader: `
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(vec2(2.0,2.0)*a_position-vec2(1.0, 1.0), 0.0, 1.0);
v_texCoord = a_texCoord;
}`,
fragmentShader: `
precision mediump float;
uniform sampler2D u_image;
uniform float positionOffsetX;
uniform float positionOffsetY;
varying vec2 v_texCoord;
varying float v_progress;
void main(){
vec2 pos = vec2(v_texCoord[0] - positionOffsetX/2.0, v_texCoord[1] - positionOffsetY/2.0);
vec4 color = texture2D(u_image, pos);
if (pos[0] < 0.0 || pos[0] > 1.0 || pos[1] < 0.0 || pos[1] > 1.0){
color = vec4(0.0,0.0,0.0,0.0);
}
gl_FragColor = color;
}`,
properties: {
positionOffsetX: { type: "uniform", value: 0.0 },
positionOffsetY: { type: "uniform", value: 0.0 }
},
inputs: ["u_image"]
};
//Setup the video context.
var canvas = document.getElementById("canvas");
var ctx = new VideoContext(canvas);
//Create a video node
var videoNode = ctx.video(exampleMediaFile.url);
videoNode.start(0);
videoNode.stop(10);
/// ------------ SCALE
const scaleEffect = ctx.effect(scaleDescription);
scaleEffect.scaleX = 2 // this is 200% scale
scaleEffect.scaleY = 2 // this is 200% scale
/// ------------ POSITION
const positionEffect = ctx.effect(positionDescription);
positionEffect.positionOffsetX = 0
positionEffect.positionOffsetY = -0.1 // this nudges the position slightly down
videoNode.connect(scaleEffect)
scaleEffect.connect(positionEffect)
positionEffect.connect(ctx.destination);
// you could play it if you wanted
// ctx.play();

Mapbox elevation data precision

I've created a simple three.js app which renders map tiles in 3D. Each tile is a separated mesh (a plane with 10 height and 10 width segments) which uses a THREE.ShaderMaterial. In order to access elevation data I used this Mapbox tileset. Two png tiles (elevation and color) are passed to the simple shader that decodes height value:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D bump;
uniform sampler2D map;
varying float vAmount;
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 bumpData = texture2D( bump, uv );
vAmount = bumpData.x;
float height = (-0.4 + (bumpData.x * 256.0 * 256.0 + bumpData.y * 256.0 + bumpData.z)/1024.0);
vec3 newPosition = position;
newPosition.z = height;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
uniform sampler2D bump;
uniform sampler2D map;
varying vec2 vUv;
varying float vAmount;
void main()
{
if(vAmount == 0.0) {
discard;
}
vec4 tile = texture2D(map, vUv);
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) + tile;
}
</script>
However, it seems like nearby tiles have a bit different height values on edges. I've tried to use THREE.NearestFilter for textures but it didn't have any effect. Is there a way to get rid of these white stripes?

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>

Categories

Resources