Initializing a javascript object containing an array - javascript

I have the following C++ struct which I want to create as faithfully as possible in Javascript:
struct Vertex
{
float coords[4];
float colors[4];
};
So I did the following:
function Vertex(coords, colors)
{
this.coords = [];
this.colors = [];
}
Now, the following works to create a Vertex instance:
var oneVertex = new Vertex();
oneVertex.coords = [20.0, 20.0, 0.0, 1.0];
oneVertex.colors = [0.0, 0.0, 0.0, 1.0];
but the following (slicker?) doesn't:
var oneVertex = new Vertex([20.0, 20.0, 0.0, 1.0],
[0.0, 0.0, 0.0, 1.0]);
Why? I am new to Javascript and what little I have read suggests it should be ok. Obviously not. It would be helpful to understand what I am missing. Thanks.

you need to use the arguments passed in to the function for it to work, as:
function Vertex(coords, colors)
{
this.coords = coords || [];
this.colors = colors || [];
}

You're constructor should initialize the properties:
function Vertex(coords, colors)
{
this.coords = coords;
this.colors = colors;
}
var oneVertex = new Vertex([20.0, 20.0, 0.0, 1.0],
[0.0, 0.0, 0.0, 1.0]);

Related

Draw quad (interleaved) in three.js

I'm trying to draw a quad in three.js, but three.js keeps complaining that 'tex' is not a 'WebGLTexture' and refuse to run, what's going on here? thank you.
// z= depth, tex is texture
function drawQuad(z, tex)
{
var verts = [
-1.0, 1.0, z, 0.0, 1.0,
-1.0, -1.0, z, 0.0, 0.0,
1.0, 1.0, z, 1.0, 1.0,
1.0, -1.0, z, 1.0, 0.0,
];
const gl = renderer.getContext();
gl.disable(gl.DEPTH_TEST);
gl.useProgram(quadShader);
var vb = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 20, 0);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 20, 12);
gl.uniform1i(gl.getUniformLocation(quadShader, 'su_tex'), 0)
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
gl.enable(gl.DEPTH_TEST);
}
tex is loaded like this
wallTex = loader.load("https://r105.threejsfundamentals.org/threejs/resources/images/wall.jpg");
drawQuad(1.0, wallTex);
Ok, i've figured it out.
Anyway, this may help those who are still confused (c++ opengl pragrammers):
WebGlTexture is the id you created with glGenTextures(1, &texturId), it is for rendering.
THREE.js.Texture is a texture container, it contains texture descriptions and image data downloaded from web or whatever, it has a hidden property __webglTexture which is null if this THREE.js.Texture never been used for rendering. then what if it has been used for rendering? it will create a WebGLTexture (via glGenTextures(1, &textureId) internally i guess) and assign this WebGlTexture id to its __webglTexture, and now you can use it for rendering.
It might be more appropriate to call THREE.js.Texture as THREE.js.TextrureRes IMO, less mis-leading.

WebGL requestAnimationFrame is drawing a blank screen

