Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • master
1 result

Target

Select target project
  • hwan/webgl-tutorial
  • eeunga/webgl-tutorial
  • Jingihong/webgl-tutorial
3 results
Select Git revision
  • master
1 result
Show changes
Commits on Source (1)
Showing
with 8741 additions and 0 deletions
MIT License
Copyright (c) 2020 함형규
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# WebGL Tutorial
### How to make Transparent WebGL canvas?
## Author
201321101 함형규
## Project summary
How to make transparent WebGL canvas?<br>
This project explains the `clearColor` and `clear` functions that can make WebGL's canvas workspace transparent, and explains the difference between the way of making the canvas element's background color transparent with CSS style.<br>
It also describes the CSS position attributes(`position`, `z-index`), which places the canvas element and other HTML elements in the same location.<br>
And now, you can create web page contents by combining HTML elements and WebGL canvas.
## Transparent WebGL canvas
You can make the background of a WebGL workspace transparent using the `clearColor` function and the `clear` function.
The `clearColor` function of the WebGL API specifies the color values used when clearing color buffers. The values are clamped between 0 and 1.
```javascript
gl.clearColor(r, g, b, a);
```
After that, use color value with `clear` function.<br>The `clear` function of the WebGL API clears buffers to preset values.
The preset values can be set by clearColor(), clearDepth() or clearStencil().
By using `gl.COLOR_BUFFER_BIT`, you can clear color buffer.
```javascript
gl.clear(gl.COLOR_BUFFER_BIT);
```
## Transparent canvas background color
You can also specify the background color of the canvas element itself using the `background-color` property of CSS styles. However, this is not related to WebGL, and is covered when WebGL clears the color buffer.
If the `background-color` of the canvas is opaque and the workspace cleared by WebGL is transparent, the `background-color` defined by CSS style will be overlaid.
```css
#canvas {
background-color: rgba(255, 255, 255, 1.0);
}
```
## CSS position
The CSS `position` attribute defines how the HTML element is positioned within the web page. You can lay out the page using various attribute values.
- `Static`: default that every element gets — it just means "put the element into its normal position in the document layout flow — nothing special to see here."
- `relative`: This is very similar to static positioning, except that once the positioned element has taken its place in the normal layout flow, you can then modify its final position, including making it overlap other elements on the page.
- `absolute`: the element can be positioned regardless of the parent element. It is not dependent on one level parent element, but is positioned depending on the element whose position is relative among the parent elements. If not, it depends on the body tag. Therefore, it is possible to place elements overlapping. In this case, it is determined by the value of the z-index that determines who the higher element is. And every HTML tag has its own default `z-index` value. this `z-index` value can be modified by css.
```css
#element {
position: 'absolute';
z-index: 1;
}
```
## How to use this page?
If you click the button, the Webgl canvas or HTML element will change to match the button's description. Enjoy!
![](https://i.imgur.com/x0HoiCr.png)
## License
MIT License
## Reference
- Project idea inspired from [student2019](https://git.ajou.ac.kr/hwan/webgl-tutorial/-/tree/master/student2019/201520510)
- WebGL code base from [class](https://git.ajou.ac.kr/hwan/cg_course/-/tree/master/WebGL/BOX)
- [MDN WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext)
- [MDN CSS position](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Positioning)
<html>
<head>
<title>WebGL Tutotial</title>
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="script.js"></script>
</head>
<body onload="main()">
<div class="header">
<header>
<h1 id="title">WebGL Tutorial</h1>
<h2 id="sub-title">How to make Transparent WebGL canvas?</h2>
</header>
</div>
<div class="description">
<div class="description-box summary">
<h3>Summary</h3>
<div>이 페이지는 WebGL의 canvas 작업 영역을 투명하게 만드는 clearColor함수와 clear함수에 대해 설명하고, css 스타일로 canvas element의 background color를 투명하게 만드는 방식과의 차이를 설명합니다. <br>또한 canvas element의 뒤에 HTML element를 위치하게 하는 css position 속성에 대해 설명하며, 이와 투명한 canvas를 함께 활용해 canvas보다 뒤에 위치한 HTML element와 WebGL 그림을 겹쳐서 화면에 표시하는 것을 보여줍니다.<br>자세한 report는 git에서 확인할 수 있습니다.</div>
</div>
<div class="description-box">
<h3>gl.clearColor & gl.clear</h3>
<div>gl.clearColor로 WebGL의 color buffer를 지울 색상값을 정할 수 있습니다. RGBA값을 사용하며, Alpha값을 사용해 투명한 색을 지정할 수 있습니다.<br>gl.clear는 지정된 값으로 buffer를 지웁니다. gl.COLOR_BUFFER_BIT 인자를 사용해서 clearColor 함수로 지정한 color buffer의 값을 사용할 수 있습니다.</div>
</div>
<div class="description-box">
<h3>CSS background-color</h3>
<div>background-color 속성을 사용해서 canvas element 자체의 배경색을 투명하게 할 수도 있습니다. 하지만 WebGL color buffer와는 관련없는 canvas element 자체의 CSS 속성으로, WebGL의 color buffer clear가 수행되면 화면상에서 덮여질 영역입니다. </div>
</div>
<div class="description-box">
<h3>CSS position & z-index</h3>
<div>position속성으로 HTML element가 화면에 배치되는 방식을 결정할 수 있습니다. 값을 'absolute'로 설정하면, 부모 element와 관련 없이 해당 element를 위치시킬 수 있습니다. 때문에 element들을 겹쳐서 배치시키는 것이 가능합니다.<br>이렇게 겹쳐있을 경우, 더 위로 올라오는 element가 누가 될지는 z-index속성값으로 결정됩니다.<br>이 속성들을 투명한 WebGL canvas와 함께 사용하면, 일반적인 HTML element위에 배경이 투명한 WebGL 그림을 겹쳐서 표현하는게 가능해집니다.</div>
</div>
</div>
<div class="contents">
<canvas id="canvas"></canvas>
<div class="box">이 Box는 canvas보다 z-index가 *낮기* 때문에 더 *뒤*에 위치합니다.</div>
<div class="control-area">
<div class="control-box">
<button id="z-control-low">Box의 z-index를 canvas보다 낮게 설정</button>
<button id="z-control-high">Box의 z-index를 canvas보다 높게 설정</button>
</div>
<div class="control-box">
<button id="alpha-control-transparent">color buffer값을 투명하게 설정</button>
<button id="alpha-control-opaque">color buffer값을 초록색으로 설정</button>
</div>
<div class="control-box">
<button id="css-alpha-control-transparent">canvas의 css 배경값을 투명하게 설정</button>
<button id="css-alpha-control-opaque">canvas의 css 배경값을 파란색으로 설정</button>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
const $ = name => document.querySelector(name);
const glModel = {
colorBufferAlpha: 0.0,
gl: null,
testGLError(functionLastCalled) {
const gl = this.gl;
let lastError = gl.getError();
if (lastError != gl.NO_ERROR) {
alert(functionLastCalled + " failed (" + lastError + ")");
return false;
}
return true;
},
initialiseGL(canvas) {
try {
this.gl = canvas.getContext("webgl", { premultipliedAlpha: false }) || canvas.getContext("experimental-webgl");
this.gl.viewport(0, 0, canvas.width, canvas.height);
}
catch (e) {}
if (!this.gl) {
alert("Unable to initialise WebGL. Your browser may not support it");
return false;
}
return true;
},
initialiseBuffer() {
const gl = this.gl;
const vertexData = [
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0,
0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0,
-0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0
];
const elementData = [ 0, 1, 2, 3, 4, 5 ];
gl.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
gl.elementBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.elementBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elementData),gl.STATIC_DRAW);
return this.testGLError("initialiseBuffers");
},
initialiseShaders() {
const gl = this.gl;
let fragmentShaderSource = '\
varying highp vec4 color; \
void main(void) \
{ \
gl_FragColor = color; \
}';
gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(gl.fragShader, fragmentShaderSource);
gl.compileShader(gl.fragShader);
if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
return false;
}
let vertexShaderSource = '\
attribute highp vec4 myVertex; \
attribute highp vec4 myColor; \
varying highp vec4 color;\
void main(void) \
{ \
gl_Position = myVertex; \
color = myColor; \
}';
gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(gl.vertexShader, vertexShaderSource);
gl.compileShader(gl.vertexShader);
if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
return false;
}
gl.programObject = gl.createProgram();
gl.attachShader(gl.programObject, gl.fragShader);
gl.attachShader(gl.programObject, gl.vertexShader);
gl.bindAttribLocation(gl.programObject, 0, "myVertex");
gl.bindAttribLocation(gl.programObject, 1, "myColor");
gl.linkProgram(gl.programObject);
if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
return false;
}
gl.useProgram(gl.programObject);
return this.testGLError("initialiseShaders");
},
renderScene() {
const gl = this.gl;
gl.clearColor(0.0, 1.0, 0.0, this.colorBufferAlpha);
gl.clear(gl.COLOR_BUFFER_BIT);
if (!this.testGLError("gl.uniformMatrix4fv")) return false;
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
if (!this.testGLError("gl.vertexAttribPointer")) return false;
gl.drawArrays(gl.TRIANGLES, 0, 3);
if (!this.testGLError("gl.drawArrays")) return false;
return true;
},
setColorBufferAlphaTransparent() {
this.colorBufferAlpha = 0.0;
},
setColorBufferAlphaOpaque() {
this.colorBufferAlpha = 1.0;
}
}
const controlBox = {
init(glModel) {
this.initZIndexControl();
this.initColorBufferAlphaControl(glModel);
this.initCssAlphaControl();
},
initZIndexControl() {
const boxMsgLow = `이 Box는 canvas보다 z-index가 *낮기* 때문에 더 *뒤*에 위치합니다.`;
const boxMsgHigh = `이 Box는 canvas보다 z-index가 *높기* 때문에 더 *앞*에 위치합니다.`;
const box = $('.box');
$('#z-control-low').addEventListener('click', () => {
box.innerHTML = boxMsgLow;
box.style.zIndex = 0;
});
$('#z-control-high').addEventListener('click', () => {
box.innerHTML = boxMsgHigh;
box.style.zIndex = 2;
});
},
initColorBufferAlphaControl(glModel) {
$('#alpha-control-transparent').addEventListener('click', () => glModel.setColorBufferAlphaTransparent());
$('#alpha-control-opaque').addEventListener('click', () => glModel.setColorBufferAlphaOpaque());
},
initCssAlphaControl() {
$('#css-alpha-control-transparent').addEventListener(
'click', () => $('#canvas').style.backgroundColor = 'rgba(0, 0, 200, 0)');
$('#css-alpha-control-opaque').addEventListener(
'click', () => $('#canvas').style.backgroundColor = 'rgba(0, 0, 200, 1)');
}
}
function main() {
controlBox.init(glModel);
if (!glModel.initialiseGL($('#canvas'))) return;
if (!glModel.initialiseBuffer()) return;
if (!glModel.initialiseShaders()) return;
requestAnimFrame = (function () {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000, 60);
};
})();
(function renderLoop() {
if (glModel.renderScene()) requestAnimFrame(renderLoop);
})();
}
#canvas {
z-index: 1;
position: absolute;
width: 200px;
height: 200px;
border: none;
background-color: rgba(0, 0, 200, 0);
}
.box {
z-index: 0;
width: 200px;
height: 200px;
padding: 70px 5px 0 5px;
box-sizing: border-box;
background-color: orange;
text-align: center;
}
.header {
width: 100%;
height: 15vh;
padding: 2vh 0 2vh 0;
text-align: center;
margin-bottom: 20px;
min-width: 800px;
}
.description {
height: auto;
padding: 0 20vw 0 20vw;
min-width: 800px;
overflow: auto;
margin-bottom: 20px;
line-height: 1.5rem;
}
.contents {
display: flex;
height: auto;
padding: 0 20vw 0 20vw;
min-width: 800px;
}
.control-area {
display: flex;
flex-direction: column;
justify-content: space-around;
width: 600px;
box-sizing: border-box;
padding: 0 20px 0 20px;
}
.control-box {
display: flex;
justify-content: space-around;
}
button:hover {
cursor: pointer;
}
.description-box {
padding: 5px;
border: 1px solid olive;
border-radius: 8px;
margin-bottom: 10px;
}
.summary {
border-color: orange;
}
#title {
color: green;
}
#sub-title {
color: yellowgreen;
}
h3 {
margin-top: 5px;
margin-bottom: 5px;
}
\ No newline at end of file
student2020/better_project/201321113/GIF_change.gif

