Я пытаюсь разработать круговую диаграмму с использованием WebGL. Тем не менее, я получаю некоторые проблемы в разных версиях Chrome. В версии 40.0.2214.111 круговая диаграмма выглядит точно так, как я ожидал, с пятью различными частями.Круговая диаграмма WebGL - Различные результаты в разных версиях Chrome
Но когда я перехожу к версии 43.0.2357.130 цвета на моем втором и четвертом квадранте не совпадают, при этом черные и коричневые цвета меняются синим цветом. Вы можете получить пример here, чтобы проверить его.
Любые идеи, почему это происходит?
Vertex Shader
attribute vec2 aVertexPosition;
varying vec2 vTexCoord;
void main(){
vTexCoord = aVertexPosition;
gl_Position = vec4(aVertexPosition, 0, 1);
}
Фрагмент Shader
precision mediump float;
varying vec2 vTexCoord;
uniform int unumberOfParts;
void main(){
vec4 angles = vec4(100.0, 110.0, 70.0, 30.0);
float prevAngle = radians(0.0);
float radQuad = radians(90.0);
float totalAngles = 0.0;
bool found = false;
bool hasRest = false;
float rad = 0.0;
float AngleToUse = 0.0;
float rest;
if (vTexCoord.y < 0.0 && vTexCoord.x < 0.0){ //Checks the coordinates of each quadrant
for (int i = 0; i<4;i++){
totalAngles = totalAngles + angles[i];
if (totalAngles > 90.0){
rest = totalAngles - 90.0;
AngleToUse = angles[i] - rest;
hasRest = true;
}
else{
AngleToUse = angles[i];
}
rad = radians(AngleToUse);
if ((tan(rad + prevAngle) >= (vTexCoord.y)/(vTexCoord.x)) && (tan(prevAngle) <= (vTexCoord.y)/(vTexCoord.x))){
float color = float(i) * 0.3;
if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
found = true;
}
}
prevAngle = prevAngle + rad;
if (totalAngles > 90.0){
break;
}
}
}
if (vTexCoord.y < 0.0 && vTexCoord.x > 0.0){
for (int i = 0; i<4;i++){
totalAngles = totalAngles + angles[i];
if (totalAngles >= 90.0){
if (totalAngles - angles[i] < 90.0){
AngleToUse = totalAngles - 90.0;
}
else if (totalAngles > 180.0){
rest = totalAngles - 180.0;
AngleToUse = angles[i] - rest;
hasRest = true;
}
else{
AngleToUse = angles[i];
}
rad = radians(AngleToUse);
if ((tan(radQuad - (rad + prevAngle)) <= (vTexCoord.y)/-(vTexCoord.x)) && (tan(radQuad - (prevAngle)) >= (vTexCoord.y)/-(vTexCoord.x))){
float color = float(i) * 0.3;
if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
//gl_FragColor = vec4(1, 0, 0, 1);
gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
found = true;
}
}
prevAngle = prevAngle + rad;
if (totalAngles > 180.0){
break;
}
}
}
}
else if (vTexCoord.y > 0.0 && vTexCoord.x > 0.0){
for (int i = 0; i<4;i++){
totalAngles = totalAngles + angles[i];
if (totalAngles >= 180.0){
if (totalAngles - angles[i] < 180.0){
AngleToUse = totalAngles - 180.0;
}
else if (totalAngles > 270.0){
rest = totalAngles - 270.0;
AngleToUse = angles[i] - rest;
hasRest = true;
}
else{
AngleToUse = angles[i];
}
rad = radians(AngleToUse);
if ((tan(rad + prevAngle) >= (vTexCoord.y)/(vTexCoord.x)) && (tan(prevAngle) <= (vTexCoord.y)/(vTexCoord.x))){
float color = float(i) * 0.3;
if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
//gl_FragColor = vec4(1, 0, 0, 1);
gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
found = true;
}
}
prevAngle = prevAngle + rad;
if (totalAngles > 270.0){
break;
}
}
}
}
else if (vTexCoord.y > 0.0 && vTexCoord.x < 0.0){
for (int i = 0; i<4;i++){
totalAngles = totalAngles + angles[i];
if (totalAngles >= 270.0){
if (totalAngles - angles[i] < 270.0){
AngleToUse = totalAngles - 270.0;
}
else{
AngleToUse = angles[i];
}
rad = radians(AngleToUse);
if ((tan((rad + prevAngle)) >= -(vTexCoord.x)/(vTexCoord.y)) && (tan((prevAngle)) <= -(vTexCoord.x)/(vTexCoord.y))){
float color = float(i) * 0.3;
if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
//gl_FragColor = vec4(1, 0, 0, 1);
gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
found = true;
}
}
prevAngle = prevAngle + rad;
if (totalAngles > 360.0){
break;
}
}
}
}
if (found == false){
if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
gl_FragColor = vec4(0, 0, 1, 1);
}
else{
gl_FragColor = vec4(1, 1, 1, 0);
}
}
}
WebGL
var c = document.getElementById('c');
var gl = c.getContext('experimental-webgl');
var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
var vertices = [-1, -1 , 1, -1, -1, 1 , 1, 1]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
vertexPosBuffer.itemSize = 2;
vertexPosBuffer.numItems = 4;
vertexPosBuffer.numberOfParts = 2;
vs = document.getElementById('vshader').textContent;
fs = document.getElementById('fshader').textContent;
var program = createProgram(vs,fs);
gl.useProgram(program);
program.vertexPosAttrib = gl.getAttribLocation(program,'aVertexPosition');
program.numberOfParts = gl.getUniformLocation(program,'anumberOfParts');
gl.enableVertexAttribArray(program.vertexPosArray);
gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize , gl.FLOAT, false , 0, 0);
gl.uniform1i(program.numberOfParts, vertexPosBuffer.numberOfParts);
gl.finish();
gl.drawArrays(gl.TRIANGLE_STRIP, 0 , vertexPosBuffer.numItems);
Это не столько ответ, сколько общий совет. Прежде всего, ваш шейдер настолько сумасшедший. С шейдером с таким количеством ветвей, это, вероятно, не намного эффективнее, чем это делается на процессоре. Во-вторых, с таким сложным шейдером будет очень сложно отлаживать. Попробуйте написать тот же алгоритм на стороне процессора и посмотреть, работает ли он правильно. В-третьих, для такого простого вывода вы могли бы достичь той же картины с лучшей производительностью, просто используя простой 2D-холст-рисунок (если только изучение OpenGL не является вашей целью в этом проекте). – aeskreis
@aeskreis моя цель заключается в создании круговой диаграммы, которая будет размещена в месте расположения графика компоновки силы с до 10.000 узлов. Я попытался использовать D3 и другие библиотеки, но объем данных был большим, чтобы иметь динамический граф. Вот почему я использую WebGL. Я ничего не знаю о OpenGL, но я ничего не нашел о создании двумерных круговых диаграмм, поэтому я попытался создать свою. Любые идеи о том, как я могу упростить свой шейдер? –
Одним из способов, который я мог бы придумать, чтобы оптимизировать это, было бы рисовать круговую диаграмму с каждым разделом, представленным в виде треугольника, с целью создания «квадратной» диаграммы. У вас будет координата положения, цвета и текстуры как ваши данные на вершину. Затем вы можете приложить альфа-маску, которая даст вам круговую форму, которую вы хотели. Это также даст вам некоторое базовое сглаживание (если ваша альфа-маска сглажена, это простая функция фотошопа или тому подобное).Я могу оставить ответ с более подробной информацией, если вы хотите. – aeskreis