I'm trying to build a small 2d game and right now I'm stuck at a small progress bar. I'm trying to make it so whenever someone goes to the game, a progress bar will be animated by going to the other end. I learned that I should use requestAnimationFrame and change the dimensions of the rectangle, and pass in a function parameter, but when I tried it, it didn't work out. Here is the code:
beta.js
import { setStyle } from "./ui.js";
import * as g from './globals.js';
import Gl from "./gl.js";
import Load from "./load.js";
class Beta {
canvas: HTMLCanvasElement;
gl!: WebGL2RenderingContext;
glHandler!: Gl;
buildVersion!: number;
constructor() {
this.buildVersion = 1.00000;
this.canvas = document.getElementById('betaMain') as HTMLCanvasElement;
this.gl = this.canvas.getContext('webgl2') as WebGL2RenderingContext;
this.glHandler = new Gl(this.gl);
this._setWindowDefaults();
this._setListeners();
this.gl.clearColor(0.1, 0.1, 0.1, 1);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
}
load() {
const load = new Load(this.glHandler);
load.drawLoaderBase();
load.drawLoaderProgress();
}
_resizeCanvas() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
_setWindowDefaults() {
this._resizeCanvas();
g.updateGlobalCenters();
g.updateGlobalDimensions();
setStyle(document.body, 'margin', '0px');
setStyle(document.body, 'padding', '0px');
setStyle(document.body, 'overflow', 'hidden');
}
_setListeners() {
$(window).on('resize', () => {
this._resizeCanvas();
g.updateGlobalCenters();
g.updateGlobalDimensions();
});
}
}
$(window).on('load', () => {
const beta = new Beta();
beta.load();
});
load.js
import Gl from "./gl.js";
class Load {
glHandler: Gl;
gl: WebGL2RenderingContext;
current: number;
max: number;
jump: number;
start: any | undefined;
previousTimeStamp: any | undefined;
constructor(glHandler: Gl) {
this.glHandler = glHandler;
this.gl = glHandler.gl;
this.max = 0.8;
this.current = -0.8;
this.jump = 0.01;
}
drawLoaderBase() {
this.glHandler.drawQuad([
-0.8, 0.01, 0.0,
-0.8, -0.01, 0.0,
0.8, -0.01, 0.0,
0.8, 0.01, 0.0
], [0.15, 0.15, 0.15, 1]);
}
drawLoaderProgress() {
this.glHandler.drawQuad([
-0.8, 0.005, -1.0,
-0.8, -0.005, -1.0,
this.current, -0.005, -1.0,
this.current, 0.005, -1.0
], [0.2, 0.2, 0.2, 1]);
this.current += this.jump
}
}
export default Load;
and gl.js (this is a file I created, hoping it could make reusable gl code).
class Gl {
gl: WebGL2RenderingContext;
constructor(gl: WebGL2RenderingContext) {
this.gl = gl;
if (gl === null) {
alert('Unable to initiate WebGL. Your browser or machine may not suppport it.');
return;
}
}
drawQuad(vertices: Array<number>, color: Array<number>) {
const indices = [3, 2, 1, 3, 1, 0];
const vertextShaderSource = `
attribute vec3 coordinates;
void main(void) {
gl_Position = vec4(coordinates, 1.0);
}
`;
const fragmentShaderSource = `
void main(void) {
gl_FragColor = vec4(0.3, 0.3, 0.3, 1);
}
`;
const vertexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
const indexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this.gl.STATIC_DRAW);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);
const vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER)!;
this.gl.shaderSource(vertexShader, vertextShaderSource);
this.gl.compileShader(vertexShader);
const fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER)!;
this.gl.shaderSource(fragmentShader, fragmentShaderSource);
this.gl.compileShader(fragmentShader);
const shaderProgram = this.gl.createProgram()!;
this.gl.attachShader(shaderProgram, vertexShader);
this.gl.attachShader(shaderProgram, fragmentShader);
this.gl.linkProgram(shaderProgram);
this.gl.useProgram(shaderProgram);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBuffer);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const coord = this.gl.getAttribLocation(shaderProgram, 'coordinates');
const drawScene = () => {
this.gl.vertexAttribPointer(coord, 3, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(coord);
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
this.gl.drawElements(this.gl.TRIANGLES, indices.length, this.gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(drawScene);
}
drawScene();
}
get glContext() {
return this.gl;
}
}
export default Gl;
Sorry that there are many lines of code that are not related. The many parts I think are important is the drawQuad function. I have tried to wrap some parts of the function in a drawscene method, and call request animation frame in there, but that didn't work. I also searched online and it said do not use setInterval. I would like to have a way to make the rectangle animate by resizing it's width.
Thanks.

Dynamic WebGL Draw in Game Loop