6.65 MiB

student2020/better_project/201321113/GIF_control.gif

3.27 MiB

student2020/better_project/201321113/GIF_delete.gif

2.34 MiB

student2020/better_project/201321113/GIF_light_color.gif

6.94 MiB

student2020/better_project/201321113/GIF_npot.gif

8.94 MiB

student2020/better_project/201321113/Mipmap.png

1.45 MiB

/* (CC-NC-BY) Junseop Lim 2020
WebGL 1.0 Tutorial - HTML image texture mapping & Phong Shading tutorial */
body {
font-family: Arial, Helvetica, sans-serif;
}
#content-title1 {
/* background-color: lightblue; */
color: black;
padding: 10px;
padding-left: 32px;
font-family: Arial, Helvetica, sans-serif;
text-align: left;
}
.paragraph {
padding-left: 34px;
font-family: Arial, Helvetica, sans-serif;
text-align: left;
}
.fa-icon-innter-text {
font-family: Arial, Helvetica, sans-serif;
font-size: 1.2rem;
font-weight: 400;
line-height: 1.5;
margin: 0;
text-align: left;
}
.toggle-btn {
width: 240px;
background-color: #a4a4a4;
/* Blue background */
border: none;
/* Remove borders */
color: white;
/* White text */
padding: 12px 16px;
/* Some padding */
font-size: 16px;
/* Set a font size */
cursor: pointer;
/* Mouse pointer on hover */
}
.toggle-btn:visited {
background-color: #757575;
}
.toggle-btn:hover {
background-color: #757575;
}
.toggle-btn:active {
background-color: #494949;
}
.button-table {
height: 150px;
padding: 0px;
padding-left: 20px;
vertical-align: text-top;
align-items: center;
}
.reflection-table {
padding: 0px;
padding-top: 80px;
vertical-align: top;
}
.light-color-table {
padding: 0px;
padding-top: 80px;
vertical-align: top;
text-align: left;
}
.slidecontainer {
text-align: right;
padding-bottom: 32px;
padding-right: 8px;
}
.slidecontainer-right {
text-align: left;
padding-bottom: 32px;
padding-left: 8px;
padding-right: 48px;
}
.parent {
display: flex;
}
.child {
flex: 1;
}
.control-table {
padding-left: 30px;
vertical-align: text-top;
}
.image-container {
background-image: url("keyboard_texture.jpg");
background-size: cover;
position: relative;
height: 400px;
}
.text {
background-color: white;
color: black;
font-size: 10vw;
font-weight: bold;
margin: 0 auto;
padding: 10px;
width: 50%;
text-align: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
mix-blend-mode: lighten;
}
html {
font-family: sans-serif;
}
form {
background: #a4a4a4;
margin: 8px auto;
border-radius: 3px;
padding: 18px;
border: 0px solid black;
}
form label,
form button {
background-color: #a4a4a4;
/* Blue background */
border: none;
/* Remove borders */
border-radius: 3px;
/* Set a border-radius */
color: white;
/* White text */
padding: 12px 16px;
/* Some padding */
font-size: 16px;
/* Set a font size */
cursor: pointer;
/* Mouse pointer on hover */
}
form label:hover,
form button:hover {
background-color: #757575;
color: white;
}
form label:active,
form button:active {
background-color: #3C3D3A;
color: white;
}
\ No newline at end of file
/* (CC-NC-BY) Junseop Lim 2020
WebGL 1.0 Tutorial - HTML image texture mapping & Phong Shading tutorial */
var gl;
var KaVal = 0.0;
var KdVal = 0.5;
var KsVal = 0.0;
var KshVal = 1.0;
var redVal = 1.0;
var greenVal = 1.0;
var blueVal = 1.0;
rotY = 0.0;
flag_npot = 0;
flag_animation = 1;
flag_delete_texture = 0;
function toggleAnimation() {
flag_animation ^= 1;
}
function toggleNPOT() {
flag_npot ^= 1;
if (flag_npot) {
alert('NPOT is enabled.');
} else {
alert('NPOT is disabled.\n\nOnly power of two textures are supported.');
}
}
function toggleDeleteTexture() {
flag_delete_texture ^= 1;
}
// Verify that the value is a power of two
function isPowerOfTwo(x) {
return (x & (x - 1)) == 0;
}
function testGLError(functionLastCalled) {
var lastError = gl.getError();
if (lastError != gl.NO_ERROR) {
alert(functionLastCalled + " failed (" + lastError + ")");
return false;
}
return true;
}
function initialiseGL(canvas) {
try {
// Try to grab the standard context. If it fails, fallback to experimental
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
gl.viewport(0, 0, canvas.width, canvas.height);
} catch (e) {}
if (!gl) {
alert("Unable to initialise WebGL. Your browser may not support it");
return false;
}
return true;
}
var vertexData = [
// Backface (RED/WHITE) -> z = 0.5
-0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0,
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, -1.0,
0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, -0.0, 0.0, 0.0, -1.0, -0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, -0.0, -0.0, 0.0, 0.0, -1.0, -0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, -0.0, 1.0, 0.0, 0.0, -1.0,
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, -1.0,
// Front (BLUE/WHITE) -> z = 0.5
-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0,
0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, -0.0, 0.0, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, 0.0, 1.0, -0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, -0.0, 1.0, 0.0, 0.0, 1.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0,
// LEFT (GREEN/WHITE) -> z = 0.5
-0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, -0.0, -0.0, -1.0, 0.0, 0.0, -0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 0.0, 0.0, -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 0.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, -0.0, -0.0, -1.0, 0.0, 0.0, -0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0, -0.0, 1.0, -1.0, 0.0, 0.0, -0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 0.0, 0.0,
// RIGHT (YELLOE/WHITE) -> z = 0.5
0.5, -0.5, -0.5, 1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 1.0, 0.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.5, 1.0, 1.0, 0.0, 1.0, -0.0, 1.0, 1.0, 0.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
// BOTTON (MAGENTA/WHITE) -> z = 0.5
-0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, -1.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, -1.0, 0.0, -0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, -1.0, 0.0, -0.5, -0.5, 0.5, 1.0, 0.0, 1.0, 1.0, -0.0, 1.0, 0.0, -1.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,
// TOP (CYAN/WHITE) -> z = 0.5
-0.5, 0.5, -0.5, 0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0,
0.5, 0.5, -0.5, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, 0.5, -0.5, 0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 0.0, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0, -0.0, 1.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0
];
function initialiseBuffer() {
gl.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
var image = new Image();
image.src = "sunshine_1024.jpg";
image.addEventListener('load', function() {
// Now that the image has loaded make copy it to the texture.
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
if (!flag_npot) {
gl.generateMipmap(gl.TEXTURE_2D);
}
});
const selectImage = document.getElementById('userImage');
selectImage.addEventListener('change', function() {
image.src = document.getElementById('userImage').files[0].name;
image.onload = function() {
// if image's width and height is not power of two, show the alert and restart the page.
if (!flag_npot && (!isPowerOfTwo(this.width) || !isPowerOfTwo(this.height))) {
alert('Your image size is ' + this.width + ' × ' + this.height + ' pixels.' +
'\n\nOpenGL ES 2.0 and WebGL have only limited NPOT support.' +
'\n\nPlease upload an image that meets the criteria.');
location.reload(true);
}
}
});
return testGLError("initialiseBuffers and texture initialize");
}
function initialiseShaders() {
var fragmentShaderSource = '\
precision mediump float;\
varying highp vec4 color; \
varying mediump vec2 texCoord;\
varying highp vec3 v,n; \
uniform sampler2D sampler2d;\
uniform float Ka;\
uniform float Kd;\
uniform float Ks;\
uniform float Ksh;\
uniform float red;\
uniform float green;\
uniform float blue;\
void main(void) \
{ \
highp vec3 L, E, R; \
highp vec3 light; \
highp vec4 light_color; \
highp float dist;\
highp vec4 diffuse; \
highp vec4 specular;\
highp vec4 specular_color;\
light = vec3(1.0, 1.0, +2.8); \
light_color = vec4 (red, green, blue, 1.0); \
specular_color = vec4 (1.0, 1.0, 1.0, 1.0); \
L = normalize(light - v);\
E = normalize(-v);\
R = normalize(-reflect(L, n)); \
normalize(light); \
dist = distance(v, light); \
dist = 2.0 / (dist*dist); \
diffuse = light_color * dist * max(dot(light, n), 0.0); \
specular = specular_color * pow(max(dot(R,E), 0.05), Ksh); \
gl_FragColor = Ka * color + Kd*diffuse + Ks*specular + texture2D(sampler2d, texCoord); \
gl_FragColor.a = 1.0; \
}';
gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(gl.fragShader, fragmentShaderSource);
gl.compileShader(gl.fragShader);
// Check if compilation succeeded
if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
return false;
}
// Vertex shader code
var vertexShaderSource = '\
attribute highp vec4 myVertex; \
attribute highp vec4 myColor; \
attribute highp vec2 myUV; \
attribute highp vec3 myNormal; \
uniform mediump mat4 vmMat; \
uniform mediump mat4 pMat; \
uniform mediump mat4 normalMat; \
varying highp vec4 color;\
varying mediump vec2 texCoord;\
varying highp vec3 v; \
varying highp vec3 n; \
void main(void) \
{ \
n = vec3(normalMat * vec4(myNormal, 1.0)); \
normalize(n); \
v = vec3(vmMat * myVertex); \
gl_Position = pMat * vec4(v, 1.0); \
color = myColor ; \
texCoord = myUV*1.0; \
}';
gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(gl.vertexShader, vertexShaderSource);
gl.compileShader(gl.vertexShader);
// Check if compilation succeeded
if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
return false;
}
// Create the shader program
gl.programObject = gl.createProgram();
// Attach the fragment and vertex shaders to it
gl.attachShader(gl.programObject, gl.fragShader);
gl.attachShader(gl.programObject, gl.vertexShader);
// Bind the custom vertex attribute "myVertex" to location 0
gl.bindAttribLocation(gl.programObject, 0, "myVertex");
gl.bindAttribLocation(gl.programObject, 1, "myColor");
gl.bindAttribLocation(gl.programObject, 2, "myUV");
gl.bindAttribLocation(gl.programObject, 3, "myNormal");
// Link the program
gl.linkProgram(gl.programObject);
// Check if linking succeeded in a similar way we checked for compilation errors
if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
return false;
}
gl.useProgram(gl.programObject);
return testGLError("initialiseShaders");
}
function renderScene() {
var vmMat = [];
var pMat = [];
var normalMat = [];
var vmMatLocation = gl.getUniformLocation(gl.programObject, "vmMat");
var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
var normalMatLocation = gl.getUniformLocation(gl.programObject, "normalMat");
if (flag_npot) {
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);
} else if (!flag_npot && flag_delete_texture) {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
}
if (flag_animation) {
rotY += 0.01;
}
if (flag_delete_texture) {
// remove current texture by binding null texture
gl.bindTexture(gl.TEXTURE_2D, null);
alert('Texture image has been deleted.');
flag_delete_texture = 0;
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0); // Added for depth Test
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Added for depth Test
gl.enable(gl.DEPTH_TEST); // Added for depth Test
mat4.lookAt(vmMat, [0.0, 0.0, 2.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
mat4.rotateY(vmMat, vmMat, rotY);
mat4.rotateX(vmMat, vmMat, rotY * 2.2); // control rotation speed by multiplication
mat4.identity(pMat);
mat4.perspective(pMat, 3.14 / 3.0, 800.0 / 600.0, 0.5, 5);
mat4.invert(normalMat, vmMat);
mat4.transpose(normalMat, normalMat);
gl.uniformMatrix4fv(vmMatLocation, gl.FALSE, vmMat);
gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat);
gl.uniformMatrix4fv(normalMatLocation, gl.FALSE, normalMat);
var KaLoc = gl.getUniformLocation(gl.programObject, "Ka");
var KdLoc = gl.getUniformLocation(gl.programObject, "Kd");
var KsLoc = gl.getUniformLocation(gl.programObject, "Ks");
var KshLoc = gl.getUniformLocation(gl.programObject, "Ksh");
var redLoc = gl.getUniformLocation(gl.programObject, "red");
var greenLoc = gl.getUniformLocation(gl.programObject, "green");
var blueLoc = gl.getUniformLocation(gl.programObject, "blue");
if (KaLoc != -1) gl.uniform1f(KaLoc, KaVal);
if (KdLoc != -1) gl.uniform1f(KdLoc, KdVal);
if (KsLoc != -1) gl.uniform1f(KsLoc, KsVal);
if (KshLoc != -1) gl.uniform1f(KshLoc, KshVal);
if (redLoc != -1) gl.uniform1f(redLoc, redVal);
if (greenLoc != -1) gl.uniform1f(greenLoc, greenVal);
if (blueLoc != -1) gl.uniform1f(blueLoc, blueVal);
if (!testGLError("gl.uniformMatrix4fv")) {
return false;
}
gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 48, 0);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 48, 12);
gl.enableVertexAttribArray(2);
gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 48, 28);
gl.enableVertexAttribArray(3);
gl.vertexAttribPointer(3, 3, gl.FLOAT, gl.FALSE, 48, 36);
if (!testGLError("gl.vertexAttribPointer")) {
return false;
}
gl.drawArrays(gl.TRIANGLES, 0, 36);
// gl.drawArrays(gl.LINE_STRIP, 0, 36);
if (!testGLError("gl.drawArrays")) {
return false;
}
return true;
}
function main() {
var canvas = document.getElementById("texture-canvas");
if (!initialiseGL(canvas)) {
return;
}
if (!initialiseBuffer()) {
return;
}
if (!initialiseShaders()) {
return;
}
// renderScene();
// Render loop
requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000, 60);
};
})();
(function renderLoop() {
if (renderScene()) {
// Everything was successful, request that we redraw our scene again in the future
requestAnimFrame(renderLoop);
}
})();
}
\ No newline at end of file
This diff is collapsed.
<!-- (CC-NC-BY) Junseop Lim 2020 -->
<!-- WebGL 1.0 Tutorial - HTML image texture mapping & Phong Shading tutorial -->
<html>
<head>
<title>WebGL Tutorial</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" href="final-script.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.1/css/all.min.css">
<script type="text/javascript" src="gl-matrix.js">
</script>
<script>
window['mat4'] = glMatrix.mat4;
window['vec4'] = glMatrix.vec4;
window['vec3'] = glMatrix.vec4;
</script>
<script type="text/javascript" src="final-script.js">
</script>
</head>
<body onload="main()">
<div class="image-container">
<div class="text">TEXTURE</div>
</div>
<h1 id="content-title1">HTML image texture mapping & Phong Shading tutorial</h1>
<div class="paragraph">
<p>This page is tutorial for WebGL, Texture Mapping Using Images and Phong Shading Tutorial.</p>
<p>While OpenGL 2.0 and later for the desktop offer full support for non-power-of-two (NPOT) textures, OpenGL ES 2.0 and WebGL have only limited NPOT support.</p>
<p>In this tutorial, you will understand how to mapping texture and restrictions of using NPOT in WebGL. You can also understand about Phong shading briefly.</p><br>
<p><strong>Note:</strong> If you are running this locally you'll need a simple web server to allow WebGL to load the images. See <a href="https://webglfundamentals.org/webgl/lessons/webgl-setup-and-installation.html" target="_blank">here</a> for
how to setup one up in couple of minutes.</p> <br> <br>
</div>
<table class="project-table" align="center">
<thead>
<tr>
<th class="render-table" rowspan="2">
<div align="center">
<canvas id="texture-canvas" style="border: none;" width="800" height="600"></canvas>
</div>
</th>
<th class="button-table" colspan="2">
<form>
<label align="left" for="userImage"><i class="fa fa-file-image"><span class="fa-icon-innter-text">&ensp;Choose images to upload (PNG, JPG)</span></i></label>
<input type="file" id="userImage" accept=".jpg, .jpeg, .png">
</form>
<div class="parent">
<div class="child" style="margin-right: 8px;">
<button class="toggle-btn" onclick="toggleAnimation()"><i class="fa fa-sync"><span class="fa-icon-innter-text">&ensp;Toggle Animation</span></i></button>
</div>
<div class="child" style="margin-right: 8px;">
<button class="toggle-btn" onclick="toggleNPOT()"><i class="fa fa-laptop-code"><span class="fa-icon-innter-text">&ensp;Toggle NPOT</span></i></button>
</div>
<div class="child">
<button class="toggle-btn" onclick="toggleDeleteTexture()"><i class="fa fa-trash-alt"><span class="fa-icon-innter-text">&ensp;Delete Texture Image</span></i></button>
</div>
</div>
</th>
</tr>
<tr>
<td class="reflection-table">
<div class="slidecontainer">
Ambient Reflection&ensp;<span id="Ka"></span>
<input type="range" style="vertical-align: -3px;" min="0" max="100" value="0" id="KaSlider">
</div>
<script>
var slider = document.getElementById("KaSlider");
var output = document.getElementById("Ka");
slider.oninput = function() {
KaVal = document.getElementById("KaSlider").value / 100;
}
</script>
<div class="slidecontainer">
Diffuse Reflection&ensp;<span id="Kd"></span>
<input type="range" style="vertical-align: -3px;" min="0" max="100" value="50" id="KdSlider">
</div>
<script>
var slider = document.getElementById("KdSlider");
var output = document.getElementById("Kd");
slider.oninput = function() {
KdVal = document.getElementById("KdSlider").value / 100;
}
</script>
<div class="slidecontainer">
Specular Reflection&ensp;<span id="Ks"></span>
<input type="range" style="vertical-align: -3px;" min="0" max="100" value="0" id="KsSlider">
</div>
<script>
var slider = document.getElementById("KsSlider");
var output = document.getElementById("Ks");
slider.oninput = function() {
KsVal = document.getElementById("KsSlider").value / 100;
}
</script>
<div class="slidecontainer">
Shininess&ensp;<span id="Ksh"></span>
<input type="range" style="vertical-align: -3px;" min="100" max="10000" value="1" id="KshSlider">
</div>
<script>
var slider = document.getElementById("KshSlider");
var output = document.getElementById("Ksh");
slider.oninput = function() {
KshVal = document.getElementById("KshSlider").value / 100;
}
</script>
</td>
<td class="light-color-table">
<div class="slidecontainer-right">
<span id="red"></span>
<input type="range" style="vertical-align: -3px;" min="0" max="100" value="100" id="redSlider">&ensp;Red Light
</div>
<script>
var slider = document.getElementById("redSlider");
var output = document.getElementById("red");
slider.oninput = function() {
redVal = document.getElementById("redSlider").value / 100;
}
</script>
<div class="slidecontainer-right">
<span id="green"></span>
<input type="range" style="vertical-align: -3px;" min="0" max="100" value="100" id="greenSlider">&ensp;Green Light
</div>
<script>
var slider = document.getElementById("greenSlider");
var output = document.getElementById("green");
slider.oninput = function() {
greenVal = document.getElementById("greenSlider").value / 100;
}
</script>
<div class="slidecontainer-right">
<span id="blue"></span>
<input type="range" style="vertical-align: -3px;" min="0" max="100" value="100" id="blueSlider"> &ensp;Blue Light
</div>
<script>
var slider = document.getElementById("blueSlider");
var output = document.getElementById("blue");
slider.oninput = function() {
blueVal = document.getElementById("blueSlider").value / 100;
}
</script>
</td>
</tr>
</thead>
</table>
<br>
<br>
<br>
</body>
</html>
\ No newline at end of file
student2020/better_project/201321113/keyboard_1024.jpg

752 KiB

student2020/better_project/201321113/keyboard_texture.jpg

1.03 MiB

Image diff could not be displayed: it is too large. Options to address this: view the blob.
student2020/better_project/201321113/npot_landscape_02.jpg

1.37 MiB

student2020/better_project/201321113/phong_shading.png

53.2 KiB