ç°å¨æä»¬å·²ç»å建好äºä¸ä¸ªå¯ä»¥æè½¬ç 3D çç«æ¹ä½ï¼æ¥ä¸æ¥æ¯æ¶å使ç¨è´´å¾æ¥ä»£æ¿æ¯ä¸ªé¢çåä¸çé¢è²äºã
å 载纹çé¦å å å ¥å 载纹çç代ç ãç°å¨æä»¬åªä½¿ç¨ä¸å¼ åä¸ç纹çè´´å°ç«æ¹ä½ç 6 个é¢ä¸ï¼ä½æ¯åæ ·çæ¹æ³å¯ä»¥ç¨æ¥å è½½ä»»ææ°éç纹çè´´å¾ã
夿³¨ï¼ å¼å¾æ³¨æçä¸ç¹æ¯å¯¹çº¹ççå è½½åæ ·éè¦éµå¾ªè·¨å访é®è§åï¼ä¹å°±æ¯è¯´ä½ åªè½ä»å 许跨å访é®çç½åå è½½ä½ éè¦ç纹çãè§ä¸æ¹è·¨å纹çå°è以äºè§£è¯¦æ ã
夿³¨ï¼ å¨ä½ çâwebgl-demo.jsâèæ¬ä¸æ·»å ä¸é¢çä¸¤ä¸ªå½æ°ï¼
//
// Initialize a texture and load an image.
// When the image finished loading copy it into the texture.
//
function loadTexture(gl, url) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Because images have to be downloaded 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,
);
const image = new Image();
image.onload = () => {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
srcFormat,
srcType,
image,
);
// 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 off 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);
}
};
image.src = url;
return texture;
}
function isPowerOf2(value) {
return (value & (value - 1)) === 0;
}
彿° loadTexture()
é¦å
è°ç¨ WebGL ç createTexture()
彿°æ¥å建ä¸ä¸ª WebGL 纹ç对象 textureãæ¥ä¸æ¥ä½¿ç¨ texImage2D()
以ä¸ä¼ ä¸ä¸ªèè²çåç´ ç¹ãè¿æ ·æä»¬å°±å¯ä»¥å¨å¾çä¸è½½å®æä¹å使ç¨è¿ä¸ªèè²ç纹çäºã
è¦ä»å¾çæä»¶å 载纹çï¼æ¥ä¸æ¥å建ä¸ä¸ª Image
对象ï¼å¹¶ä¸º src
设置æä»¬æ³è¦ç¨ä½çº¹ççå¾çç URLãæä»¬ä¸º image.onload
设置ç彿°ä¼å¨å¾çä¸è½½å®ææ¶è¢«è°ç¨ã飿¶æä»¬å次è°ç¨ texImage2D()
ï¼è¿æ¬¡æä»¬å°å¾çä½ä¸ºçº¹ççæ°æ®æºãä¹åï¼æä»¬æ ¹æ®ä¸è½½çå¾åå¨ä¸¤ä¸ªç»´åº¦ä¸æ¯å¦ä¸º 2 ç广¥è®¾ç½®çº¹ççè¿æ»¤ï¼filterï¼åå¹³éºï¼wrapï¼ã
WebGL1 ä¸ï¼å¯¹äºé 2 çå¹çº¹çåªè½ä½¿ç¨ NEAREST
å LINEAR
è¿æ»¤ï¼ä¸ä¸ä¼çæè´´å¾ãæ¤å¤ï¼å¹³éºæ¨¡å¼ä¹å¿
须设置为 CLAMP_TO_EDGE
ãå¦ä¸æ¹é¢ï¼å¦æçº¹çå¨ä¸¤ä¸ªç»´åº¦ä¸é½æ¯ 2 çå¹ï¼é£ä¹ WebGL å°±å¯ä»¥ä½¿ç¨æ´é«è´¨éçè¿æ»¤ï¼å¯ä»¥ä½¿ç¨è´´å¾ï¼è¿è½å¤å°å¹³éºæ¨¡å¼è®¾ç½®ä¸º REPEAT
æ MIRRORED_REPEAT
ã
使ç¨éå¤çº¹ç寻åçä¸ä¸ªä¾åå°±æ¯ä½¿ç¨ä¸å¼ ç åççº¹çæ¥å¹³éºæ»¡ä¸é¢å¢å£ã
å¤çº§æ¸è¿çº¹çå纹çåæ éå¤å¯ä»¥éè¿è°ç¨ texParameteri()
æ¥ç¦ç¨ï¼å½ç¶é¦å
ä½ å·²ç»éè¿è°ç¨ bindTexture()
ç»å®è¿çº¹çäºãè¿æ ·è½ç¶å·²ç»å¯ä»¥ä½¿ç¨é 2 çå¹çº¹çäºï¼ä½æ¯ä½ å°æ æ³ä½¿ç¨å¤çº§æ¸è¿çº¹çï¼çº¹çåæ å
è£
ï¼çº¹çåæ éå¤ï¼è䏿 æ³æ§å¶è®¾å¤å¦ä½å¤çä½ ç纹çã
// gl.NEAREST is also allowed, instead of gl.LINEAR, as neither mipmap.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// Prevents s-coordinate wrapping (repeating).
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// Prevents t-coordinate wrapping (repeating).
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
ç°å¨ï¼å½ä½¿ç¨ä»¥ä¸åæ°æ¶ï¼å ¼å®¹ WebGL ç设å¤å°±ä¼èªå¨åå¾å¯ä»¥ä½¿ç¨ä»»ä½å辨çç纹çï¼å½ç¶è¿è¦èèåç´ ä¸éï¼ã妿ä¸ä½¿ç¨ä¸é¢è¿äºåæ°çè¯ï¼ä»»ä½é 2 çå¹çº¹ç使ç¨é½ä¼å¤±è´¥ç¶åè¿åä¸å¼ 纯é»å¾çã
为äºå è½½å¾åï¼å¨æä»¬ç main()
彿°ä¸æ·»å 对 loadTexture()
彿°çè°ç¨ãè¿å¯ä»¥å¨ initBuffers(gl)
è°ç¨ä¹åæ·»å ã
ä½éè¦æ³¨æçæ¯ï¼æµè§å¨ä¼ä»å è½½çå¾å䏿ä»å·¦ä¸è§å¼å§çèªä¸èä¸é¡ºåºå¤å¶åç´ ï¼è WebGL éè¦æèªä¸èä¸ç顺åºââä»å·¦ä¸è§å¼å§çåç´ é¡ºåºãï¼åè§ä¸ºä»ä¹æç WebGL çº¹çæ¯é¢ åçï¼ä»¥äºè§£è¯¦æ ãï¼
æä»¥ä¸ºäºé²æ¢æ¸²ææ¶å¾åçº¹çæ¹åéè¯¯ï¼æä»¬è¿éè¦è°ç¨ pixelStorei()
å¹¶å° gl.UNPACK_FLIP_Y_WEBGL
åæ°è®¾ç½®ä¸º true
ï¼ä»¥è°æ´åç´ é¡ºåºï¼ä½¿å
¶ç¿»è½¬æ WebGL éè¦çèªä¸èä¸é¡ºåºã
夿³¨ï¼ æ·»å ä¸é¢ç代ç å° main()
彿°ï¼ç´§è·å¨ initBuffers()
è°ç¨ä¹åï¼
// Load texture
const texture = loadTexture(gl, "cubetexture.png");
// Flip image pixels into the bottom-to-top order that WebGL expects.
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
夿³¨ï¼ æåï¼å° cubetexture.png ä¸è½½å°ä¸ JavaScript æä»¶ç¸åçæ¬å°ç®å½ã
æ å°çº¹çå°é¢ç°å¨ï¼çº¹çå·²å 载并åå¤å°±ç»ªãä½å¨æä»¬ä½¿ç¨å®ä¹åï¼æä»¬éè¦å»ºç«çº¹çåæ å°ç«æ¹ä½ä¸çé¢çé¡¶ç¹çæ å°ãè¿å°å代 initBuffers()
ä¸ä¸ºè®¾ç½®æ¯ä¸ªç«æ¹ä½é¢é¢è²èåå¨çææå
åç代ç ã
夿³¨ï¼ æ·»å è¿ä¸ªå½æ°å°âinit-buffer.jsâæ¨¡åï¼
function initTextureBuffer(gl) {
const textureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
const textureCoordinates = [
// Front
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
// Back
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
// Top
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
// Bottom
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
// Right
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
// Left
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
];
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(textureCoordinates),
gl.STATIC_DRAW,
);
return textureCoordBuffer;
}
é¦å ï¼è¿æ®µä»£ç å建äºä¸ä¸ª WebGL ç¼å²åºï¼æä»¬å°å¨å ¶ä¸å卿¯ä¸ªé¢ç纹çåæ ï¼ç¶åå°è¯¥ç¼å²åºç»å®ä¸ºå°è¦åå ¥çæ°ç»ã
textureCoordinates
æ°ç»å®ä¹å¥½äºä¸æ¯ä¸ªé¢ä¸çæ¯ä¸ªé¡¶ç¹ä¸ä¸å¯¹åºç纹çåæ ã请注æï¼çº¹çåæ çåå¼èå´åªè½ä» 0.0 å° 1.0ï¼æä»¥ä¸è®ºçº¹çè´´å¾çå®é
大尿¯å¤å°ï¼ä¸ºäºå®ç°çº¹çæ å°ï¼æä»¬è¦ä½¿ç¨ç纹çåæ åªè½è§èåå° 0.0 å° 1.0 çèå´å
ã
䏿¦æä»¬å»ºç«äºçº¹çæ å°æ°ç»ï¼æä»¬å°æ°ç»ä¼ éå°ç¼å²åºä¸ï¼è¿æ · WebGL å°±å¯ä»¥ä½¿ç¨è¯¥æ°æ®äºã
ç¶åæä»¬è¿åæ°çç¼å²åºã
æ¥ä¸æ¥ï¼æä»¬éè¦æ´æ° initBuffers()
æ¥å建并è¿å纹çåæ ç¼å²åºä»£æ¿é¢è²ç¼å²åºã
夿³¨ï¼ å¨âinit-buffers.jsâæ¨¡åç initBuffers()
彿°ä¸ï¼å° initColorBuffer()
çè°ç¨æ¿æ¢ä¸ºä¸é¢çè¿è¡ï¼
const textureCoordBuffer = initTextureBuffer(gl);
夿³¨ï¼ å¨âinit-buffers.jsâæ¨¡åç initBuffers()
彿°ä¸ï¼å° return
è¯å¥æ¿æ¢ä¸ºä»¥ä¸å
容ï¼
return {
position: positionBuffer,
textureCoord: textureCoordBuffer,
indices: indexBuffer,
};
æ´æ°çè²å¨
为äºä½¿ç¨çº¹çæ¥ä»£æ¿åä¸çé¢è²ï¼çè²å¨ç¨åºåçè²å¨ç¨åºçåå§å代ç é½éè¦è¿è¡ä¿®æ¹ã
é¡¶ç¹çè²å¨æä»¬éè¦æ´æ¹é¡¶ç¹çè²å¨ï¼ä½¿å ¶ä¸åè·åé¢è²æ°æ®ï¼èæ¯è·å纹çåæ æ°æ®ã
夿³¨ï¼ å¨ä½ ç main()
彿°ä¸æ´æ° vsSource
å®ä¹ï¼åè¿æ ·ï¼
const vsSource = `
attribute vec4 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
varying highp vec2 vTextureCoord;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
vTextureCoord = aTextureCoord;
}
`;
代ç çå ³é®æ´æ¹å¨äºä¸åè·åé¡¶ç¹é¢è²æ°æ®è½¬èè·åå设置纹çåæ æ°æ®ï¼è¿æ ·å°±è½æé¡¶ç¹ä¸å ¶å¯¹åºç纹çèç³»å¨ä¸èµ·äºã
çæ®µçè²å¨é£ä¹ç段çè²å¨ä¹è¦ç¸åºå°è¿è¡æ´æ¹ï¼åè¿æ ·æ´æ° main()
彿°ä¸ç fsSource
声æï¼
const fsSource = `
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
`;
ç°å¨ç代ç ä¸ä¼å使ç¨ä¸ä¸ªç®åçé¢è²å¼å¡«å çæ®µé¢è²ï¼ç段çé¢è²æ¯éè¿éæ ·å¨ä½¿ç¨æå¥½çæ å°æ¹å¼ä»çº¹çä¸çæ¯ä¸ä¸ªåç´ è®¡ç®åºæ¥çã
Attribute ä¸ Uniform ä½ç½®å 为æä»¬ä¿®æ¹äº attribute å¹¶æ·»å äº uniformï¼æä»¥æä»¬éè¦æ¥æ¾å®ä»¬çä½ç½®ã
夿³¨ï¼ å¨ä½ ç main()
彿°ä¸ï¼åè¿æ ·æ´æ° programInfo
çå®ä¹ï¼
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
textureCoord: gl.getAttribLocation(shaderProgram, "aTextureCoord"),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
uSampler: gl.getUniformLocation(shaderProgram, "uSampler"),
},
};
ç»å¶å
·ä½çº¹çè´´å¾çç«æ¹ä½
对 drawScene()
彿°çæ´æ¹å¾ç®åã
夿³¨ï¼ å¨âdraw-scene.jsâæ¨¡åç drawScene()
彿°ä¸æ·»å 以ä¸å½æ°ï¼
// åè¯ WebGL å¦ä½ä»ç¼å²åºä¸æå纹çåæ
function setTextureAttribute(gl, buffers, programInfo) {
const num = 2; // æ¯ä¸ªåæ ç± 2 个å¼ç»æ
const type = gl.FLOAT; // ç¼å²åºä¸çæ°æ®ä¸º 32 使µ®ç¹æ°
const normalize = false; // ä¸åæ ååå¤ç
const stride = 0; // ä»ä¸ä¸ªåæ å°ä¸ä¸ä¸ªåæ è¦è·åå¤å°åè
const offset = 0; // ä»ç¼å²åºå
ç第å 个åèå¼å§è·åæ°æ®
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
gl.vertexAttribPointer(
programInfo.attribLocations.textureCoord,
num,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);
}
夿³¨ï¼ å¨ä½ çâdraw-scene.jsâæ¨¡åç drawScene()
彿°ä¸ï¼ç¨ä¸é¢ä¸è¡æ¿æ¢ setColorAttribute()
çè°ç¨ï¼
setTextureAttribute(gl, buffers, programInfo);
ç¶åæ·»å ä»£ç æ¥æå®è¦æ å°å°é¢ç纹çã
夿³¨ï¼ å¨ä½ ç drawScene()
彿°ä¸ï¼å°±å¨å¯¹ gl.uniformMatrix4fv()
ç两次è°ç¨ä¹åï¼æ·»å 以ä¸ä»£ç ï¼
// Tell WebGL we want to affect texture unit 0
gl.activeTexture(gl.TEXTURE0);
// Bind the texture to texture unit 0
gl.bindTexture(gl.TEXTURE_2D, texture);
// Tell the shader we bound the texture to texture unit 0
gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
WebGL æä¾äºè³å° 8 个纹çåå
ï¼gl.TEXTURE0
æ¯ç¬¬ä¸ä¸ªãè¥æä»¬æ³è¦æ¹å第ä¸ä¸ªåå
ï¼æä»¬éè¦è°ç¨ bindTexture()
以å°çº¹çç»å®å°çº¹çåå
0 ç TEXTURE_2D
ç»å®ç¹ãç¶ååè¯çè²å¨æç¨çº¹çåå
0 ä½ä¸º uSampler
ã
æåï¼å¨ drawScene()
彿°ä¸æ·»å texture
ä½ä¸ºåæ°ï¼å
æ¬å®è¢«å®ä¹å被è°ç¨çå°æ¹ã
夿³¨ï¼ æ´æ°ä½ ç drawScene()
彿°çå®ä¹ä»¥æ·»å æ°çåæ°ï¼
function drawScene(gl, programInfo, buffers, texture, cubeRotation) {
夿³¨ï¼ æ´æ°ä½ ç main()
彿°ä¸è°ç¨ drawScene()
çå°æ¹ï¼
drawScene(gl, programInfo, buffers, texture, cubeRotation);
好ï¼ç°å¨æä»¬çç«æ¹ä½å°±ä¼åè¿æ ·æè½¬èµ·æ¥äºã
æ¥ç宿´ç¤ºä¾ä»£ç | 卿°çªå£éæå¼ç¤ºä¾
è·¨å纹çå è½½ WebGL 纹çåºè¯¥ä¹å¯ä»¥è¯´æ¯è·¨åè®¿é®æ§å¶éçä¸ä¸ªè¯é¢ã为äºå¨æä»¬çæ¾ç¤ºå 容é使ç¨å ¶ä»ååéç纹çå¾çï¼å 许跨å访é®ä¹æ¯è¦èèçãå¯ä»¥éè¿æ¥çHTTP è®¿é®æ§å¶æ¥è·åå°æ´å¤çç¸å ³ç»èã
è¿ç¯æç« ä¹å¯¹è·¨åå 载纹çå° WebGL ååºäºè§£éãèä¸æç« éé¢è¿å å«äºä¸ä¸ªä½¿ç¨çä¾åã
被污æè¿çï¼åªåï¼ç»å¸æ¯ä¸è½æ¿æ¥å½ä½ WebGL çº¹çæ¥ä½¿ç¨çã举个ä¾åæ¥è¯´ï¼å½æä¸å¼ è·¨åçå¾çç»å°ä¸ä¸ª 2D ç <canvas>
䏿¶ï¼è¿ä¸ªç»å¸å°±æ¯â被污æè¿çâã
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4