From 161658f33c62eeea4ba8eaeed89a79cb9da568c5 Mon Sep 17 00:00:00 2001 From: quez-fun <54435650+quez-fun@users.noreply.github.com> Date: Wed, 12 Jun 2024 21:10:07 +0800 Subject: [PATCH] Update index.html added initial picking response to 3d objects upon mousemove event --- index.html | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 282 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 5d19869..4f602ed 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ body { margin: 0 auto; font-family: Arial, Helvetica, sans-serif; - color: ##777; + color: #777; overflow: hidden; width: auto; height: auto; @@ -49,10 +49,75 @@ text-decoration: none; color: blue; } + + /* + span { + color: aquamarine; + font-weight: 300; +} + + + .tag { + position: absolute; + z-index: 99; + display: none; + top: 0; + left: 0; + width: 70px; + } + + a { + border: 1px solid #1d71b8; + background-color: #fff; + border-radius: 5px; + color: #1d71b8; + display: block; + font-size: 11px; + line-height: 18px; + margin: auto; + padding: 5px; + text-decoration: none; + text-align: center; + } + + a:before { + border: 11px solid transparent; + border-bottom: 0; + border-top: 11px solid #1d71b8; + bottom: 0; + content: ""; + display: block; + left: 50%; + position: absolute; + transform: translate(-50%, 90%); + width: 0; + } + + a:after { + border: 10px solid transparent; + border-bottom: 0; + border-top: 10px solid #fff; + bottom: 0; + content: ""; + display: block; + left: 50%; + position: absolute; + transform: translate(-50%, 85%); + width: 0; + } + */ + +

My Projects

temporary link(to be integrated soon)

@@ -72,6 +137,27 @@

My Projects

void main() { gl_FragColor = vec4(0.05, 0.3,0.8, 0.55); } + + + @@ -103,6 +189,46 @@

My Projects

u_worldViewProjection: m4.identity(), }; + let initialAnimation = true; + + //create frame buffer + const targetTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, targetTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + + const depthBuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); + + function setFramebufferAttachmentSizes(width, height) { + gl.bindTexture(gl.TEXTURE_2D, targetTexture); + const level = 0; + const internalFormat = gl.RGBA; + const border = 0; + const format = gl.RGBA; + const type = gl.UNSIGNED_BYTE; + const data = null; + gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, + width, height, border, + format, type, data); + + //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.canvas.width * 2, gl.canvas.height * 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); + } + + const fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); //这条放出来以后,图形就没了,但也分离了渲染层和pick层 + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, 0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); + + let pickUniforms = { + u_worldViewProjection: m4.identity(), + u_world: m4.identity(), + }; + function main() { if (!gl) { @@ -116,11 +242,13 @@

My Projects

