NeuralCortex
NeuralCortex

Reputation: 47

Problems by coloring WebGL 3D Object

I'm trying to implement a WebGL app according to the documentation in the Mozilla Docs.

My code generates a sphere with is shaped by a scalefactor. The colors are generated according to the scalefactor. The shape is ok, but the colors are wrong. So what is going wrong - I have no clue. This code works on Android and in Java. I'm using the latest Chrome browser.

Here is the code:

export function createHcm3dObject(gl, diagram3D, deltaTheta, deltaPhi) {

let positions = [];
let colors = [];
let alpha = 1.0;

for (let theta = 0; theta < 360; theta += deltaTheta) {
    for (let phi = 0; phi < 180; phi += deltaPhi) {

        //r is scalefactor between 0 and 1 which shapes the sphere
        let r = diagram3D[theta][phi];
        //Color is generated according to the radius (alpha is currently set to 1.0)
        let x1Color = generateColorArray(r, alpha);
        let x1 = r * Math.sin(math3d.toRadians(phi)) * Math.cos(math3d.toRadians(theta));
        let y1 = r * Math.sin(math3d.toRadians(phi)) * Math.sin(math3d.toRadians(theta));
        let z1 = r * Math.cos(math3d.toRadians(phi));

        r = diagram3D[theta + deltaTheta][phi];
        let x2Color = generateColorArray(r, alpha);
        let x2 = r * Math.sin(math3d.toRadians(phi)) * Math.cos(math3d.toRadians(theta + deltaTheta));
        let y2 = r * Math.sin(math3d.toRadians(phi)) * Math.sin(math3d.toRadians(theta + deltaTheta));
        let z2 = r * Math.cos(math3d.toRadians(phi));

        r = diagram3D[theta][phi + deltaPhi];
        let x3Color = generateColorArray(r, alpha);
        let x3 = r * Math.sin(math3d.toRadians(phi + deltaPhi)) * Math.cos(math3d.toRadians(theta));
        let y3 = r * Math.sin(math3d.toRadians(phi + deltaPhi)) * Math.sin(math3d.toRadians(theta));
        let z3 = r * Math.cos(math3d.toRadians(phi + deltaPhi));

        r = diagram3D[theta + deltaTheta][phi + deltaPhi];
        let x4Color = generateColorArray(r, alpha);
        let x4 = r * Math.sin(math3d.toRadians(phi + deltaPhi)) * Math.cos(math3d.toRadians(theta + deltaTheta));
        let y4 = r * Math.sin(math3d.toRadians(phi + deltaPhi)) * Math.sin(math3d.toRadians(theta + deltaTheta));
        let z4 = r * Math.cos(math3d.toRadians(phi + deltaPhi));

        //1. Triangle
        positions.push(x1, y1, z1);
        positions.push(x3, y3, z3);
        positions.push(x4, y4, z4);

        //2. Triangle
        positions.push(x2, y2, z2);
        positions.push(x1, y1, z1);
        positions.push(x4, y4, z4);

        //Colors for 1. Triangle (red,green,blue,alpha=1.0)
        colors.push(x1Color[0], x1Color[1], x1Color[2], x1Color[3]);
        colors.push(x3Color[0], x3Color[1], x3Color[2], x3Color[3]);
        colors.push(x4Color[0], x4Color[1], x4Color[2], x4Color[3]);

        //Colors for 2. Triangle
        colors.push(x2Color[0], x2Color[1], x2Color[2], x2Color[3]);
        colors.push(x1Color[0], x1Color[1], x1Color[2], x1Color[3]);
        colors.push(x4Color[0], x4Color[1], x4Color[2], x4Color[3]);
    }
    //console.log(positions);
    //console.log(colors);
}

// Now pass the list of positions into WebGL to build the
// shape. We do this by creating a Float32Array from the
// JavaScript array, then use it to fill the current buffer.

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

return {
    position: positionBuffer,
    color: colorBuffer,
    positionSize: positions.length,
    deltaTheta,
    deltaPhi
  };
  };

