diff --git a/panorama-viewer.js b/panorama-viewer.js index 787ff7c..e375c06 100644 --- a/panorama-viewer.js +++ b/panorama-viewer.js @@ -13,38 +13,39 @@ // throw "parallels must be ≥ 3"; } - const radius = 1; + const radius = 0.67; - const positions = new Float32Array(meridians * parallels * 3); - let positionsIdx = 0; + // The seam needs two of each vertex so we can map the texture correctly. + const vertices = new Float32Array((meridians + 1) * parallels * 5); + const vertexStride = 5 * vertices.constructor.BYTES_PER_ELEMENT; + const positionOffset = 0; + const textureCoordOffset = 3 * vertices.constructor.BYTES_PER_ELEMENT; + let verticesIdx = 0; for (let p = 0; p < parallels; p++) { const y = p * 2 * radius / (parallels - 1) - radius; - for (let m = 0; m <= meridians; m++) { + for (let m = 0; m < meridians + 1; m++) { const θ = m * 2 * Math.PI / meridians; const x = Math.sin(θ) * radius; const z = Math.cos(θ) * radius; + const u = m / meridians; + const v = p / (parallels - 1); - const currPosition = [ - Math.sin(θ) * radius, - y, - Math.cos(θ) * radius, - ]; - for (const coord of currPosition) { - positions[positionsIdx++] = coord; - } + vertices[verticesIdx++] = x; + vertices[verticesIdx++] = y; + vertices[verticesIdx++] = z; + vertices[verticesIdx++] = u; + vertices[verticesIdx++] = v; } } const indices = new Uint16Array(meridians * (parallels - 1) * 6); - const textureCoords = new Float32Array(meridians * (parallels - 1) * 12); let indicesIdx = 0; - let textureCoordsIdx = 0; for (let p = 0; p < parallels - 1; p++) { for (let m = 0; m < meridians; m++) { - const lowerLeft = p * meridians + m; - const lowerRight = p * meridians + (m + 1) % meridians; - const upperLeft = (p + 1) * meridians + m; - const upperRight = (p + 1) * meridians + (m + 1) % meridians; + const lowerLeft = p * (meridians + 1) + m; + const lowerRight = p * (meridians + 1) + (m + 1); + const upperLeft = (p + 1) * (meridians + 1) + m; + const upperRight = (p + 1) * (meridians + 1) + (m + 1); const currIndices = [ // Lower triangle lowerLeft, lowerRight, upperRight, @@ -55,31 +56,14 @@ for (const index of currIndices) { indices[indicesIdx++] = index; } - - const currTextureCoords = [ - // Lower triangle - m / meridians, p / (parallels - 1), - (m + 1) / meridians, p / (parallels - 1), - (m + 1) / meridians, (p + 1) / (parallels - 1), - - // Upper triangle - m / meridians, p / (parallels - 1), - (m + 1) / meridians, (p + 1) / (parallels - 1), - m / meridians, (p + 1) / (parallels - 1), - ]; - for (const coord of currTextureCoords) { - textureCoords[textureCoordsIdx++] = coord; - } } } return { - positions, textureCoords, indices, - positionStride: 3 * positions.constructor.BYTES_PER_ELEMENT, - textureCoordStride: 2 * textureCoords.constructor.BYTES_PER_ELEMENT, + vertices, indices, + vertexStride, positionOffset, textureCoordOffset, }; } - // console.log(makeCylinder()); const initShaderProgram = (gl) => { const vShaderSrc = ` @@ -194,17 +178,12 @@ viewer.addEventListener("mousemove", runPanState); gl.useProgram(program); - const cylinder = makeCylinder(3, 3); - console.log(cylinder); + const cylinder = makeCylinder(24, 12); - let positionBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - gl.bufferData(gl.ARRAY_BUFFER, cylinder.positions, gl.STATIC_DRAW); + let vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, cylinder.vertices, gl.STATIC_DRAW); const positionLocation = gl.getAttribLocation(program, "position"); - - let textureCoordBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer); - gl.bufferData(gl.ARRAY_BUFFER, cylinder.textureCoords, gl.STATIC_DRAW); const textureCoordLocation = gl.getAttribLocation(program, "textureCoord"); let indexBuffer = gl.createBuffer(); @@ -227,16 +206,14 @@ mat4.rotateY(modelMatrix, modelMatrix, θy); gl.uniformMatrix4fv(modelMatrixLocation, false, modelMatrix); - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.enableVertexAttribArray(positionLocation); - gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer); + gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, cylinder.vertexStride, cylinder.positionOffset); gl.enableVertexAttribArray(textureCoordLocation); - gl.vertexAttribPointer(textureCoordLocation, 2, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(textureCoordLocation, 2, gl.FLOAT, false, cylinder.vertexStride, cylinder.textureCoordOffset); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); - gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0); + gl.drawElements(gl.TRIANGLES, cylinder.indices.length, gl.UNSIGNED_SHORT, 0); requestAnimationFrame(render); };