viewer/wsquad.js
import * as mat4 from "./glmatrix/mat4.js";
import * as vec3 from "./glmatrix/vec3.js";
/**
* A World-space quadrangle used for rendering a capping polygon for the sectionplane.
*
* @class WSQuad
*/
export class WSQuad {
constructor(viewer, gl) {
// @todo reuse the same program for all WS Quads
this.gl = gl;
this.viewer = viewer;
this.temp = vec3.create();
let vao = this.vao = gl.createVertexArray();
gl.bindVertexArray(vao);
let positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1., +1., -1., -1., +1., -1.,
-1., +1., +1., -1., +1., +1.
]), gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
let vs_source = `#version 300 es
precision highp float;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
layout(location=0) in vec4 vertexPosition;
layout(std140) uniform Placement {
/* vec4 for alignment */
vec4 position;
vec4 axis1;
vec4 axis2;
/* float size; size is in the position.w */
} placement;
out vec3 worldCoords;
void main() {
vec4 floatVertex = vec4(placement.position.xyz +
vertexPosition.x * placement.axis1.xyz * placement.position.w +
vertexPosition.y * placement.axis2.xyz * placement.position.w, 1.);
worldCoords = floatVertex.xyz;
gl_Position = projectionMatrix * viewMatrix * floatVertex;
}`;
let fs_source = `#version 300 es
precision highp float;
uniform vec4 sectionPlane[6];
in vec3 worldCoords;
out vec4 fragColor;
void main() {
for (int i = 0; i < 6; ++i) {
if (dot(worldCoords, sectionPlane[i].xyz) >= sectionPlane[i].w) {
discard;
}
}
fragColor = vec4(0.1, 0.1, 0.1, 1.0);
}`;
let vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vs_source);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(vs));
}
let fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fs_source);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(fs));
}
let p = this.program = gl.createProgram();
gl.attachShader(p, vs);
gl.attachShader(p, fs);
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(p));
}
this.locations = {
placement: gl.getUniformBlockIndex(p, "Placement"),
viewMatrix: gl.getUniformLocation(p, "viewMatrix"),
projectionMatrix: gl.getUniformLocation(p, "projectionMatrix"),
sectionPlane: gl.getUniformLocation(p, "sectionPlane")
};
this.placementData = new Float32Array(12);
}
position(bounds, planeEq) {
const Z = vec3.fromValues(0,0,1);
if (Math.abs(vec3.dot(Z, planeEq)) > 0) {
Z[0] = 1.;
Z[2] = 0.;
}
let l = vec3.len(planeEq);
for (var i = 0; i < 3; ++i) {
this.placementData[i] = planeEq[3] * planeEq[i] / l;
}
let X = this.placementData.subarray(4, 7);
let Y = this.placementData.subarray(8, 11);
let XY = [X, Y];
vec3.cross(X, planeEq, Z);
vec3.normalize(X, X);
vec3.cross(Y, X, planeEq)
vec3.normalize(Y, Y);
let scale = 0.;
let zero_one = [0,1];
for (let i of zero_one) {
for (let j of zero_one) {
for (let k of zero_one) {
let p = vec3.fromValues(bounds[3*i+0], bounds[3*j+1], bounds[3*k+2]);
vec3.subtract(this.temp, p, planeEq);
let d = vec3.dot(planeEq, this.temp);
vec3.scale(this.temp, planeEq, d);
vec3.subtract(this.temp, p, this.temp);
for (let i = 0; i < 2; ++i) {
let d = Math.abs(vec3.dot(this.temp, XY[i]));
if (d > scale) {
scale = d;
}
}
}
}
}
this.placementData[3] = scale;
let gl = this.gl;
this._buffer = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, this._buffer);
gl.bufferData(gl.UNIFORM_BUFFER, this.placementData, gl.DYNAMIC_DRAW);
}
draw() {
if (!this._buffer) {
console.error("quad not initialized yet");
return;
}
let gl = this.gl;
gl.useProgram(this.program);
gl.uniformMatrix4fv(this.locations.projectionMatrix, false, this.viewer.camera.projMatrix);
gl.uniformMatrix4fv(this.locations.viewMatrix, false, this.viewer.camera.viewMatrix);
gl.uniform4fv(this.locations.sectionPlane, this.viewer.sectionPlanes.buffer);
// @todo can we skip uniform buffer and just use 4fv if we make it a vec4[3]?
gl.bindBufferBase(gl.UNIFORM_BUFFER, this.locations.placement, this._buffer);
gl.bindVertexArray(this.vao);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.bindVertexArray(null);
}
}