function generateColorArray(r, alpha) {
let colorQuad = [];
let green = Math.abs(Math.sin(2 * r * Math.PI));
let blue = Math.abs(Math.cos(2 * r * Math.PI));
colorQuad[0] = 0.0;
colorQuad[1] = green;
colorQuad[2] = blue;
colorQuad[3] = alpha;
if (r >= 0.5 / 2) {
    let red = Math.abs(Math.cos(2 * r * Math.PI));
    green = Math.abs(Math.sin(2 * r * Math.PI));
    if (r < 0.5) {
        green = 1.0;
    }
    colorQuad[0] = red;
    colorQuad[1] = green;
    colorQuad[2] = 0.0;
    colorQuad[3] = alpha;
}
if (r >= 0.5) {
    let red = Math.abs(Math.cos(2 * r * Math.PI));
    green = Math.abs(Math.cos(2 * r * Math.PI));
    if (r < 0.75) {
        red = 1.0;
    }
    colorQuad[0] = red;
    colorQuad[1] = green;
    colorQuad[2] = 0.0;
    colorQuad[3] = alpha;
}
if (r >= 0.75) {
    let red = 1.0;
    blue = Math.abs(Math.cos(2 * r * Math.PI));
    colorQuad[0] = red;
    colorQuad[1] = 0.0;
    colorQuad[2] = blue;
    colorQuad[3] = alpha;
}
return colorQuad;
}

React Class:

export class Viewer3d extends Component {

state = {
rotX: 0,
rotY: 0,
gl: null,
buffers: null,
programInfo: null,
};

  componentDidMount() {
 this.init();
 }

 init = () => {
console.log("Comp did mount");
const canvas = document.querySelector("#glCanvas");
/** @type {WebGLRenderingContext} */
const gl = canvas.getContext("webgl");
if (!gl) {
  alert(
    "Unable to initialize WebGL. Your browser or machine may not support it."
  );
  return;
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

let vs = document.getElementById("vshader").textContent;
let fs = document.getElementById("fshader").textContent;

//console.log(vs+" "+fs);

const shaderProgram = shader.initShaderProgram(gl, vs, fs);

let diagram3D = [];

let deltaTheta = 10;
let deltaPhi = 10;

for (let theta = 0; theta <= 360; theta += deltaTheta) {
  let phiArray = [];
  for (let phi = 0; phi <= 180; phi += deltaPhi) {
    let eleCorr = 90 - phi;
    let thetaCorr = 360 - theta;
    let out = engine.antenna_correction(
      thetaCorr,
      0,
      eleCorr,
      0,
      "012EA34",
      "012EA34"
    );
    let att = out.a;
    let logarithmic = false;

    if (logarithmic) {
      att = 1.0 - (-20.0 * Math.log10(att)) / 40.0;
    }

    phiArray[phi] = att;
  }
  diagram3D[theta] = phiArray;
}

//console.log(diagram3D);

const buffers = hcm3d.createHcm3dObject(
  gl,
  diagram3D,
  deltaTheta,
  deltaPhi
);

const programInfo = {
  program: shaderProgram,
  attribLocations: {
    vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
    vertexColor: gl.getAttribLocation(shaderProgram,"aVertexColor"),
  },
  uniformLocations: {
    projectionMatrix: gl.getUniformLocation(shaderProgram,"uProjectionMatrix"),
    modelViewMatrix: gl.getUniformLocation(shaderProgram,"uModelViewMatrix"),
  },
};

  this.setState({ gl, buffers, programInfo });
  this.drawScene(gl, programInfo, buffers);
 };

drawScene = (gl, programInfo, buffers) => {
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things

// Clear the canvas before we start drawing on it.

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// Create a perspective matrix, a special matrix that is
// used to simulate the distortion of perspective in a camera.
// Our field of view is 45 degrees, with a width/height
// ratio that matches the display size of the canvas
// and we only want to see objects between 0.1 units
// and 100 units away from the camera.

const fieldOfView = (45 * Math.PI) / 180; // in radians
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.1;
const zFar = 100.0;
const projectionMatrix = mat4.create();

// note: glmatrix.js always has the first argument
// as the destination to receive the result.
mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);

// Set the drawing position to the "identity" point, which is
// the center of the scene.
const modelViewMatrix = mat4.create();

// Now move the drawing position a bit to where we want to
// start drawing the square.

mat4.translate(
  modelViewMatrix, // destination matrix
  modelViewMatrix, // matrix to translate
  [0, 0, -2.5]
);

mat4.rotate(modelViewMatrix, modelViewMatrix, this.state.rotY, [1, 0, 0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, this.state.rotX, [0, 1, 0]);

gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);

gl.vertexAttribPointer(
  programInfo.attribLocations.vertexPosition,
  3,
  gl.FLOAT,
  false,
  0,
  0
);

gl.vertexAttribPointer(
  programInfo.attribLocations.vertexColor,
  4,
  gl.FLOAT,
  false,
  0,
  0
);

gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);

gl.useProgram(programInfo.program);

gl.uniformMatrix4fv(
  programInfo.uniformLocations.projectionMatrix,
  false,
  projectionMatrix
);
gl.uniformMatrix4fv(
  programInfo.uniformLocations.modelViewMatrix,
  false,
  modelViewMatrix
);

gl.drawArrays(gl.TRIANGLES, 0, buffers.positionSize);
};

 onMouseMove = (evt) => {
if (!mouseDown) {
  return;
}

evt.preventDefault();

let deltaX = evt.clientX - mouseX;
let deltaY = evt.clientY - mouseY;
mouseX = evt.clientX;
mouseY = evt.clientY;
this.rotateScene(deltaX, deltaY);
 };

