#glsl #webgl
#glsl #webgl
Вопрос:
Я пытаюсь взять шаблон шума, который состоит из черного и белого (и серого, где между ними плавный переход), и я пытаюсь сопоставить его с двумя разными цветами, но мне трудно понять, как это сделать.
Я могу легко заменить белый или черный на простой оператор if, но градиентные области, где смешано белое и черное, по-прежнему представляют собой смесь белого и черного, что имеет смысл. Итак, мне нужно на самом деле сопоставить цвета с новыми цветами, но я понятия не имею, как я должен это делать.
Комментарии:
1. Просто используйте
mix
(color0,color1,noise)
Ответ №1:
Есть простые способы
- Негибкий способ, используйте
mix
gl_FragColor = mix(color0, color1, noise)
- Более гибкий способ — использовать рамповую текстуру
float u = (noise * (rampTextureWidth - 1.0) 0.5) / rampTextureWidth; gl_FragColor = texture2D(rampTexture, vec2(u, 0.5));
Использование текстур рампы обрабатывает любое количество цветов, в то время как as mix обрабатывает только 2.
const vs = `
attribute vec4 position;
attribute float noise;
uniform mat4 u_matrix;
varying float v_noise;
void main() {
gl_Position = u_matrix * position;
v_noise = noise;
}
`;
const fs = `
precision highp float;
varying float v_noise;
uniform sampler2D rampTexture;
uniform float rampTextureWidth;
void main() {
float u = (v_noise * (rampTextureWidth - 1.0) 0.5) / rampTextureWidth;
gl_FragColor = texture2D(rampTexture, vec2(u, 0.5));
}
`;
"use strict";
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
// compiles shaders, links program, looks up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
/*
6------7
/| /|
/ | / |
2------3 |
| | | |
| 4---|--5
| / | /
|/ |/
0------1
*/
const arrays = {
position: [
-1, -1, -1,
1, -1, -1,
-1, 1, -1,
1, 1, -1,
-1, -1, 1,
1, -1, 1,
-1, 1, 1,
1, 1, 1,
],
noise: {
numComponents: 1,
data: [
1, 0.5, 0.2, 0.3, 0.9, 0.1, 0.7, 1,
],
},
indices: [
0, 2, 1, 1, 2, 3,
1, 3, 5, 5, 3, 7,
5, 7, 4, 4, 7, 6,
4, 6, 0, 0, 6, 2,
2, 6, 3, 6, 7, 3,
0, 1, 4, 4, 1, 5,
],
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const red = [255, 0, 0, 255];
const yellow = [255, 255, 0, 255];
const blue = [ 0, 0, 255, 255];
const green = [ 0, 255, 0, 255];
const cyan = [ 0, 255, 255, 255];
const magenta = [255, 0, 255, 255];
function makeTexture(gl, name, colors) {
const width = colors.length / 4;
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
width, 1, 0,
gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array(colors));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
return {
name,
texture,
width,
};
}
const textures = [
makeTexture(gl, 'one color',
[...red]),
makeTexture(gl, 'two colors',
[...red, ...yellow]),
makeTexture(gl, 'three colors',
[...blue, ...red, ...yellow]),
makeTexture(gl, 'six colors',
[...green, ...red, ...blue, ...yellow, ...cyan, ...magenta]),
];
const infoElem = document.querySelector('#info');
function render(time) {
time *= 0.001;
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
// draw cube
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 40;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const eye = [1, 4, -7];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
const world = m4.rotationY(time);
gl.useProgram(programInfo.program);
const tex = textures[time / 2 % textures.length | 0];
infoElem.textContent = tex.name;
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.uniformXXX, gl.activeTexture, gl.bindTexture
twgl.setUniformsAndBindTextures(programInfo, {
u_matrix: m4.multiply(viewProjection, world),
rampTexture: tex.texture,
rampTextureWidth: tex.width,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
<div id="info"></div>