const bufferInfo = webglUtils.createBufferInfoFromArrays(gl, arrays); const programInfo = webglUtils.createProgramInfo(gl, ["vertex-shader-3d", "fragment-shader-3d"]); + const pickProgramInfo = webglUtils.createProgramInfo(gl, ["pick-vertex-shader-3d", "pick-fragment-shader-3d"]); function drawScene() { resizeCanvasToDisplaySize(canvas); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.clearColor(1, 1, 1, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); @@ -154,12 +282,143 @@

My Projects

}); - requestAnimationFrame(shrink); - //requestAnimationFrame(moveCam); - //console.log('drawScene'); + if (initialAnimation) { + requestAnimationFrame(shrink); + } + + //console.log('drawscene'); } + function renderPicking(e) { + + //创建frame buffer + gl.bindTexture(gl.TEXTURE_2D, targetTexture); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.canvas.width * 2, gl.canvas.height * 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + // 加入depth buffer(2/3) + gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, gl.canvas.width * 2, gl.canvas.height * 2); + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, 0); + + // 加入depth buffer(3/3) + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); + + gl.bindTexture(gl.TEXTURE_2D, targetTexture); + + // 创建mouse event对frustum matrix的转换通讯 + + const near = 1, far = 2000; + const top = Math.tan(degToRad(60) * 0.5) * near; + const bottom = -top; + const left = aspect * bottom; + const right = aspect * top; + const width = Math.abs(right - left); + const height = Math.abs(top - bottom); + const rect = canvas.getBoundingClientRect(); + + const pixelX = (e.clientX - rect.left) * gl.canvas.width / gl.canvas.clientWidth; + const pixelY = gl.canvas.height - (e.clientY - rect.top) * gl.canvas.height / gl.canvas.clientHeight - 1; + + const subLeft = left + pixelX * width / gl.canvas.width; + const subBottom = bottom + pixelY * height / gl.canvas.height; + const subWidth = width / gl.canvas.width; + const subHeight = height / gl.canvas.height; + + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + // Tell WebGL how to convert from clip space to pixels + gl.viewport(0, 0, 1, 1); + + // Clear the canvas AND the depth buffer. + // gl.clear(gl.COLOR_BUFFER_BIT); //| gl.DEPTH_BUFFER_BIT + + var projectionMatrix = m4.frustum(subLeft, subLeft + subWidth, subBottom, subBottom + subHeight, near, far); + + var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix); + + gl.useProgram(pickProgramInfo.program); + + webglUtils.setBuffersAndAttributes(gl, pickProgramInfo, bufferInfo); + + webglUtils.setUniforms(pickProgramInfo, pickUniforms); + + + // Draw objects + objects.forEach(function (object) { + + let worldMatrix = m4.xRotation(0); + worldMatrix = m4.translate(worldMatrix, object.xTranslation, object.yTranslation, object.zTranslation); + worldMatrix = m4.yRotate(worldMatrix, object.yRotation); + + // Multiply the matrices. + m4.multiply(viewProjectionMatrix, worldMatrix, uniformsThatAreComputedForEachObject.u_worldViewProjection); + + // Set the uniforms we just computed + webglUtils.setUniforms(pickProgramInfo, uniformsThatAreComputedForEachObject); + + webglUtils.setUniforms(pickProgramInfo, object.pickIDUniform); + + // Draw the geometry. + gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0); + + }); + + //阅读物体id + const pixels = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + + + if (pixels[0] > 0) { + console.log('picked'); + + resizeCanvasToDisplaySize(canvas); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); + gl.clearColor(0, 0, 1, 0.1); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + const projectionMatrix = m4.perspective(fieldOfViewRadians, aspect, 1, 2000); + const viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix); + + gl.useProgram(programInfo.program); + + // Setup all the needed buffers and attributes. + webglUtils.setBuffersAndAttributes(gl, programInfo, bufferInfo); + + gl.disable(gl.DEPTH_TEST); + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + + objects.forEach(function (object) { + + let worldMatrix = m4.xRotation(0); + worldMatrix = m4.translate(worldMatrix, object.xTranslation, object.yTranslation +5, object.zTranslation); + worldMatrix = m4.yRotate(worldMatrix, object.yRotation); + + // Multiply the matrices. + m4.multiply(viewProjectionMatrix, worldMatrix, uniformsThatAreComputedForEachObject.u_worldViewProjection); + + // Set the uniforms we just computed + webglUtils.setUniforms(programInfo, uniformsThatAreComputedForEachObject); + + // Draw the geometry. + gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0); + + }); + } else { + drawScene(); + } + } + + function drawObjects() { for (var i = 0; i < rowNum; i++) { @@ -173,6 +432,10 @@

My Projects

yTranslation: 0, zTranslation: (j - columnNum / 2) * (width + gapH) + gapH / 2, + pickIDUniform: { + u_id: [(i + 1) / 255, (j + i) / 255, 0, 1], + } + }); @@ -183,6 +446,10 @@

My Projects

yTranslation: 0, zTranslation: (j - columnNum / 2) * (width + gapH) + width + gapH / 2, + pickIDUniform: { + u_id: [(i + 1) / 255, (j + i) / 255, 0, 1], + } + }); objects.push({ @@ -192,6 +459,10 @@

My Projects

yTranslation: 0, zTranslation: (j - columnNum / 2) * (width + gapH) + width / 2 + gapH / 2, + pickIDUniform: { + u_id: [(i + 1) / 255, (j + i) / 255, 0, 1], + } + }); objects.push({ @@ -201,6 +472,10 @@

My Projects

yTranslation: 0, zTranslation: (j - columnNum / 2) * (width + gapH) + width / 2 + gapH / 2, + pickIDUniform: { + u_id: [(i + 1) / 255, (j + i) / 255, 0, 1], + } + }); } @@ -239,6 +514,8 @@

My Projects

requestAnimationFrame(drawScene); //console.log('shrink'); + } else { + initialAnimation = false; } } @@ -247,9 +524,7 @@

My Projects

drawScene(); window.addEventListener('resize', drawScene, false); - - //测试动画 - window.addEventListener('click', shrink, false); + window.addEventListener('mousemove', renderPicking, false); }