Используемая вами библиотека не всегда имеет значения по умолчанию undefined
. Установка normalized
в true
по некоторому пути для типов массивов Uint8Array
и Int8Array
.
Нормализация данных буфера атрибута
Аргумент нормализации, если true
in WebGLRenderingContext.vertexAttribPointer
нормализует целое число в диапазоне единиц измерения. Для подписанных от -1 до 1 и для беззнаковых от 0 до 1.
В результате атрибут color
устанавливается на 1 / 255
, когда вы используете массив типа Uint8Array
и don t define the value of
normalized`
В вершинном шейдере вы можете уменьшить значение до 1.
Пример вершинного шейдера
attribute float color;
//... code
varying vec4 colorOut;
void main() {
// ... code
colorOut = vec4(0, color * 255.0, 0, 1); // scale the color by 255
}
Пример
Показано, как изменяется normalized
данные атрибута. Красный не нормализован, а зеленый. Обратите внимание, что здесь не используется никакая библиотека.
const GL_OPTIONS = {alpha: false, depth: false, premultpliedAlpha: false, preserveDrawingBufer: true};
const CELL_SIZE = 10, GRID_SIZE = 32, GRID_PX_WIDTH = GRID_SIZE * CELL_SIZE, CELLS = GRID_SIZE ** 2;
const GL_SETUP = {
get context() { return canvas.getContext("webgl", GL_OPTIONS) },
get locations() { return ["A_pos", "A_green", "A_red", "U_res"] },
get vertex() { return `
attribute vec2 pos;
attribute float green;
attribute float red;
uniform vec2 res;
varying vec4 colorV;
void main() {
gl_PointSize = ${(CELL_SIZE - 2).toFixed(1)};
gl_Position = vec4(pos / res, 0, 1);
colorV = vec4(red, green * 255.0, 0, 1);
}`;
},
get fragment() { return `
precision highp float;
varying vec4 colorV;
void main() {
gl_FragColor = colorV;
}`;
},
get buffers() {
return {
pos: { buffer: GL_SETUP.grid },
red: { size: 1, type: gl.UNSIGNED_BYTE, normalize: false, buffer: GL_SETUP.colorsRed },
green: { size: 1, type: gl.UNSIGNED_BYTE, normalize: true, buffer: GL_SETUP.colorsGreen }
};
},
get grid() {
var i = CELLS, buf = new Float32Array(i * 2), idx;
while (i--) {
idx = i << 1;
buf[idx++] = (i % GRID_SIZE) * CELL_SIZE - GRID_PX_WIDTH / 2;
buf[idx] = (i / GRID_SIZE | 0) * CELL_SIZE - GRID_PX_WIDTH / 2;
}
return buf;
},
get colorsRed() {
var i = CELLS, buf = new Uint8Array(i);
while(i--) { buf[i] = Math.random() < 0.5 && i < CELLS / 2 ? 1 : 0 }
return buf;
},
get colorsGreen() {
var i = CELLS, buf = new Uint8Array(i);
while(i--) { buf[i] = Math.random() < 0.5 && i >= CELLS / 2 ? 1 : 0 }
return buf;
},
};
const gl = GL_SETUP.context;
const shader = initShader(gl, GL_SETUP);
const W = canvas.width = innerWidth, H = canvas.height = innerHeight;
gl.viewport(0, 0, W, H);
gl.uniform2fv(shader.locations.res, new Float32Array([W / 2 , -H / 2]));
gl.drawArrays(gl.POINTS, 0, CELLS);
function compileAndAttach(gl, program, src, type = gl.VERTEX_SHADER) {
const shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
gl.attachShader(program, shader);
}
function createShader(gl, settings) {
const locations = {}, program = gl.createProgram();
compileAndAttach(gl, program, settings.vertex);
compileAndAttach(gl, program, settings.fragment, gl.FRAGMENT_SHADER);
gl.linkProgram(program);
gl.useProgram(program);
for(const desc of settings.locations) {
const [type, name] = desc.split("_");
locations[name] = gl[`get${type==="A" ? "Attrib" : "Uniform"}Location`](program, name);
}
return {program, locations, gl};
}
function initShader(gl, settings) {
const shader = createShader(gl, settings);
for (const [name, data] of Object.entries(settings.buffers)) {
const {use = gl.STATIC_DRAW, type = gl.FLOAT, buffer, size = 2, normalize = false} = data;
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, buffer, use);
gl.enableVertexAttribArray(shader.locations[name]);
gl.vertexAttribPointer(shader.locations[name], size, type, normalize, 0, 0);
}
return shader;
}
body { padding: 0px }
canvas {
position: absolute;
top: 0px;
left: 0px;
}
<canvas id="canvas"></canvas>