onMouseDown = (evt) => {
evt.preventDefault();

mouseDown = true;
mouseX = evt.clientX;
mouseY = evt.clientY;
};

onMouseUp = (evt) => {
evt.preventDefault();
mouseDown = false;
 };

 rotateScene = (deltaX, deltaY) => {
this.setState({
  rotX: this.state.rotX + deltaX / 100,
  rotY: this.state.rotY + deltaY / 100,
  });
  this.drawScene(this.state.gl, this.state.programInfo, this.state.buffers);
 };

render() {
return (
  <div className="w3-container w3-padding-16">
    <canvas
      id="glCanvas"
      width={1280}
      height={720}
      onMouseMove={this.onMouseMove}
      onMouseDown={this.onMouseDown}
      onMouseUp={this.onMouseUp}
    ></canvas>
  </div>
   );
 }
}

export default Viewer3d;

Fragment Shader:

<script id="fshader" type="x-shader/x-fragment">
  precision mediump float;
  varying vec4 vColor;

  void main(void) {
    gl_FragColor = vColor;
  }
</script>

Vertex Shader:

<script id="vshader" type="x-shader/x-vertex">
  attribute vec4 aVertexPosition;
  attribute vec4 aVertexColor;

  uniform mat4 uModelViewMatrix;
  uniform mat4 uProjectionMatrix;

  varying vec4 vColor;

  void main(void) {
    gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
    vColor = aVertexColor;
  }
</script>

Upvotes: 0

Views: 82

Answers (1)

Nikolay Handzhiyski
Nikolay Handzhiyski

Reputation: 1579

You need to bind one buffer (say the color one), then use vertexAttribPointer to bind the set buffer to the color attribute. Then again, bind the vertex position buffer, and call vertexAttribPointer to bind it the vertex position attribute. Pseudocode:

gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);

gl.vertexAttribPointer(programInfo.attribLocations.vertexColor, ...);

gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);

gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, ...);

Upvotes: 1

Related Questions