У меня есть несколько точек в двухмерных координатах, и у каждой точки есть оценка. Я хочу нарисовать точки на шейдере, и цвет точек должен быть красным, но вес должен быть основан на счете.
Это должно выглядеть следующим образом, например, верхний левый балл равен 0,8, верхний правый и нижний левый балл равен 0,9, а нижний правый балл равен 0,7.
(Приношу извинения за то, что не смог вставить некоторые изображения сюда. Это мой первый вопрос, и у меня не хватает репутации....)
https://jsfiddle.net/p19uc825/
Формула, которую я сейчас имею, рассчитывает расстояние между центром и 2-й координатой для каждой точки. Ниже приведен метод, который я использую, чтобы получить цвет для каждой позиции.
Мои координаты:
const coordinates = [
0.2,0.8,
0.2,0.2,
0.8,0.8,
0.8,0.2,
];
Счет:
const scores = [
0.8,0.9,0.9,0.7
];
Часть фрагмента шейдерного источника:
vec3 get_pos_color(in vec2 st, in vec2 normalizedPosition, in float score)
{
float mult = 1.4;
float pct = 0.0;
pct = (
distance(
vec3(normalizedPosition.x, normalizedPosition.y, score),
vec3(st.x,st.y,score)
) * mult - score);
vec3 color = vec3(pct, pct, pct) + vec3(1,1,1);
return color;
}
Это работает с 4 координатами, как показано выше в jsfiddle.
Однако, если я добавлю еще одну точку с координатой [0.8,0.5] и присвоу ей 0,1 балла, это будет выглядеть так -
https://jsfiddle.net/nqy3az1b/
кажется, что новая точка имеет больший вес, чем эти две 0,9 точки, в то время как у нее должен быть очень светлый цвет, поскольку у этой новой точки самый низкий балл. Я думаю, что для этого есть две причины - 1. Когда шейдер интерполирует эту новую точку, она учитывает 2 близкие к ней точки, верхнюю правую и нижнюю правую. 2. Новая точка может быть добавлена с большим весом, потому что она находится ближе всего к центру, потому что в коде фрагмента шейдера выше, я вычисляю расстояние между точкой и центром.
Чего я действительно хочу добиться, так это того, чтобы вес цвета для каждой точки определялся только оценкой, независимо от ее положения.
Я знаю, что расстояние() в источнике фрагмента не является правильной формулой, используемой для интерполяции пикселей, поэтому любые предложения по поводу того, что я могу попробовать, будут с благодарностью.
Я рекомендую рассчитать минимальное расстояние до точки, где "сокр" взвешивает обратное расстояние (1/х):
float min_pct = 100.0; // any large value
for(int i=0;i<6;i++){
float sco = uScores[i];
vec2 pos = uPositions[i];
float mult = 2.5;
float pct = distance(st.xy, pos.xy) * mult / sco;
min_pct = min(min_pct, pct);
}
Используйте mix
чтобы интерполировать между 2 цветами в соответствии с окончательным весом
vec3 color1 = vec3(1.0);
vec3 color2 = vec3(1.0, 0.0, 0.0);
result = mix(color1, color2, 1.0-min_pct);
Посмотрите пример, где я применил предложения к вашему исходному коду:
let glCanvas;
let glContext;
let shaderProgram = {};
let verticesBuffer;
function initialize() {
// Get WebGL context,
glCanvas = document.getElementById("glCanvas");
glContext = glCanvas.getContext("webgl") || glCanvas.getContext("experimental-webgl");
if (!glContext) {
alert("Failed to acquire a WebGL context. Sorry!");
return false;
}
// Initialize shaders, buffers and state,
if (!initializeShaderProgram()) {
delete glContext;
return false;
}
initializeBuffers();
initializeState();
return true;
}
function initializeShaderProgram() {
var vertexShaderCode =
"attribute vec3 vertexPosition;\n" +
"varying vec4 vertexColor;\n" +
"\n" +
"void main(void) {\n" +
" gl_Position = vec4(vertexPosition, 1.0);\n" +
"}\n";
var fragmentShaderCode =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"uniform mediump float time;\n" +
"uniform vec2 u_resolution;\n" +
"uniform vec2 uPositions[5];\n" +
"uniform float uScores[5];\n" +
"varying lowp vec4 vertexColor;\n" +
"\n" +
'
vec3 rgba2rgb(in vec3 RGB_background, in vec4 RGBA_color){
float alpha = RGBA_color.a;
vec3 res = vec3(
(1.0 - alpha) * RGB_background.r + alpha * RGBA_color.r,
(1.0 - alpha) * RGB_background.g + alpha * RGBA_color.g,
(1.0 - alpha) * RGB_background.b + alpha * RGBA_color.b);
return res;
}
void main(void) {
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 result = vec3(1,1,1);
float min_pct = 100.0; // any large value
for(int i=0;i<6;i++){
float sco = uScores[i];
vec2 pos = uPositions[i];
float mult = 2.5;
float pct = distance(st.xy, pos.xy) * mult / sco;
min_pct = min(min_pct, pct);
}
vec3 color1 = vec3(1.0);
vec3 color2 = vec3(1.0, 0.0, 0.0);
result = mix(color1, color2, 1.0-min_pct);
result = result + vec3(1,0,0);
gl_FragColor = vec4(result, 1.0);
}
';
// Create shaders,
var vertexShader = createShader( vertexShaderCode, glContext. VERTEX_SHADER);
var fragmentShader = createShader(fragmentShaderCode, glContext.FRAGMENT_SHADER);
if ((!vertexShader) || (!fragmentShader)) return false;
// Create shader program,
shaderProgram.program = glContext.createProgram();
glContext.attachShader(shaderProgram.program, vertexShader);
glContext.attachShader(shaderProgram.program, fragmentShader);
glContext.linkProgram(shaderProgram.program);
// Check the shader program creation status,
if (!glContext.getProgramParameter(shaderProgram.program, glContext.LINK_STATUS)) {
alert("Unable to initialize the shader program.");
return false;
}
// Get attributes' and uniforms' locations,
shaderProgram.attributes = {};
shaderProgram.attributes.vertexPosition = glContext.getAttribLocation(
shaderProgram.program, "vertexPosition");
shaderProgram.uniforms = {};
shaderProgram.uniforms.time = glContext.getUniformLocation(shaderProgram.program, "time");
shaderProgram.uniforms.positions = glContext.getUniformLocation(shaderProgram.program, "uPositions");
shaderProgram.uniforms.scores = glContext.getUniformLocation(shaderProgram.program, "uScores");
return true;
}
function createShader(shaderCode, shaderType) {
var shader = glContext.createShader(shaderType);
glContext.shaderSource(shader, shaderCode);
glContext.compileShader(shader);
if (!glContext.getShaderParameter(shader, glContext.COMPILE_STATUS)) {
alert("Errors occurred while compiling the shader:\n" + glContext.getShaderInfoLog(shader));
return null;
}
return shader;
}
function initializeBuffers() {
var vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
verticesBuffer = glContext.createBuffer();
glContext.bindBuffer(glContext.ARRAY_BUFFER, verticesBuffer);
glContext.bufferData(glContext.ARRAY_BUFFER, new Float32Array(vertices), glContext.STATIC_DRAW);
}
function initializeState() {
// Set the current shader in use,
glContext.useProgram(shaderProgram.program);
//tell the shader the resolution of the canvas (hard coded to 128 for simplicity)
glContext.uniform2f(glContext.getUniformLocation(shaderProgram.program, "u_resolution"),
document.getElementById("glCanvas").width,
document.getElementById("glCanvas").height
);
// Set the vertices buffer (I know it already bound, but that where it normally
// belongs in the workflow),
glContext.bindBuffer(glContext.ARRAY_BUFFER, verticesBuffer);
// Set where the vertexPosition attribute gets its data,
glContext.vertexAttribPointer(shaderProgram.attributes.vertexPosition, 3, glContext.FLOAT, false, 0, 0);
// Enable attributes used in shader,
glContext.enableVertexAttribArray(shaderProgram.attributes.vertexPosition);
// Set clear color to black,
glContext.clearColor(0.0, 0.0, 0.0, 1.0);
// Set the scores
const scores = [
0.8,0.9,0.9,0.7,0.1
/* 0.7,0.7,0.7,0.7 */
];
glContext.uniform1fv(shaderProgram.uniforms.scores, scores);
// Set the coordinates
const coordinates = [
0.2,0.8,
0.2,0.2,
0.8,0.8,
0.8,0.2,
0.8,0.5
];
glContext.uniform2fv(shaderProgram.uniforms.positions, coordinates);
}
function start() {
// Start the drawing loop,
drawScene();
}
function drawScene() {
// Clear the color buffer,
glContext.clear(glContext.COLOR_BUFFER_BIT);
// The revered draw call!
glContext.drawArrays(glContext.TRIANGLE_STRIP, 0, 4);
// Request drawing again next frame,
window.requestAnimationFrame(drawScene);
}
// Initialize everything,
if (initialize()) {
// Start drawing,
start();
}
html, body { height: 100%; width: 100%; }
.container { width: 100%; height: 100%; position: relative; }
canvas { position: absolute; width: 100%; height: 100%; background: #000; opacity: 1; z-index: 1000000; pointer-events:none; }
#map_div { position: absolute; width: 100%; height: 100%; }
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3&sensor=false"></script>
<div class="container">
<canvas id="glCanvas">
</canvas>
<div id="map_div"></div>
</div>