I am fairly new to WebGL and I am working on a 3D game that dynamically generates land around the player. So, I am trying to add vertices to draw in game. Things worked fine, until I started to add this feature, making hundreds of gl.drawArrays() calls per frame, which made it super laggy. After having done some research I found that a better way to approach this is to make a huge array containing all of the vertices (each shape separated by degenerate triangles) and then make one gl.drawArray() call per frame.
Here is the part of my code that runs on load:
function loadGraphics() {
// ground
// buffers
quadVertexPositionBuffer = gl.createBuffer();
vertices = [];
verticesItemCount = 0;
quadVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadVertexColorBuffer);
var colors = [
0.0, 0.4, 0.0, 1.0,
0.0, 0.4, 0.0, 1.0,
0.0, 0.4, 0.0, 1.0,
0.0, 0.4, 0.0, 1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.DYNAMIC_DRAW);
quadVertexColorBuffer.itemSize = 4;
quadVertexColorBuffer.numItems = 4;
}
Here is the part that runs per frame:
function drawGraphics() {
// draw code for graphics
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clearColor(0.35, 0.4, 1.0, 1.0 );
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
// perspective
var cameraX = camera.x, cameraY = camera.y, cameraZ = camera.z;
mat4.rotate(mvMatrix, rotMatrix[1], [1, 0, 0]);
mat4.rotate(mvMatrix, rotMatrix[0], [0, 1, 0]);
mat4.translate(mvMatrix, [-cameraX/33, -cameraY/33, -cameraZ/33]);
debug.add("{camera} x:"+camera.x+",y:"+camera.y+",z:"+camera.z+";");
debug.add("\n{mouse delta} x:"+mouse.x-mouse.prevX+",y:"+mouse.y-mouse.prevY+";");
debug.add("\n{rm}[0]:"+rotMatrix[0]+",[1]:"+rotMatrix[1]);
// ground
gl.bindBuffer(gl.ARRAY_BUFFER, quadVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, quadVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
// land plots
vertices = [];
verticesItemCount = 0;
for (var i = 0; i < landPlots.length; i++) {
var oX = landPlots[i].x*3;
var oZ = landPlots[i].z*3;
var plotVertices = [
-1.5+oX, 0.0, 1.5+oZ, 1.0,
1.5+oX, 0.0, 1.5+oZ, 1.0,
-1.5+oX, 0.0, -1.5+oZ, 1.0,
1.5+oX, 0.0, -1.5+oZ, 1.0
];
pushDrawArray(plotVertices, 4);
for(var j = 1; j <= 2; j++) {
debug.add(" " + renderLandPlotIntersection(landPlots[i], j));
}
}
gl.bindBuffer(gl.ARRAY_BUFFER, quadVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 4, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, verticesItemCount);
}
function renderLandPlotIntersection(landPlot, side) {
var x = landPlot.x;
var z = landPlot.z;
var lvl = landPlot.level;
var olvl = null;
var plot;
switch (side) {
case 0: plot =getLandPlot(x-1, z ); if (plot !== null) olvl = plot.level/66; else return 0; break;
case 1: plot =getLandPlot(x, z+1); if (plot !== null) olvl = plot.level/66; else return 0; break;
case 2: plot =getLandPlot(x+1, z ); if (plot !== null) olvl = plot.level/66; else return 0; break;
case 3: plot =getLandPlot(x, z-1); if (plot !== null) olvl = plot.level/66; else return 0; break;
default: throw "Land plot intersection drawing: side out of range."; return -1;
}
var intersectionVertices = [
x*3, lvl, z*3,
x*3, lvl, z*3,
x*3, olvl, z*3,
x*3, olvl, z*3
];
pushDrawArray(intersectionVertices, 4);
return +1;
}
function pushDrawArray(array, itemCount) {
if (vertices.length > 0) {
// degenerate
vertices.push(vertices[vertices.length-3]);
vertices.push(vertices[vertices.length-2]);
vertices.push(vertices[vertices.length-1]);
vertices.push(array[0]);
vertices.push(array[1]);
vertices.push(array[2]);
verticesItemCount += 2 ;
}
gl.bufferSubData(gl.ARRAY_BUFFER, verticesItemCount*4, array);
verticesItemCount += itemCount;
}
I started using DYNAMIC_DRAW, though I don't really know how to use it. verticesItemCount marks how many vertices are in the vertices array.
gl.drawArrays() returns this error:
[.Offscreen-For-WebGL-060B7ED8]GL ERROR :GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1 localhost/:1 WebGL: too many errors, no more errors will be reported to the console for this context.
How can I fix this code to not cause an error?
I know what I did. I made the vertex position array longer than my vertex color array, so it was trying to access something out of bounds. The fix is to keep the vertex color array the same length as the vertex position array.

glmatrix.js anomaly - changing order of transforms does not change outcome

In creating a webgl "hello world" for demonstration to a high school class, I am experiencing an anomalous result.
Using gl-matrix.js version 2.2.0, reversing the order of two transforms does not produce a difference in output.
This code produces the desired result:
function DrawScene(gl) {
var time_now = new Date();
var elapsed_time = new Date();
elapsed_time.setDate(time_program_started - time_now);
var projection_matrix = mat4.create();
var modelview_matrix = mat4.create();
var mvp = mat4.create();
gl.viewport(0, 0, gl.size[0], gl.size[1]);
gl.clearColor(0.2, 0.2, 0.2, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
mat4.perspective(projection_matrix, D2R(50.0), gl.size[0] / gl.size[1], 1.0, 10.0);
mat4.translate(modelview_matrix, modelview_matrix, [0.0, 0.0, -3.5]);
mat4.rotate(modelview_matrix, modelview_matrix, D2R(elapsed_time / 1000.0 * 60.0), [0.0, 1.0, 0.0]);
mat4.multiply(mvp, projection_matrix, modelview_matrix);
triangle.Render(gl, shader_index, [1.0, 1.0, 1.0, 1.0], mvp);
}
namely a triangle that spins in place about its Y axis.
Reversing the order of the translate and rotate should spin the triangle around the camera (part of my intended lesson), but instead continues to spin the triangle in place. I sanity checked this in an equivalent legacy OpenGL "hello world" producing exactly the expected results.
The vertex shader simply multiples the vertex position attribute with the mvp uniform. Is there a problem in gl-matrix.js or in this code?
For completeness, here is the render function.
Triangle.prototype.Render = function (gl, shader_index, color, mvp) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertex_buffer_object);
gl.vertexAttribPointer(shaders[shader_index].VP, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaders[shader_index].VP);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.element_buffer_object);
shaders[shader_index].Use(gl);
gl.uniformMatrix4fv(shaders[shader_index].MVP, false, mvp);
if (shader_index == 0)
gl.uniform4fv(shaders[shader_index].COLOR, color);
else {
gl.bindBuffer(gl.ARRAY_BUFFER, this.color_buffer_object);
gl.vertexAttribPointer(shaders[shader_index].COLOR, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaders[shader_index].COLOR);
}
gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);
shaders[shader_index].StopUsing(gl);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
Thank you.
I believe there is an error in my use of gl-matrix or gl-matrix itself. Replacing gl-matrix with mjs.js works as expacted.
function DrawScene(gl) {
var time_now = new Date();
var elapsed_time = new Date();
elapsed_time.setDate(time_program_started - time_now);
var projection_matrix = M4x4.I;
var modelview_matrix = M4x4.I;
var mvp = M4x4.I;
gl.viewport(0, 0, gl.size[0], gl.size[1]);
gl.clearColor(0.2, 0.2, 0.2, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
projection_matrix = M4x4.makePerspective(50.0, gl.size[0] / gl.size[1], 1.0, 10.0);
modelview_matrix = M4x4.rotate(D2R(elapsed_time / 1000.0 * 60.0), [0.0, 1.0, 0.0], modelview_matrix);
modelview_matrix = M4x4.translate([0.0, 0.0, -5.5], modelview_matrix);
mvp = M4x4.mul(projection_matrix, modelview_matrix);
triangle.Render(gl, shader_index, [1.0, 1.0, 1.0, 1.0], mvp);
}
Does indeed rotate about the camera. Reversing to translate then rotate spins about the Y axis of the triangle.
I would be very pleased to have my code for gl-matrix corrected. If it cannot, gl-matrix is very broken.

Click to zoom in WebGL

I need to implement what amounts to a "Google Maps" style zoom effect in WebGL. Specifically I have a simple 2-dimensional scene that is always perpendicular to the camera. When a user clicks on the scene, the camera should zoom to a location that is over the click, but closer to the 2-dimensional scene.
For example see this jsfiddle, that implements the scene but no zooming:
http://jsfiddle.net/JqBs8/4/
If you have a WebGL enabled browser, you should see a triangle and a square (2-dimensional) rendered at -7 on the Z axis. I have put in a placeholder handleMouseUp() event handler that logs any click events, but I'm a little lost as to how to translate the coordinates given by the click event into a new location for the camera (or I guess equivalently a new view matrix).
(The jsfiddle is based on tutorial 1 from learningwebgl.com and uses the glMatrix http://code.google.com/p/glmatrix/ library for matrix operations. Keep in mind that this is WebGL, which is similar to OpenGL ES, and has no access to glu* functions.)
I've written something in this jsfiddle that should help you.
http://jsfiddle.net/hedzys6r/
(or https://codepen.io/brainjam/pen/gBZyGm)
Just click on the WebGL window to zoom in to where the mouse is pointing.
The basic idea is that a point in the WebGL window is obtained by projecting it from 3-space using the projection matrix pMatrix and the view matrix (the view matrix depends on where the camera is and the direction in which it is looking). The composition of these matrices is named pvMatrix in the code.
If you want the opposite transform from the window back to three space, you have to take a clip space coordinate (x,y,z) and 'unproject' it back into 3D using the inverse of pvMatrix. In clip space, coordinates are in the range [-1,1], and the z coordinate is depth.
In the OpenGL world, these transforms are implemented in gluProject() and gluUnproject() (which you can Google for more information and source code).
In the jsfiddle example, we calculate the (x,y) coordinates in clip space, and then unproject (x,y,z) for two different values of z. From that we get two points in 3D space that map onto (x,y), and we can infer a direction vector. We can then move the camera in that direction to get a zoom effect.
In the code, the camera position is at the negation of the eye vector.
This example shows you how to move the camera in the direction that you are clicking. If you want to actually move towards specific objects in the scene, you have to implement something like object selection, which is a different kettle of fish. The example I've given is unaware of the objects in the scene.
This is really part of brainjam's answer, but just in case that jsfiddle were to go away, I wanted to make sure the code was archived. Here is the primary bit:
function handleMouseUp(event) {
var world1 = [0,0,0,0] ;
var world2 = [0,0,0,0] ;
var dir = [0,0,0] ;
var w = event.srcElement.clientWidth ;
var h = event.srcElement.clientHeight ;
// calculate x,y clip space coordinates
var x = (event.offsetX-w/2)/(w/2) ;
var y = -(event.offsetY-h/2)/(h/2) ;
mat4.inverse(pvMatrix, pvMatrixInverse) ;
// convert clip space coordinates into world space
mat4.multiplyVec4(pvMatrixInverse, [x,y,-1,1], world1) ;
vec3.scale(world1,1/world1[3]) ;
mat4.multiplyVec4(pvMatrixInverse, [x,y,0,1], world2) ;
vec3.scale(world2,1/world2[3]) ;
// calculate world space view vector
vec3.subtract(world2,world1,dir) ;
vec3.normalize(dir) ;
vec3.scale(dir,0.3) ;
// move eye in direction of world space view vector
vec3.subtract(eye,dir) ;
drawScene();
console.log(event)
}
And the entirety of the JS...
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
var mvMatrix = mat4.create();
var pMatrix = mat4.create();
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
var triangleVertexPositionBuffer;
var squareVertexPositionBuffer;
function initBuffers() {
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
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
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.numItems = 4;
}
var eye = vec3.create([0,0,0]) ; // negation of actual eye position
var pvMatrix = mat4.create();
var pvMatrixInverse = mat4.create();
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
// calculate the view transform mvMatrix, and the projection-view matrix pvMatrix
mat4.translate(mvMatrix, eye);
mat4.multiply(pMatrix,mvMatrix,pvMatrix) ;
mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
}
function handleMouseUp(event) {
var world1 = [0,0,0,0] ;
var world2 = [0,0,0,0] ;
var dir = [0,0,0] ;
var w = event.srcElement.clientWidth ;
var h = event.srcElement.clientHeight ;
// calculate x,y clip space coordinates
var x = (event.offsetX-w/2)/(w/2) ;
var y = -(event.offsetY-h/2)/(h/2) ;
mat4.inverse(pvMatrix, pvMatrixInverse) ;
// convert clip space coordinates into world space
mat4.multiplyVec4(pvMatrixInverse, [x,y,-1,1], world1) ;
vec3.scale(world1,1/world1[3]) ;
mat4.multiplyVec4(pvMatrixInverse, [x,y,0,1], world2) ;
vec3.scale(world2,1/world2[3]) ;
// calculate world space view vector
vec3.subtract(world2,world1,dir) ;
vec3.normalize(dir) ;
vec3.scale(dir,0.3) ;
// move eye in direction of world space view vector
vec3.subtract(eye,dir) ;
drawScene();
console.log(event)
}
function webGLStart() {
var canvas = document.getElementById("lesson01-canvas");
initGL(canvas);
initShaders();
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
canvas.onmouseup = handleMouseUp;
drawScene();
}
webGLStart();

Categories

Resources