From 2da9b820a96d331a32688f475f29cde46cd8d7ce Mon Sep 17 00:00:00 2001 From: pureblackkkk Date: Sun, 21 May 2023 15:13:43 +0800 Subject: [PATCH] feat: Add example from book for chapter5,6,7 --- chapter05/camerarotate/app.js | 302 +++++++++++++++++++++++ chapter05/camerarotate/app_origin.js | 124 ++++++++++ chapter05/camerarotate/index.html | 13 + chapter05/camerarotate/shader.frag | 8 + chapter05/camerarotate/shader.vert | 10 + chapter05/shadow/app.js | 120 +++++++++ chapter05/shadow/index.html | 13 + chapter05/shadow/shader.frag | 6 + chapter05/shadow/shader.vert | 10 + chapter06/light/app.js | 214 ++++++++++++++++ chapter06/light/index.html | 13 + chapter06/light/shader.frag | 7 + chapter06/light/shader.vert | 33 +++ chapter07/cube-texture/app.js | 274 ++++++++++++++++++++ chapter07/cube-texture/index.html | 14 ++ chapter07/cube-texture/shader.frag | 14 ++ chapter07/cube-texture/shader.vert | 14 ++ chapter07/reflection-texture/app.js | 213 ++++++++++++++++ chapter07/reflection-texture/index.html | 13 + chapter07/reflection-texture/shader.frag | 8 + chapter07/reflection-texture/shader.vert | 12 + 21 files changed, 1435 insertions(+) create mode 100644 chapter05/camerarotate/app.js create mode 100644 chapter05/camerarotate/app_origin.js create mode 100644 chapter05/camerarotate/index.html create mode 100644 chapter05/camerarotate/shader.frag create mode 100644 chapter05/camerarotate/shader.vert create mode 100644 chapter05/shadow/app.js create mode 100644 chapter05/shadow/index.html create mode 100644 chapter05/shadow/shader.frag create mode 100644 chapter05/shadow/shader.vert create mode 100644 chapter06/light/app.js create mode 100644 chapter06/light/index.html create mode 100644 chapter06/light/shader.frag create mode 100644 chapter06/light/shader.vert create mode 100644 chapter07/cube-texture/app.js create mode 100644 chapter07/cube-texture/index.html create mode 100644 chapter07/cube-texture/shader.frag create mode 100644 chapter07/cube-texture/shader.vert create mode 100644 chapter07/reflection-texture/app.js create mode 100644 chapter07/reflection-texture/index.html create mode 100644 chapter07/reflection-texture/shader.frag create mode 100644 chapter07/reflection-texture/shader.vert diff --git a/chapter05/camerarotate/app.js b/chapter05/camerarotate/app.js new file mode 100644 index 0000000..a45fe68 --- /dev/null +++ b/chapter05/camerarotate/app.js @@ -0,0 +1,302 @@ +import {createProgram, setupWebGL, pointsToBuffer} from 'GLHelper'; +import { vec3, vec4, mat4 } from 'gl-matrix'; +import vertexShader from './shader.vert'; +import fragmentShader from './shader.frag'; + +let gl; +let width; +let height; + +// Mouse Settings +let lastMousePosition = vec3(0, 0, 0); +let isMouseDown = false; +let isMouseRotation = false; +let rotationLongitude = 0; +let rotationLatitude = 0; +const RotationVelocity = 1000; + +// Transform setting +let transitionMatrix; +let rotationMatrix; +let projectionMatrix; +let scaleMatrix; +let transformMatrix = mat4(vec4(1,0,0,0), vec4(0,1,0,0), vec4(0,0,1,0), vec4(0,0,0,1)); +let transformMatrixLoc; + +// Camera setting +let fov = Math.PI / 2; +let aspect; +let near = 0.1; +let far = 5; +let cameraPosition = vec3(0, 0, 1); +let cameraLookAtPosition = vec3(0, 0, 0); +let cameraLookUp = vec3(0, 1, 0); +let upLatitude = Math.PI / 2; +const cameraUpRadius = Math.sqrt(2); + + +function setTransitionMatrix() { + // Move the camera to 0, 0, 0 + transitionMatrix = mat4( + 1, 0, 0, -cameraPosition[0], + 0, 1, 0, -cameraPosition[1], + 0, 0, 1, -cameraPosition[2], + 0, 0, 0, 1, + ); +} + +function setRotationMatrix() { + // Rotate camera, making it looking at -z and up vector equals to y + const crossAxis = vec3.create(); + const cameraLookAtVec = vec3.create(); + vec3.subtract(cameraLookAtVec, cameraLookAtPosition, cameraPosition); + vec3.normalize(cameraLookAtVec, cameraLookAtVec); + vec3.cross(crossAxis, cameraLookAtVec, cameraLookUp); + vec3.normalize(crossAxis, crossAxis); + rotationMatrix = mat4( + vec4(crossAxis[0], crossAxis[1], crossAxis[2], 0), + vec4(cameraLookUp[0], cameraLookUp[1], cameraLookUp[2], 0), + vec4(-cameraLookAtVec[0], -cameraLookAtVec[1], -cameraLookAtVec[2], 0), + vec4(0, 0, 0, 1) + ); +} + +function setProjectionMarix() { + // Transform view space to cubeic + const coefficentA = -near - far; + const coefficentB = -near * far; + + projectionMatrix = mat4( + vec4(-near, 0, 0, 0), + vec4(0, -near, 0, 0), + vec4(0, 0, coefficentA, coefficentB), + vec4(0, 0, 1, 0), + ); +} + +function setScaleMatirx() { + const top = near * Math.tan(fov / 2); + const right = top * aspect; + + scaleMatrix = mat4( + vec4(1/right, 0, 0, 0), + vec4(0, 1/top, 0, 0), + vec4(0, 0, 2/(far - near), (far + near) / (far - near)), + vec4(0, 0, 0, 1), + ); +} + +function setMVPTransformMatrix() { + setTransitionMatrix(); + setRotationMatrix(); + setProjectionMarix(); + setScaleMatirx(); + const lookatMatrix = mat4.create(); + const perspectiveMatrix = mat4.create(); + mat4.lookAt(lookatMatrix, cameraPosition, vec3(0, 0, 0), cameraLookUp); + mat4.perspective(perspectiveMatrix, fov, width / height, near, far); + + const iMat = mat4(vec4(1,0,0,0), vec4(0,1,0,0), vec4(0,0,1,0), vec4(0,0,0,1)); + + const test = mat4.create(); + mat4.multiply(test, transitionMatrix, iMat); + mat4.multiply(test, rotationMatrix, test); + mat4.multiply(transformMatrix, lookatMatrix, iMat); + mat4.multiply(transformMatrix, projectionMatrix, transformMatrix); + mat4.multiply(transformMatrix, scaleMatrix, transformMatrix); +} + +function setMVPTransformMatrix2() { + const lookatMatrix = mat4.create(); + const perspectiveMatrix = mat4.create(); + + mat4.lookAt(lookatMatrix, cameraPosition, vec3(0, 0, 0), cameraLookUp); + mat4.perspective(perspectiveMatrix, fov, width / height, near, far); + + const iMat = mat4(vec4(1,0,0,0), vec4(0,1,0,0), vec4(0,0,1,0), vec4(0,0,0,1)); + mat4.multiply(transformMatrix, lookatMatrix, iMat); + mat4.multiply(transformMatrix, perspectiveMatrix, transformMatrix); +} + +function updateCameraSettings(horizontalAngle, verticalAngle) { + rotationLatitude += verticalAngle; + rotationLongitude += horizontalAngle; + + // Set camera new position + const radius = vec3.length(vec3(cameraPosition) - vec3(cameraLookAtPosition)); + const temp = Math.cos(rotationLatitude) * radius; + cameraPosition = vec3( + temp * Math.sin(rotationLongitude), + radius * Math.sin(rotationLatitude), + temp * Math.cos(rotationLongitude), + ); + + // Update new up vector + upLatitude += horizontalAngle; + const temp2 = Math.cos(upLatitude) * cameraUpRadius; + vec3.normalize(cameraLookUp, vec3( + temp2 * Math.sin(rotationLongitude), + cameraUpRadius * Math.sin(upLatitude), + temp2 * Math.cos(rotationLongitude), + )); +} + +function getCordinatePositionFromMouse(x, y) { + const newX = 2 * x / width - 1; + const newY = 2 * (height - y) / height - 1; + return vec3(newX, newY, 0); +} + +function handleMouseDown() { + isMouseDown = true; +} + +function handleMouseUp() { + isMouseDown = false; + isMouseRotation = false; + lastMousePosition = vec3(0, 0, 0); +} + +function handleMouseMove(e) { + if (isMouseDown === false) { + return; + } + isMouseRotation = true; + + const { clientX, clientY } = e; + const currentVec = getCordinatePositionFromMouse(clientX, clientY); + const deltaVec = vec3(currentVec) - vec3(lastMousePosition); + + // Calculate verlocity coefficent and update mouse settings + const horizontalVelocityCoefficent = deltaVec[0] / width; + const verticalVelocityCoffeicent = deltaVec[1] / height; + const deltahorizontalAngle = horizontalVelocityCoefficent * RotationVelocity; + const deltaVerticalAngle = verticalVelocityCoffeicent * RotationVelocity; + updateCameraSettings(deltahorizontalAngle, deltaVerticalAngle); + + // Set last position to current one + lastMousePosition = currentVec; +} + +function throttleCallback(interval, fn) { + let lastTime = Date.now(); + const throttledCallback = (e) => { + const currentTime = Date.now(); + if ((currentTime - lastTime) > interval) { + fn(e); + lastTime = currentTime; + } + } + return throttledCallback; +} + +function initEvent() { + const canvas = document.getElementById('gl-canvas'); + document.addEventListener('mousedown', handleMouseDown); + document.addEventListener('mouseup', handleMouseUp); + canvas.addEventListener('mousemove', throttleCallback(100, handleMouseMove)); +} + +function init() { + const vertices = [ + vec4(-0.5, -0.5, 0.5, 1.0), + vec4(-0.5, 0.5, 0.5, 1.0), + vec4(0.5, 0.5, 0.5, 1.0), + vec4(0.5, -0.5, 0.5, 1.0), + vec4(-0.5, -0.5, -0.5, 1.0), + vec4(-0.5, 0.5, -0.5, 1.0), + vec4(0.5, 0.5, -0.5, 1.0), + vec4(0.5, -0.5, -0.5, 1.0), + ]; + + const vertexColors = [ + [0.0, 0.0, 0.0, 1.0], + [1.0, 0.0, 0.0, 1.0], + [1.0, 1.0, 0.0, 1.0], + [0.0, 1.0, 0.0, 1.0], + [0.0, 0.0, 1.0, 1.0], + [1.0, 0.0, 1.0, 1.0], + [1.0, 1.0, 1.0, 1.0], + [0.0, 1.0, 1.0, 1.0], + ]; + + const vertexIndex = [ + 1, 0, 3, + 3, 2, 1, + 2, 3, 7, + 7, 6, 2, + 3, 0, 4, + 4, 7, 3, + 6, 5, 1, + 1, 2, 6, + 4, 5, 6, + 6, 7, 4, + 5, 4, 0, + 0, 1, 5, + ]; + + // Make gl + const canvas = document.getElementById('gl-canvas'); + height = canvas.height; + width = canvas.width; + aspect = width / height; + + gl = setupWebGL(canvas); + + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.enable(gl.DEPTH_TEST); + + // Create program with shader + const program = createProgram(gl, vertexShader, fragmentShader); + gl.useProgram(program); + + // Load data + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(vertices), gl.STATIC_DRAW); + + // Set shader position variable + const vPosition = gl.getAttribLocation(program, 'vPosition'); + gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vPosition); + + const colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(vertexColors), gl.STATIC_DRAW); + + // Set shader color variable + const vColor = gl.getAttribLocation(program, 'vColor'); + gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vColor); + + const indexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(vertexIndex), gl.STATIC_DRAW); + + // get uniform variable + transformMatrixLoc = gl.getUniformLocation(program, 'r'); + gl.uniformMatrix4fv(transformMatrixLoc, false, transformMatrix); + + // Init Event + initEvent(); + + render(); +} + +function render() { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + if (isMouseRotation) { + // Set new transformMatrix + setMVPTransformMatrix(); + + // Set uniform variable + gl.uniformMatrix4fv(transformMatrixLoc, false, new Float32Array(transformMatrix)); + } + + gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0); + requestAnimationFrame(render); +} + +init(); \ No newline at end of file diff --git a/chapter05/camerarotate/app_origin.js b/chapter05/camerarotate/app_origin.js new file mode 100644 index 0000000..a818e98 --- /dev/null +++ b/chapter05/camerarotate/app_origin.js @@ -0,0 +1,124 @@ +import {createProgram, setupWebGL, pointsToBuffer} from 'GLHelper'; +import {vec4} from 'gl-matrix'; +import colorString from 'color-string'; + +import vertexShader from './shader.vert'; +import fragmentShader from './shader.frag'; + +let gl; + +const points = []; +const colors = []; + +let axis = 0; +const theta = [0, 0, 0]; + +let thetaLoc; + +function colorCube() { + quad(1, 0, 3, 2); + quad(2, 3, 7, 6); + quad(3, 0, 4, 7); + quad(6, 5, 1, 2); + quad(4, 5, 6, 7); + quad(5, 4, 0, 1); +} + +const vertices = [ + vec4(-0.5, -0.5, 0.5, 1.0), + vec4(-0.5, 0.5, 0.5, 1.0), + vec4(0.5, 0.5, 0.5, 1.0), + vec4(0.5, -0.5, 0.5, 1.0), + vec4(-0.5, -0.5, -0.5, 1.0), + vec4(-0.5, 0.5, -0.5, 1.0), + vec4(0.5, 0.5, -0.5, 1.0), + vec4(0.5, -0.5, -0.5, 1.0), +]; + +const vertexColors = [ + 'black', + 'red', + 'yellow', + 'green', + 'blue', + 'magenta', + 'cyan', + 'white', +].map((color) => { + return colorString.get(color).value.slice(0, 3); +}); + +// console.log(vertexColors); + +function quad(a, b, c, d) { + // We need to parition the quad into two triangles in order for + // WebGL to be able to render it. In this case, we create two + // triangles from the quad indices + + // vertex color assigned by the index of the vertex + const indices = [a, b, c, a, c, d]; + + for(let i = 0; i < indices.length; ++i) { + points.push(vertices[indices[i]]); + // colors.push( vertexColors[indices[i]] ); + + // for solid colored faces use + colors.push(vertexColors[a]); + } +} + +function init() { + const canvas = document.getElementById('gl-canvas'); + gl = setupWebGL(canvas); + if(!gl) { + console.error('WebGL isn\'t available'); + } + + colorCube(); + + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + + gl.enable(gl.DEPTH_TEST); + + const program = createProgram(gl, vertexShader, fragmentShader); + gl.useProgram(program); + + const cBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(colors, Uint8Array), gl.STATIC_DRAW); + + const vColor = gl.getAttribLocation(program, 'vColor'); + gl.vertexAttribPointer(vColor, 3, gl.UNSIGNED_BYTE, true, 0, 0); + gl.enableVertexAttribArray(vColor); + + const vBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(points), gl.STATIC_DRAW); + + + const vPosition = gl.getAttribLocation(program, 'vPosition'); + gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vPosition); + + thetaLoc = gl.getUniformLocation(program, 'theta'); + + /* globals xButton:true yButton:true zButton:true */ + [xButton, yButton, zButton].forEach((button, i) => { + button.addEventListener('click', () => { + axis = i; + }); + }); + + render(); +} + +function render() { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + theta[axis] += 2.0; + gl.uniform3fv(thetaLoc, theta); + gl.drawArrays(gl.TRIANGLES, 0, 36); + requestAnimationFrame(render); +} + +init(); diff --git a/chapter05/camerarotate/index.html b/chapter05/camerarotate/index.html new file mode 100644 index 0000000..c468139 --- /dev/null +++ b/chapter05/camerarotate/index.html @@ -0,0 +1,13 @@ + + + + + + + 3D Cube + + + + + + \ No newline at end of file diff --git a/chapter05/camerarotate/shader.frag b/chapter05/camerarotate/shader.frag new file mode 100644 index 0000000..9fee22a --- /dev/null +++ b/chapter05/camerarotate/shader.frag @@ -0,0 +1,8 @@ +precision mediump float; +varying vec4 fColor; + +void +main() +{ + gl_FragColor = fColor; +} \ No newline at end of file diff --git a/chapter05/camerarotate/shader.vert b/chapter05/camerarotate/shader.vert new file mode 100644 index 0000000..aa04f36 --- /dev/null +++ b/chapter05/camerarotate/shader.vert @@ -0,0 +1,10 @@ +attribute vec4 vPosition; +attribute vec4 vColor; +varying vec4 fColor; +uniform mat4 r; + +void main() +{ + gl_Position = r * vPosition; + fColor = vColor; +} \ No newline at end of file diff --git a/chapter05/shadow/app.js b/chapter05/shadow/app.js new file mode 100644 index 0000000..7ca4550 --- /dev/null +++ b/chapter05/shadow/app.js @@ -0,0 +1,120 @@ +import {createProgram, setupWebGL, pointsToBuffer} from 'GLHelper'; +import {vec3, vec4, mat4} from 'gl-matrix'; +import vertexShader from './shader.vert'; +import fragmentShader from './shader.frag'; + +let gl; +let fColorLoc; +let modelViewMatrixLoc; +let projectionMatrixLoc; +let theta = 0.0; +let red, black; +let at, eye, up, light; +let shadowProjectionMatrix; + +function init() { + const canvas = document.getElementById('gl-canvas'); + const {width, height} = canvas; + gl = setupWebGL(canvas); + if(!gl) { + console.error('WebGL isn\'t available'); + } + gl.viewport(0, 0, width, height); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.enable(gl.DEPTH_TEST); + const program = createProgram(gl, vertexShader, fragmentShader); + gl.useProgram(program); + + const pointsArray = [ + vec4(-0.5, 0.5, -0.5, 1.0), + vec4(-0.5, 0.5, 0.5, 1.0), + vec4(0.5, 0.5, 0.5, 1.0), + vec4(0.5, 0.5, -0.5, 1.0), + ]; + // Light related + light = vec3(0.0, 2.0, 0.0); + + // Camera related + at = vec3(0.0, 0.0, 0.0); + up = vec3(0.0, 1.0, 0.0); + eye = vec3(1.0, 1.0, 1.0); + + // Color related + red = vec4(1.0, 0.0, 0.0, 1.0); + black = vec4(0.0, 0.0, 0.0, 1.0); + + // Shadow projection matrix + shadowProjectionMatrix = mat4( + vec4(1, 0, 0, 0), + vec4(0, 1, 0, -1 / light[1]), + vec4(0, 0, 1, 0), + vec4(0, 0, 0, 0), + ); + + console.log(shadowProjectionMatrix); + + // Init position buffer and push the data + const vBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(pointsArray), gl.STATIC_DRAW); + const vPosition = gl.getAttribLocation(program, 'vPosition'); + gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vPosition); + + // Init uniform color variable + fColorLoc = gl.getUniformLocation(program, 'fColor'); + + // Init transform matrix location + modelViewMatrixLoc = gl.getUniformLocation(program, 'modelViewMatrix'); + projectionMatrixLoc = gl.getUniformLocation(program, 'projectionMatrix'); + + // Generate transform matrix + const projectionMatrix = mat4.ortho(-5.0, 5.0, -5, 5, 0.1, 10.0); + gl.uniformMatrix4fv(projectionMatrixLoc, false, projectionMatrix); + + render(); +} + +function render() { + theta += 0.1; + if (theta > 2*Math.PI) { + theta -= 2*Math.PI; + } + + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Create model view matrix + let modelViewMatrix = mat4.create(); + mat4.lookAt(modelViewMatrix, eye, at, up); + + gl.uniformMatrix4fv(modelViewMatrixLoc, false, modelViewMatrix); + gl.uniform4fv(fColorLoc, red); + + gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); + + // Rotate light + light[0] = Math.sin(theta); + light[2] = Math.cos(theta); + + // Create model view matrix for shadow + let translateMatrix = mat4.create(); + let translateMatrixReverse = mat4.create(); + let shadowModelViewMatrix = mat4.create(); + + mat4.translate(translateMatrix, mat4.create(), -1 * vec3(light)); + mat4.translate(translateMatrixReverse, mat4.create(), vec3(light)); + + mat4.multiply(shadowModelViewMatrix, translateMatrix, shadowModelViewMatrix); + mat4.multiply(shadowModelViewMatrix, shadowProjectionMatrix, shadowModelViewMatrix); + mat4.multiply(shadowModelViewMatrix, translateMatrixReverse, shadowModelViewMatrix); + mat4.multiply(shadowModelViewMatrix, modelViewMatrix, shadowModelViewMatrix); + + // Send shadow color and matrix + gl.uniformMatrix4fv(modelViewMatrixLoc, false, shadowModelViewMatrix); + gl.uniform4fv(fColorLoc, black); + gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); + + requestAnimationFrame(render); +} + +init(); \ No newline at end of file diff --git a/chapter05/shadow/index.html b/chapter05/shadow/index.html new file mode 100644 index 0000000..9ed0aa3 --- /dev/null +++ b/chapter05/shadow/index.html @@ -0,0 +1,13 @@ + + + + + + + 3D Cube Trackball + + + + + + \ No newline at end of file diff --git a/chapter05/shadow/shader.frag b/chapter05/shadow/shader.frag new file mode 100644 index 0000000..dd4b8e9 --- /dev/null +++ b/chapter05/shadow/shader.frag @@ -0,0 +1,6 @@ +precision mediump float; +varying vec4 color; + +void main() { + gl_FragColor = color; +} \ No newline at end of file diff --git a/chapter05/shadow/shader.vert b/chapter05/shadow/shader.vert new file mode 100644 index 0000000..ac960ff --- /dev/null +++ b/chapter05/shadow/shader.vert @@ -0,0 +1,10 @@ +attribute vec4 vPosition; +varying vec4 color; +uniform vec4 fColor; +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; + +void main() { + gl_Position = projectionMatrix * modelViewMatrix * vPosition; + color = fColor; +} \ No newline at end of file diff --git a/chapter06/light/app.js b/chapter06/light/app.js new file mode 100644 index 0000000..3dd979b --- /dev/null +++ b/chapter06/light/app.js @@ -0,0 +1,214 @@ +import {createProgram, setupWebGL, pointsToBuffer} from 'GLHelper'; +import {vec3, vec4, mat4} from 'gl-matrix'; +import vertexShader from './shader.vert'; +import fragmentShader from './shader.frag'; + +function init() { + // Init webgl context + const canvas = document.getElementById('gl-canvas'); + const {width, height} = canvas; + const gl = setupWebGL(canvas); + if(!gl) { + console.error('WebGL isn\'t available'); + } + gl.viewport(0, 0, width, height); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.enable(gl.DEPTH_TEST); + const program = createProgram(gl, vertexShader, fragmentShader); + gl.useProgram(program); + + // Init light related constant + const lightPosition = vec4(1.0, 2.0, 3.0, 1.0); + const lightAmbient = vec4(0.7, 0.7, 0.2, 1.0); + const lightDiffuse = vec4(1.0, 1.0, 1.0, 1.0); + const lightSpecular = vec4(1.0, 1.0, 1.0, 1.0); + const shiness = 100.0; + + // Init material related (ka, kd, ks) + const materialAmbient = vec4(1.0, 0.0, 1.0, 1.0); + const materialDiffuse = vec4(1.0, 0.8, 0.0, 1.0); + const materialSpecular = vec4(1.0, 0.8, 0.0, 1.0); + + // Caculate product + let ambientProduct = vec4.create(); + let diffuseProduct = vec4.create(); + let specularProdcut = vec4.create(); + vec4.multiply(ambientProduct, lightAmbient, materialAmbient); + vec4.multiply(diffuseProduct, lightDiffuse, materialDiffuse); + vec4.multiply(specularProdcut, lightSpecular, materialSpecular); + + // Cube related constant + // 立方体点位置 + // v0----- v3 + // /| /| + // v1------v2| + // | | | | + // | |v4---|-|v7 + // |/ |/ + // v5------v6 + // 顺序为前后左右上下 + + const vertices = [ + // v0-v1-v2-v3-up + vec4(-0.5, 0.5, -0.5, 1), + vec4(-0.5, 0.5, 0.5, 1), + vec4(0.5, 0.5, 0.5, 1), + vec4(0.5, 0.5, -0.5, 1), + // v0-v4-v5-v1-left + vec4(-0.5, 0.5, -0.5, 1), + vec4(-0.5, -0.5, -0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + vec4(-0.5, 0.5, 0.5, 1), + // v1-v5-v6-v2-front + vec4(-0.5, 0.5, 0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(0.5, 0.5, 0.5, 1), + // v2-v6-v7-v3-right + vec4(0.5, 0.5, 0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(0.5, 0.5, -0.5, 1), + // v3-v7-v4-v0-back + vec4(0.5, 0.5, -0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(-0.5, -0.5, -0.5, 1), + vec4(-0.5, 0.5, -0.5, 1), + // v4-v7-v6-v5-bottom + vec4(-0.5, -0.5, -0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + ]; + + const normals = [ + // up + vec4(0, 1, 0, 0), + vec4(0, 1, 0, 0), + vec4(0, 1, 0, 0), + vec4(0, 1, 0, 0), + // left + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + // font + vec4(0, 0, 1, 0), + vec4(0, 0, 1, 0), + vec4(0, 0, 1, 0), + vec4(0, 0, 1, 0), + // right + vec4(1, 0, 0, 0), + vec4(1, 0, 0, 0), + vec4(1, 0, 0, 0), + vec4(1, 0, 0, 0), + // back + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + // bottom + vec4(0, -1, 0, 0), + vec4(0, -1, 0, 0), + vec4(0, -1, 0, 0), + vec4(0, -1, 0, 0), + ]; + + const indexs = [ + // up + 0, 1, 2, + 0, 2, 3, + // left + 4, 5, 6, + 4, 6, 7, + // font + 8, 9, 10, + 8, 10, 11, + // right + 12, 13, 14, + 12, 14, 15, + // back + 16, 17, 18, + 16, 18, 19, + // bottom + 20, 21, 22, + 20, 22, 23, + ]; + + // Camera related constant + const eye = vec4(-1, 1, 1, 1); + const up = vec4(0, 1, 0, 0); + const at = vec4(0, 0, 0, 1); + + + // Load vertices to buffer + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(vertices), gl.STATIC_DRAW); + const vPosition = gl.getAttribLocation(program, 'vPosition'); + gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vPosition); + + // Load normals to buffer + const normalsBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, normalsBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(normals), gl.STATIC_DRAW); + const vNormal = gl.getAttribLocation(program, 'vNormal'); + gl.vertexAttribPointer(vNormal, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vNormal); + + // Load element index + const indexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indexs), gl.STATIC_DRAW); + + // Load uniform variable + let modelViewMatrix = mat4.create(); + mat4.lookAt(modelViewMatrix, eye, at, up); + const modelViewMatrixLoc = gl.getUniformLocation(program, 'modelViewMatrix'); + gl.uniformMatrix4fv(modelViewMatrixLoc, false, modelViewMatrix); + + let projectionMatrix = mat4.create(); + mat4.ortho(projectionMatrix, -5.0, 5.0, -5.0, 5.0, 0.5, 10); + const projectionMatrixLoc = gl.getUniformLocation(program, 'projectionMatrix'); + gl.uniformMatrix4fv(projectionMatrixLoc, false, projectionMatrix); + + const ambientProductLoc = gl.getUniformLocation(program, 'ambientProduct'); + gl.uniform4fv(ambientProductLoc, ambientProduct); + + const diffuseProductLoc = gl.getUniformLocation(program, 'diffuseProduct'); + gl.uniform4fv(diffuseProductLoc, diffuseProduct); + + const specularProdcutLoc = gl.getUniformLocation(program, 'specularProdcut'); + gl.uniform4fv(specularProdcutLoc, specularProdcut); + + const lightPosnitionLoc = gl.getUniformLocation(program, 'lightPosition'); + gl.uniform4fv(lightPosnitionLoc, lightPosition); + + const shinessLoc = gl.getUniformLocation(program, 'shiness'); + gl.uniform1f(shinessLoc, shiness); + + // Render function + let theta = 0.0; + + const render = () => { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + theta += 0.1; + if (theta > 2*Math.PI) { + theta -= 2*Math.PI; + } + + // Rotate light + lightPosition[0] = Math.sin(theta); + lightPosition[2] = Math.cos(theta); + gl.uniform4fv(lightPosnitionLoc, lightPosition); + + // Redraw + gl.drawElements(gl.TRIANGLES, indexs.length, gl.UNSIGNED_BYTE, 0); + requestAnimationFrame(render); + } + + render(); +} + +init(); \ No newline at end of file diff --git a/chapter06/light/index.html b/chapter06/light/index.html new file mode 100644 index 0000000..bca40f0 --- /dev/null +++ b/chapter06/light/index.html @@ -0,0 +1,13 @@ + + + + + + + light + + + + + + \ No newline at end of file diff --git a/chapter06/light/shader.frag b/chapter06/light/shader.frag new file mode 100644 index 0000000..0c0eff6 --- /dev/null +++ b/chapter06/light/shader.frag @@ -0,0 +1,7 @@ +precision mediump float; +varying vec4 fColor; + +void main() { + gl_FragColor = fColor; +} + diff --git a/chapter06/light/shader.vert b/chapter06/light/shader.vert new file mode 100644 index 0000000..60c2835 --- /dev/null +++ b/chapter06/light/shader.vert @@ -0,0 +1,33 @@ +attribute vec4 vPosition; +attribute vec4 vNormal; +varying vec4 fColor; +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; +uniform vec4 lightPosition; +uniform vec4 ambientProduct; +uniform vec4 specularProduct; +uniform vec4 diffuseProduct; +uniform float shiness; + +void main() { + vec3 pos = (modelViewMatrix * vPosition).xyz; + vec3 light = (modelViewMatrix * lightPosition).xyz; + float distanceSquare = dot(light - pos, light - pos); + + vec3 L = normalize(light - pos); + vec3 E = -pos; + vec3 H = normalize(L + E); + vec3 N = normalize(modelViewMatrix * vNormal).xyz; + + // Ambient light + vec4 ambient = ambientProduct; + + // Diffusion light + vec4 diffuse = max(dot(L, N), 0.0) * diffuseProduct; + + // Speculation light + vec4 specular = pow(max(dot(N, H), 0.0), shiness) * specularProduct; + + fColor = ambient + (diffuse + specular) / distanceSquare; + gl_Position = projectionMatrix * modelViewMatrix * vPosition; +} diff --git a/chapter07/cube-texture/app.js b/chapter07/cube-texture/app.js new file mode 100644 index 0000000..239b3b2 --- /dev/null +++ b/chapter07/cube-texture/app.js @@ -0,0 +1,274 @@ +import {createProgram, setupWebGL, pointsToBuffer} from 'GLHelper'; +import {vec2, vec4, mat4} from 'gl-matrix'; +import vertexShader from './shader.vert'; +import fragmentShader from './shader.frag'; + +function createTexture(gl) { + const texSize = 64; + const numRows = 8; + const numCols = 8; + + const myTexels = new Uint8Array(4 * texSize * texSize); + for (let i = 0; i < texSize; i++) { + for (let j = 0; j < texSize; j++) { + const patchX = Math.floor(i / (texSize / numRows)); + const patchY = Math.floor(j / (texSize / numCols)); + const c = (patchX % 2 !== patchY % 2) ? 255 : 0; + myTexels[4 * i * texSize + 4 * j] = c; + myTexels[4 * i * texSize + 4 * j + 1] = c; + myTexels[4 * i * texSize + 4 * j + 2] = c; + myTexels[4 * i * texSize + 4 * j + 3] = 255; + } + } + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, myTexels); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); +} + +function createAdditionTexture(gl) { + const texSize = 64; + + const myTexels = new Uint8Array(4 * texSize * texSize); + for (let i = 0; i < texSize; i++) { + for (let j = 0; j < texSize; j++) { + const c = 127 + 127 * Math.sin(0.1 * i + j); + myTexels[4 * i * texSize + 4 * j] = c; + myTexels[4 * i * texSize + 4 * j + 1] = c; + myTexels[4 * i * texSize + 4 * j + 2] = c; + myTexels[4 * i * texSize + 4 * j + 3] = 255; + } + } + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, myTexels); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); +} + +function init() { + // Init + const canvas = document.getElementById('gl-canvas'); + const {width, height} = canvas; + const gl = setupWebGL(canvas); + if(!gl) { + console.error('WebGL isn\'t available'); + } + gl.viewport(0, 0, width, height); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.enable(gl.DEPTH_TEST); + const program = createProgram(gl, vertexShader, fragmentShader); + gl.useProgram(program); + + // Cube related constant + // 立方体点位置 + // v0----- v3 + // /| /| + // v1------v2| + // | | | | + // | |v4---|-|v7 + // |/ |/ + // v5------v6 + // 顺序为前后左右上下 + + const vertices = [ + // v0-v1-v2-v3-up + vec4(-0.5, 0.5, -0.5, 1), + vec4(-0.5, 0.5, 0.5, 1), + vec4(0.5, 0.5, 0.5, 1), + vec4(0.5, 0.5, -0.5, 1), + // v0-v4-v5-v1-left + vec4(-0.5, 0.5, -0.5, 1), + vec4(-0.5, -0.5, -0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + vec4(-0.5, 0.5, 0.5, 1), + // v1-v5-v6-v2-front + vec4(-0.5, 0.5, 0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(0.5, 0.5, 0.5, 1), + // v2-v6-v7-v3-right + vec4(0.5, 0.5, 0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(0.5, 0.5, -0.5, 1), + // v3-v7-v4-v0-back + vec4(0.5, 0.5, -0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(-0.5, -0.5, -0.5, 1), + vec4(-0.5, 0.5, -0.5, 1), + // v4-v7-v6-v5-bottom + vec4(-0.5, -0.5, -0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + ]; + + const colors = [ + // 黄色-up + vec4(1, 1, 0, 0.8), + vec4(1, 1, 0, 0.8), + vec4(1, 1, 0, 0.8), + vec4(1, 1, 0, 0.8), + // 绿色-left + vec4(0, 1, 0, 0.8), + vec4(0, 1, 0, 0.8), + vec4(0, 1, 0, 0.8), + vec4(0, 1, 0, 0.8), + // 蓝色-front + vec4(0, 0, 1, 0.8), + vec4(0, 0, 1, 0.8), + vec4(0, 0, 1, 0.8), + vec4(0, 0, 1, 0.8), + // 紫色-right + vec4(1, 0, 1, 0.8), + vec4(1, 0, 1, 0.8), + vec4(1, 0, 1, 0.8), + vec4(1, 0, 1, 0.8), + // 青色-back + vec4(0, 1, 1, 0.8), + vec4(0, 1, 1, 0.8), + vec4(0, 1, 1, 0.8), + vec4(0, 1, 1, 0.8), + // unknown-bottom + vec4(0.5, 0.5, 0.5, 0.8), + vec4(0.5, 0.5, 0.5, 0.8), + vec4(0.5, 0.5, 0.5, 0.8), + vec4(0.5, 0.5, 0.5, 0.8), + ]; + + // Create texures + const texCord = [ + vec2(0.0, 0.0), + vec2(0.0, 1.0), + vec2(1.0, 1.0), + vec2(1.0, 0.0), + ]; + + let textures = []; + new Array(6).fill(0).forEach(() => { + textures = [...texCord, ...textures]; + }); + + console.log(textures); + + // Create indexs + const indexs = [ + // up + 0, 1, 2, + 0, 2, 3, + // left + 4, 5, 6, + 4, 6, 7, + // font + 8, 9, 10, + 8, 10, 11, + // right + 12, 13, 14, + 12, 14, 15, + // back + 16, 17, 18, + 16, 18, 19, + // bottom + 20, 21, 22, + 20, 22, 23, + ]; + + // Camera related constant + let eye = vec4(0, 0, 2, 1); + const up = vec4(0, 1, 0, 0); + const at = vec4(0, 0, 0, 1); + + // Texture toogle + let isShowAdditionTexture = 0; + + // Load vertcies to buffer + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(vertices), gl.STATIC_DRAW); + const vPosition = gl.getAttribLocation(program, 'vPosition'); + gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vPosition); + + // Load colors to buffer + const colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + console.log(pointsToBuffer(colors)); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(colors), gl.STATIC_DRAW); + const vColor = gl.getAttribLocation(program, 'vColor'); + gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vColor); + + // Load element index + const indexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indexs), gl.STATIC_DRAW); + + // Load textures + const textureBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer); + console.log(pointsToBuffer(textures)); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(textures), gl.STATIC_DRAW); + const vTexCoord = gl.getAttribLocation(program, 'vTexCoord'); + gl.vertexAttribPointer(vTexCoord, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vTexCoord); + + // Load model view matrix + let modelViewMatrix = mat4.create(); + mat4.lookAt(modelViewMatrix, eye, at, up); + const modelViewMatrixLoc = gl.getUniformLocation(program, 'modelViewMatrix'); + gl.uniformMatrix4fv(modelViewMatrixLoc, false, modelViewMatrix); + + // Load proejection matrix + let projectionMatrix = mat4.create(); + mat4.ortho(projectionMatrix, -5.0, 5.0, -5.0, 5.0, 0.5, 10); + const projectionMatrixLoc = gl.getUniformLocation(program, 'projectionMatrix'); + gl.uniformMatrix4fv(projectionMatrixLoc, false, projectionMatrix); + + // Create texture + gl.activeTexture(gl.TEXTURE0); + createTexture(gl); + gl.uniform1i(gl.getUniformLocation(program, 'texMap'), 0); + + gl.activeTexture(gl.TEXTURE1); + createAdditionTexture(gl); + gl.uniform1i(gl.getUniformLocation(program, 'addedTexMap'), 1); + + // Add event listener + const button = document.getElementById('textureButton'); + if (button) { + button.addEventListener('click', () => { + isShowAdditionTexture = !isShowAdditionTexture ? 1 : 0; + gl.uniform1i(gl.getUniformLocation(program, 'isAddedTexMap'), isShowAdditionTexture); + }) + } + + // Render function + let theta = 0.0; + const render = () => { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.drawElements(gl.TRIANGLES, indexs.length, gl.UNSIGNED_BYTE, 0); + requestAnimationFrame(render); + + // Update theta and model view Matrix + theta += 0.01; + if (theta > 2 * Math.PI) { + theta -= 2 * Math.PI; + } + + eye = mat4( + 2 * Math.cos(theta) * Math.sin(theta), + 2 * Math.sin(theta), + 2 * Math.cos(theta) * Math.cos(theta), + 1, + ); + mat4.lookAt(modelViewMatrix, eye, at, up); + gl.uniformMatrix4fv(modelViewMatrixLoc, false, modelViewMatrix); + } + + render(); +} + +init(); \ No newline at end of file diff --git a/chapter07/cube-texture/index.html b/chapter07/cube-texture/index.html new file mode 100644 index 0000000..b2b9bc7 --- /dev/null +++ b/chapter07/cube-texture/index.html @@ -0,0 +1,14 @@ + + + + + + + cube-texture + + + + + + + \ No newline at end of file diff --git a/chapter07/cube-texture/shader.frag b/chapter07/cube-texture/shader.frag new file mode 100644 index 0000000..caa173d --- /dev/null +++ b/chapter07/cube-texture/shader.frag @@ -0,0 +1,14 @@ +precision mediump float; +varying vec2 fTexCoord; +varying vec4 fColor; +uniform int isAddedTexMap; +uniform sampler2D texMap; +uniform sampler2D addedTexMap; + +void main() { + if (isAddedTexMap == 0) { + gl_FragColor = fColor * texture2D(texMap, fTexCoord); + } else { + gl_FragColor = fColor * texture2D(texMap, fTexCoord) * texture2D(addedTexMap, fTexCoord); + } +} diff --git a/chapter07/cube-texture/shader.vert b/chapter07/cube-texture/shader.vert new file mode 100644 index 0000000..5fa1a4b --- /dev/null +++ b/chapter07/cube-texture/shader.vert @@ -0,0 +1,14 @@ +attribute vec4 vPosition; +attribute vec4 vColor; +attribute vec2 vTexCoord; +varying vec4 fColor; +varying vec2 fTexCoord; + +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; + +void main() { + gl_Position = projectionMatrix * modelViewMatrix * vPosition; + fColor = vColor; + fTexCoord = vTexCoord; +} \ No newline at end of file diff --git a/chapter07/reflection-texture/app.js b/chapter07/reflection-texture/app.js new file mode 100644 index 0000000..9e04a8b --- /dev/null +++ b/chapter07/reflection-texture/app.js @@ -0,0 +1,213 @@ +import {createProgram, setupWebGL, pointsToBuffer} from 'GLHelper'; +import {vec2, vec4, mat4} from 'gl-matrix'; +import vertexShader from './shader.vert'; +import fragmentShader from './shader.frag'; + +function createTexture(gl) { + const red = new Uint8Array([255, 0, 0, 255]); + const green = new Uint8Array([0, 255, 0, 255]); + const blue = new Uint8Array([0, 0, 255, 255]); + const cyan = new Uint8Array([0, 255, 255, 255]); + const magenta = new Uint8Array([255, 0, 255, 255]); + const yellow = new Uint8Array([255, 255, 0, 255]); + + gl.activeTexture(gl.TEXTURE0); + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, red); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, green); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, blue); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, cyan); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, magenta); + gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, yellow); + gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST); +} + + +function init() { + // Init + const canvas = document.getElementById('gl-canvas'); + const {width, height} = canvas; + const gl = setupWebGL(canvas); + if(!gl) { + console.error('WebGL isn\'t available'); + } + gl.viewport(0, 0, width, height); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.enable(gl.DEPTH_TEST); + const program = createProgram(gl, vertexShader, fragmentShader); + gl.useProgram(program); + + // Cube related constant + // 立方体点位置 + // v0----- v3 + // /| /| + // v1------v2| + // | | | | + // | |v4---|-|v7 + // |/ |/ + // v5------v6 + // 顺序为前后左右上下 + + const vertices = [ + // v0-v1-v2-v3-up + vec4(-0.5, 0.5, -0.5, 1), + vec4(-0.5, 0.5, 0.5, 1), + vec4(0.5, 0.5, 0.5, 1), + vec4(0.5, 0.5, -0.5, 1), + // v0-v4-v5-v1-left + vec4(-0.5, 0.5, -0.5, 1), + vec4(-0.5, -0.5, -0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + vec4(-0.5, 0.5, 0.5, 1), + // v1-v5-v6-v2-front + vec4(-0.5, 0.5, 0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(0.5, 0.5, 0.5, 1), + // v2-v6-v7-v3-right + vec4(0.5, 0.5, 0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(0.5, 0.5, -0.5, 1), + // v3-v7-v4-v0-back + vec4(0.5, 0.5, -0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(-0.5, -0.5, -0.5, 1), + vec4(-0.5, 0.5, -0.5, 1), + // v4-v7-v6-v5-bottom + vec4(-0.5, -0.5, -0.5, 1), + vec4(0.5, -0.5, -0.5, 1), + vec4(0.5, -0.5, 0.5, 1), + vec4(-0.5, -0.5, 0.5, 1), + ]; + + const normals = [ + // up + vec4(0, 1, 0, 0), + vec4(0, 1, 0, 0), + vec4(0, 1, 0, 0), + vec4(0, 1, 0, 0), + // left + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + // font + vec4(0, 0, 1, 0), + vec4(0, 0, 1, 0), + vec4(0, 0, 1, 0), + vec4(0, 0, 1, 0), + // right + vec4(1, 0, 0, 0), + vec4(1, 0, 0, 0), + vec4(1, 0, 0, 0), + vec4(1, 0, 0, 0), + // back + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + vec4(-1, 0, 0, 0), + // bottom + vec4(0, -1, 0, 0), + vec4(0, -1, 0, 0), + vec4(0, -1, 0, 0), + vec4(0, -1, 0, 0), + ]; + + // Create indexs + const indexs = [ + // up + 0, 1, 2, + 0, 2, 3, + // left + 4, 5, 6, + 4, 6, 7, + // font + 8, 9, 10, + 8, 10, 11, + // right + 12, 13, 14, + 12, 14, 15, + // back + 16, 17, 18, + 16, 18, 19, + // bottom + 20, 21, 22, + 20, 22, 23, + ]; + + // Camera related constant + let eye = vec4(0, 0, 2, 1); + const up = vec4(0, 1, 0, 0); + const at = vec4(0, 0, 0, 1); + + // Load vertcies to buffer + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(vertices), gl.STATIC_DRAW); + const vPosition = gl.getAttribLocation(program, 'vPosition'); + gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vPosition); + + // Load normals to buffer + const normalsBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, normalsBuffer); + gl.bufferData(gl.ARRAY_BUFFER, pointsToBuffer(normals), gl.STATIC_DRAW); + const vNormals = gl.getAttribLocation(program, 'vNormals'); + gl.vertexAttribPointer(vNormals, 4, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(vNormals); + + // Load element index + const indexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indexs), gl.STATIC_DRAW); + + // Load model view matrix + let modelViewMatrix = mat4.create(); + mat4.lookAt(modelViewMatrix, eye, at, up); + const modelViewMatrixLoc = gl.getUniformLocation(program, 'modelViewMatrix'); + gl.uniformMatrix4fv(modelViewMatrixLoc, false, modelViewMatrix); + + // Load proejection matrix + let projectionMatrix = mat4.create(); + mat4.ortho(projectionMatrix, -5.0, 5.0, -5.0, 5.0, 0.5, 10); + const projectionMatrixLoc = gl.getUniformLocation(program, 'projectionMatrix'); + gl.uniformMatrix4fv(projectionMatrixLoc, false, projectionMatrix); + + // Load eye position + gl.uniform4fv(gl.getUniformLocation(program, 'eyePosition'), eye); + + // Create texture + gl.activeTexture(gl.TEXTURE0); + createTexture(gl); + gl.uniform1i(gl.getUniformLocation(program, 'texMap'), 0); + + // Render function + let theta = 0.0; + const render = () => { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.drawElements(gl.TRIANGLES, indexs.length, gl.UNSIGNED_BYTE, 0); + requestAnimationFrame(render); + + // Update theta and model view Matrix + theta += 0.01; + if (theta > 2 * Math.PI) { + theta -= 2 * Math.PI; + } + + eye = mat4( + 2 * Math.cos(theta) * Math.sin(theta), + 2 * Math.sin(theta), + 2 * Math.cos(theta) * Math.cos(theta), + 1, + ); + mat4.lookAt(modelViewMatrix, eye, at, up); + gl.uniformMatrix4fv(modelViewMatrixLoc, false, modelViewMatrix); + gl.uniform4fv(gl.getUniformLocation(program, 'eyePosition'), eye); + } + + render(); +} + +init(); \ No newline at end of file diff --git a/chapter07/reflection-texture/index.html b/chapter07/reflection-texture/index.html new file mode 100644 index 0000000..59ec80d --- /dev/null +++ b/chapter07/reflection-texture/index.html @@ -0,0 +1,13 @@ + + + + + + + reflection-texture + + + + + + \ No newline at end of file diff --git a/chapter07/reflection-texture/shader.frag b/chapter07/reflection-texture/shader.frag new file mode 100644 index 0000000..40424ce --- /dev/null +++ b/chapter07/reflection-texture/shader.frag @@ -0,0 +1,8 @@ +precision mediump float; +varying vec3 transformedNormals; +uniform samplerCube texMap; + +void main() { + vec4 texColor = textureCube(texMap, transformedNormals); + gl_FragColor = texColor; +} diff --git a/chapter07/reflection-texture/shader.vert b/chapter07/reflection-texture/shader.vert new file mode 100644 index 0000000..4ffd44f --- /dev/null +++ b/chapter07/reflection-texture/shader.vert @@ -0,0 +1,12 @@ +attribute vec4 vPosition; +attribute vec4 vNormals; +varying vec3 transformedNormals; +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; +uniform vec4 eyePosition; + +void main() { + gl_Position = projectionMatrix * modelViewMatrix * vPosition; + vec3 modelViewedNormals = (modelViewMatrix * vNormals).xyz; + transformedNormals = reflect(eyePosition.xyz, modelViewedNormals); +} \ No newline at end of file