show_texture.html
<!DOCTYPE html>
<html>
<head>
<title>hello web gl</title>
<script type="text/javascript" src="js/hi.js"></script>
</head>
<body>
<div>
<canvas id="canvas" width="200px" height="200px"></canvas>
</div>
</body>
</html>
hi_server.go
package main
import(
"net/http"
)
func main(){
http.Handle("/", http.FileServer(http.Dir("./")))
http.ListenAndServe(":8123", nil)
}
hi.js
/**
* Created by houbingshuai on 2016/12/3.
*/
window.onload = function () {
//顶点着色器程序
let VSHADER_SOURCE =
"attribute vec4 a_Position;" +
"attribute vec2 a_TextCoord;" + // 接受纹理坐标
"varying vec2 v_TexCoord;" + // 传递纹理坐标
"void main() {" +
//设置坐标
"gl_Position = a_Position; " +
"v_TexCoord = a_TextCoord; " + // 设置纹理坐标
"} ";
//片元着色器
let FSHADER_SOURCE =
"precision mediump float;" + //需要声明浮点数精度,否则报错No precision specified for (float)
"uniform sampler2D u_Sampler;" + // 取样器
"varying vec2 v_TexCoord;" + // 接受纹理坐标
"void main() {" +
//设置颜色
"gl_FragColor = texture2D(u_Sampler, v_TexCoord);" + // 设置颜色
"}";
//获取canvas元素
let canvas = document.getElementById('canvas');
//获取绘制二维上下文
let gl = canvas.getContext('webgl');
if (!gl) {
console.log("Failed");
return;
}
//编译着色器
let vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, VSHADER_SOURCE);
gl.compileShader(vertShader);
let fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, FSHADER_SOURCE);
gl.compileShader(fragShader);
//合并程序
let shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
//不加"precision mediump float;" ,则useProgram函数调用会出错。
gl.useProgram(shaderProgram);
//获取坐标点
let a_Position = gl.getAttribLocation(shaderProgram, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
}
//绘制一个点
initBuffers(gl, shaderProgram, 4);
// 清除指定<画布>的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清空 <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
initTexture(gl, shaderProgram);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
// Fill the buffer with the values that define multi pt.
function initBuffers(gl, shaderProgram) {
//顶点坐标和纹理坐标
var vertices = new Float32Array([
-0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, 0.0, 0.0,
0.5, 0.5, 1.0, 1.0,
0.5, -0.5, 1.0, 0.0
]);
//获取单个字节
let FSIZE = vertices.BYTES_PER_ELEMENT;
//创建缓冲区对象
let vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log("Failed to create the butter object");
return -1;
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//向缓冲区写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
//获取坐标点
let a_Position = gl.getAttribLocation(shaderProgram, 'a_Position');
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
//连接a_Position变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);
//获取纹理坐标点
let a_TextCoord = gl.getAttribLocation(shaderProgram, 'a_TextCoord');
//
gl.vertexAttribPointer(a_TextCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
//连接a_TextCoord变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_TextCoord);
}
function initTexture(gl, shaderProgram, n) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Because images have to be download over the internet
// they might take a moment until they are ready.
// Until then put a single pixel in the texture so we can
// use it immediately. When the image has finished downloading
// we'll update the texture with the contents of the image.
const level = 0;
const internalFormat = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
width, height, border, srcFormat, srcType,
pixel);
//创建image对象
var image = new Image();
//加载纹理
image.onload = function(){ loadTexture(gl, texture, image, shaderProgram); };
// 浏览器开始加载图片 注意:一定是2^mx2^n尺寸的图片
image.src = "./TexturedQuad/shan.png";
}
function loadTexture(gl, texture, image, shaderProgram) {
const level = 0;
const internalFormat = gl.RGBA;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
//gl.activeTexture(gl.TEXTURE0);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
srcFormat, srcType, image);
/*
//must write the following code, otherwize report the following warning.
[.Offscreen-For-WebGL-08413F30]RENDER WARNING: texture bound to texture unit 0 is not renderable.
It maybe non-power-of-2 and have incompatible texture filtering.
*/
// WebGL1 has different requirements for power of 2 images
// vs non power of 2 images so check if the image is a
// power of 2 in both dimensions.
if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
// Yes, it's a power of 2. Generate mips.
gl.generateMipmap(gl.TEXTURE_2D);
} else {
// No, it's not a power of 2. Turn of mips and set
// wrapping to clamp to edge
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
var u_Sampler = gl.getUniformLocation(shaderProgram, 'u_Sampler');
//6.将0号纹理图像传递给着色器
gl.uniform1i(u_Sampler, 0);
// 清空 <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
//must write the following code, because this function is called when image is loaded successful.
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function isPowerOf2(value) {
return (value & (value - 1)) == 0;
}
参考资料
http://www.cnblogs.com/bsman/p/6196871.html
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/generateMipmap