WebGL 利用FBO完成立方体贴图。
这篇主要记录WebGL的一些基本要点,顺便也学习下如何使用FBO与环境贴图。先看下效果图(需要支持WebGL,Chrome,火狐,IE11)。
主要实现过程如下,先用FBO输出当前环境在立方体纹理中,再画出当前立方体,最后画球,并且把FBO关联的纹理贴在这个球面上。
开始WebGL时,最好有些OpenGL基础,在前面讲Obj完善与MD2时,大家可能已经发现了,因为着色器的添加使用,原来一些Opengl大部分API已经没有使用。WebGL就和这差不多,大部分功能是着色器完成主要功能,记录下主要过程,大家可以比较下前面的,看看是不是很像,为了熟悉WebGL基本功能,本文没有利用比较完善的框架,只是用到一个帮助计算矩阵的框架(gl-matrix.js).
和使用OpenGL一样,我们要初始化使用环境,提取一些全局使用量。相关代码如下:
1 var gl;//WebGLRenderingContext
2 var cubeVBO;//Cube buffer ID
3 var sphereVBO;//球体VBO
4 var sphereEBO;//球体EBO
5 var cubeTexID;//立方体纹理ID
6 var fboBuffer;//桢缓存对象
7 var glCubeProgram;//立方体着色器应用
8 var glSphereProgram;//球体着色器应用
9
10 var fboWidth = 512;//桢缓存绑定纹理宽度
11 var fboHeight = 512;//桢缓存绑定纹理高度
12 var targets;//立方体贴图六个方向
13
14 var pMatrix = mat4.create();//透视矩阵
15 var vMatrix = mat4.create();//视图矩阵
16 var eyePos = vec3.fromValues(0.0, 1.0, 0.0);//眼睛位置
17 var eyeLookat = vec3.fromValues(0.0, -0.0, 0.0);//眼睛方向
18 var spherePos = vec3.fromValues(0.0, -0.0, 0.0);//球体位置
19 var canvanName;
20
21 function webGLStart(cName) {
22 canvanName = cName;
23 InitWebGL();
24 InitCubeShader();
25 InitSphereShader();
26 InitCubeBuffer();
27 InitSphereBuffer();
28 InitFBOCube();
29 //RenderFBO();
30 gl.clearColor(0.0, 0.0, 0.0, 1.0);
31 gl.enable(gl.DEPTH_TEST);
32 tick();
33 }
34
35 function InitWebGL() {
36 //var canvas = document.getElementById(canvanName);
37 InitGL(canvanName);
38 }
39
40 function InitGL(canvas) {
41 try {
42 //WebGLRenderingContext
43 gl = canvas.getContext("experimental-webgl");
44 gl.viewportWidth = canvas.width;
45 gl.viewportHeight = canvas.height;
46
47 targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
48 gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
49 gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
50 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
51 gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
52 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
53 } catch (e) { }
54 if (!gl) { alert("你的浏览器不支持WebGL"); }
55 }
初始化
在这里,我们初始化在网页中WebGL的上下方环境,并给出一系列初始化过程。下面先给出房间,也就是其中立方体的相关代码。
1 function InitCubeShader() {
2 //WebGLShader
3 var shader_vertex = GetShader("cubeshader-vs");
4 var shader_fragment = GetShader("cubeshader-fs");
5 //WebglCubeProgram
6 glCubeProgram = gl.createProgram();
7 gl.attachShader(glCubeProgram, shader_vertex);
8 gl.attachShader(glCubeProgram, shader_fragment);
9 gl.linkProgram(glCubeProgram);
10 if (!gl.getProgramParameter(glCubeProgram, gl.LINK_STATUS)) {
11 alert("Shader hava error.");
12 }
13 gl.useProgram(glCubeProgram);
14 glCubeProgram.positionAttribute = gl.getAttribLocation(glCubeProgram, "a_position");
15 glCubeProgram.normalAttribute = gl.getAttribLocation(glCubeProgram, "a_normal");
16 glCubeProgram.texCoordAttribute = gl.getAttribLocation(glCubeProgram, "a_texCoord");
17
18 glCubeProgram.view = gl.getUniformLocation(glCubeProgram, "view");
19 glCubeProgram.perspective = gl.getUniformLocation(glCubeProgram, "perspective");
20 }
21
22 function InitCubeBuffer() {
23 var cubeData = [
24 -10.0, -10.0, -10.0, 0.0, 0.0, -10.0, 1.0, 0.0,
25 -10.0, 10.0, -10.0, 0.0, 0.0, -10.0, 1.0, 1.0,
26 10.0, 10.0, -10.0, 0.0, 0.0, -10.0, 0.0, 1.0,
27
28 10.0, 10.0, -10.0, 0.0, 0.0, -10.0, 0.0, 1.0,
29 10.0, -10.0, -10.0, 0.0, 0.0, -10.0, 0.0, 0.0,
30 -10.0, -10.0, -10.0, 0.0, 0.0, -10.0, 1.0, 0.0,
31
32 -10.0, -10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0,
33 10.0, -10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 0.0,
34 10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 1.0,
35
36 10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 1.0,
37 -10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 1.0,
38 -10.0, -10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0,
39
40 -10.0, -10.0, -10.0, 0.0, -10.0, 0.0, 0.0, 0.0,
41 10.0, -10.0, -10.0, 0.0, -10.0, 0.0, 1.0, 0.0,
42 10.0, -10.0, 10.0, 0.0, -10.0, 0.0, 1.0, 1.0,
43
44 10.0, -10.0, 10.0, 0.0, -10.0, 0.0, 1.0, 1.0,
45 -10.0, -10.0, 10.0, 0.0, -10.0, 0.0, 0.0, 1.0,
46 -10.0, -10.0, -10.0, 0.0, -10.0, 0.0, 0.0, 0.0,
47
48 10.0, -10.0, -10.0, 10.0, 0.0, 0.0, 0.0, 0.0,
49 10.0, 10.0, -10.0, 10.0, 0.0, 0.0, 1.0, 0.0,
50 10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 1.0, 1.0,
51
52 10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 1.0, 1.0,
53 10.0, -10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 1.0,
54 10.0, -10.0, -10.0, 10.0, 0.0, 0.0, 0.0, 0.0,
55
56 10.0, 10.0, -10.0, 0.0, 10.0, 0.0, 0.0, 0.0,
57 -10.0, 10.0, -10.0, 0.0, 10.0, 0.0, 1.0, 0.0,
58 -10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 1.0, 1.0,
59
60 -10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 1.0, 1.0,
61 10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 0.0, 1.0,
62 10.0, 10.0, -10.0, 0.0, 10.0, 0.0, 0.0, 0.0,
63
64 -10.0, 10.0, -10.0, -10.0, 0.0, 0.0, 0.0, 0.0,
65 -10.0, -10.0, -10.0, -10.0, 0.0, 0.0, 1.0, 0.0,
66 -10.0, -10.0, 10.0, -10.0, 0.0, 0.0, 1.0, 1.0,
67
68 -10.0, -10.0, 10.0, -10.0, 0.0, 0.0, 1.0, 1.0,
69 -10.0, 10.0, 10.0, -10.0, 0.0, 0.0, 0.0, 1.0,
70 -10.0, 10.0, -10.0, -10.0, 0.0, 0.0, 0.0, 0.0,
71 ];
72 cubeVBO = gl.createBuffer();
73 gl.bindBuffer(gl.ARRAY_BUFFER, cubeVBO);
74 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeData), gl.STATIC_DRAW);
75 }
76
77 function RenderCube() {
78 gl.useProgram(glCubeProgram);
79 gl.bindBuffer(gl.ARRAY_BUFFER, cubeVBO);
80
81 gl.vertexAttribPointer(glCubeProgram.positionAttribute, 3, gl.FLOAT, false, 32, 0);
82 gl.enableVertexAttribArray(glCubeProgram.positionAttribute);
83
84 gl.vertexAttribPointer(glCubeProgram.normalAttribute, 3, gl.FLOAT, false, 32, 12);
85 gl.enableVertexAttribArray(glCubeProgram.normalAttribute);
86
87 gl.vertexAttribPointer(glCubeProgram.texCoordAttribute, 2, gl.FLOAT, false, 32, 24);
88 gl.enableVertexAttribArray(glCubeProgram.texCoordAttribute);
89
90 gl.uniformMatrix4fv(glCubeProgram.view, false, vMatrix);
91 gl.uniformMatrix4fv(glCubeProgram.perspective, false, pMatrix);
92
93 gl.drawArrays(gl.TRIANGLES, 0, 36);
94 }
立方体
上面的代码主要分为初始化立方体的着色器对象,初始化相关缓存,然后绘制立方体,可以说在Opengl中,如果用着色器来画,过程也是差不多的,在Opengl里,已经没有固定管线的一些功能如InterleavedArrays来指定是顶点还是法线或是纹理了,统一用vertexAttribPointer来传递应用程序与着色器之间的数据。在前面 MD2桢动画实现里面后面的参数传递改进版也有相关应用。
相应着立方体着色器主要代码如下.
1 <script id="cubeshader-fs" type="x-shader/x-fragment">
2 precision mediump float;
3
4 varying vec3 normal;
5 varying vec3 tex1;
6 varying vec3 tex2;
7 void main( void )
8 {
9 float x = tex1.x * 6.28 * 8.0; //2兀 * 8
10 float y = tex1.y * 6.28 * 8.0; //2兀 * 8
11 //cos(x)= 8个 (1 -1 1)
12 gl_FragColor = vec4(tex2,1.0) * vec4(sign(cos(x)+cos(y))); //
13 //gl_FragColor = vec4(normal*vec3(0.5)+vec3(0.5), 1);
14 }
15 </script>
16
17 <script id="cubeshader-vs" type="x-shader/x-vertex">
18 attribute vec3 a_position;
19 attribute vec3 a_normal;
20 attribute vec2 a_texCoord;
21
22 uniform mat4 view;
23 uniform mat4 perspective;
24 varying vec3 normal;
25 varying vec3 tex1;
26 varying vec3 tex2;
27 void main( void )
28 {
29 gl_Position = perspective * view * vec4(a_position,1.0);
30 normal = a_normal;
31 tex1 = vec3(a_texCoord,0.0);
32 tex2 = normalize(a_position)*0.5+0.5;
33 }
34 </script>
立方体着色器实现
着色器中,已经没有ftransform()功能可供调用,要自己传递如模型,视图,透视矩阵,在这里,模型是以原点为中心来绘画,意思模型视图矩阵也就是视图矩阵,所以屏幕位置的计算只需要视图和透视矩阵。在片断着色器中,x,y是从顶点着色器中的纹理坐标传递过来,相应过程6.28*8.0,相当于8个360度,用于控制立方体上的方块显示,而tex2是着色器中的顶点映射[0,1]的值,分别给立方体的六面分别设置不同的意思,然后用二个矢量的乘积来混合这二种颜色显示,gl_FragColor = vec4(tex2,1.0) * vec4(sign(cos(x)+cos(y)))。
在显示球体之前,应该先生成当前环境的立方体绘图,在这里使用FBO,先生成桢缓存和立方体绘理,并关联,然后以原点为中心,分别向上下左右前右绘图,然后利用桢缓冲分别输出到立方体上的六个面,主要代码如下:
1 function InitFBOCube() {
2 // WebGLFramebuffer
3 fboBuffer = gl.createFramebuffer();
4 gl.bindFramebuffer(gl.FRAMEBUFFER, fboBuffer);
5 fboBuffer.width = 512;
6 fboBuffer.height = 512;
7
8 cubeTexID = gl.createTexture();
9 gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTexID);
10 gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
11 gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
12 gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
13 gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
14
15 for (var i = 0; i < targets.length; i++) {
16 gl.texImage2D(targets[i], 0, gl.RGBA, fboBuffer.width, fboBuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
17 }
18 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
19 }
20
21 function RenderFBO() {
22 gl.disable(gl.DEPTH_TEST);
23 gl.viewport(0, 0, fboBuffer.width, fboBuffer.height);
24 gl.clearColor(0.0, 0.0, 0.0, 1.0);
25 gl.bindFramebuffer(gl.FRAMEBUFFER, fboBuffer);
26 for (var i = 0; i < targets.length; i++) {
27 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, targets[i], cubeTexID, null);
28 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
29 }
30
31 mat4.perspective(pMatrix, 45, fboBuffer.width / fboBuffer.height, 0.1, 100.0);
32 for (var i = 0; i < targets.length; i++) {
33 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, targets[i], cubeTexID, null);
34 var lookat = vec3.create();
35 var up = vec3.create();
36 up[1] = 1.0;
37 if (i == 0) {
38 lookat[0] = -1.0;
39 } else if (i == 1) {
40 lookat[0] = 1.0;
41 } else if (i == 2) {
42 lookat[1] = -1.0;
43 up[0] = 1.0;
44 } else if (i == 3) {
45 lookat[1] = 1.0;
46 up[0] = 1.0;
47 } else if (i == 4) {
48 lookat[2] == -1.0;
49 } else if (i == 5) {
50 lookat[2] = 1.0;
51 } else {
52 }
53 //vec3.fromValues(0.0, 0.0, 0.0)
54 vMatrix = mat4.create();
55 mat4.lookAt(vMatrix, vec3.fromValues(0.0, 0.0, 0.0), lookat, up);
56 //mat4.scale(vMatrix, vMatrix, vec3.fromValues(-1.0, -1.0, -1.0));
57 //mat4.translate(vMatrix, vMatrix, spherePos);
58 RenderCube();
59 }
60 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
61 gl.enable(gl.DEPTH_TEST);
62 }
FBO与立方体纹理
在上面不知是gl-matrix提供的矩阵算法有问题,还是本来应该这样,在上下面的时候生成的纹理图不对,需要偏转摄像机的向上矢量。因为这是摄像机位置与目标的生成的Z轴和设定的UP轴平行了,这样导致不能正确计算X轴,然后对应的UP轴也计算不出来,相应视图矩阵出现错误。
最后是球体的绘画,代码主要和立方体的差不多,注意球体的顶点算法。
1 function InitSphereShader() {
2 //WebGLShader
3 var shader_vertex = GetShader("sphereshader-vs");
4 var shader_fragment = GetShader("sphereshader-fs");
5 //WebglCubeProgram
6 glSphereProgram = gl.createProgram();
7 gl.attachShader(glSphereProgram, shader_vertex);
8 gl.attachShader(glSphereProgram, shader_fragment);
9 gl.linkProgram(glSphereProgram);
10 if (!gl.getProgramParameter(glSphereProgram, gl.LINK_STATUS)) {
11 alert("Shader hava error.");
12 }
13 glSphereProgram.positionAttribute = gl.getAttribLocation(glSphereProgram, "a_position");
14 glSphereProgram.normalAttribute = gl.getAttribLocation(glSphereProgram, "a_normal");
15
16 glSphereProgram.eye = gl.getUniformLocation(glSphereProgram, "eye");
17 glSphereProgram.mapCube = gl.getUniformLocation(glSphereProgram, "mapCube");
18
19 glSphereProgram.model = gl.getUniformLocation(glSphereProgram, "model");
20 glSphereProgram.view = gl.getUniformLocation(glSphereProgram, "view");
21 glSphereProgram.perspective = gl.getUniformLocation(glSphereProgram, "perspective");
22 }
23
24 function InitSphereBuffer() {
25 var radius = 1;
26 var segments = 16;
27 var rings = 16;
28 var length = segments * rings * 6;
29 var sphereData = new Array();
30 var sphereIndex = new Array();
31 for (var y = 0; y < rings; y++) {
32 var phi = (y / (rings - 1)) * Math.PI;
33 for (var x = 0; x < segments; x++) {
34 var theta = (x / (segments - 1)) * 2 * Math.PI;
35 sphereData.push(radius * Math.sin(phi) * Math.cos(theta));
36 sphereData.push(radius * Math.cos(phi));
37 sphereData.push(radius * Math.sin(phi) * Math.sin(theta));
38 sphereData.push(Math.sin(phi) * Math.cos(theta));
39 sphereData.push(radius * Math.cos(phi))
40 sphereData.push(Math.sin(phi) * Math.sin(theta));
41 }
42 }
43 for (var y = 0; y < rings - 1; y++) {
44 for (var x = 0; x < segments - 1; x++) {
45 sphereIndex.push((y + 0) * segments + x);
46 sphereIndex.push((y + 1) * segments + x);
47 sphereIndex.push((y + 1) * segments + x + 1);
48
49 sphereIndex.push((y + 1) * segments + x + 1);
50 sphereIndex.push((y + 0) * segments + x + 1)
51 sphereIndex.push((y + 0) * segments + x);
52 }
53 }
54 sphereVBO = gl.createBuffer();
55 gl.bindBuffer(gl.ARRAY_BUFFER, sphereVBO);
56 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(sphereData), gl.STATIC_DRAW);
57 sphereVBO.numItems = segments * rings;
58 sphereEBO = gl.createBuffer();
59 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereEBO);
60 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(sphereIndex), gl.STATIC_DRAW);
61 sphereEBO.numItems = sphereIndex.length;
62 }
63
64 function RenderSphere() {
65 gl.useProgram(glSphereProgram);
66 gl.bindBuffer(gl.ARRAY_BUFFER, sphereVBO);
67
68 gl.vertexAttribPointer(glSphereProgram.positionAttribute, 3, gl.FLOAT, false, 24, 0);
69 gl.enableVertexAttribArray(glSphereProgram.positionAttribute);
70
71 gl.vertexAttribPointer(glSphereProgram.normalAttribute, 3, gl.FLOAT, false, 24, 12);
72 gl.enableVertexAttribArray(glSphereProgram.normalAttribute);
73
74 var mMatrix = mat4.create();
75 mat4.translate(mMatrix, mMatrix, spherePos);
76 gl.uniform3f(glSphereProgram.eye, eyePos[0],eyePos[1],eyePos[2]);
77 gl.uniformMatrix4fv(glSphereProgram.model, false, mMatrix);
78 gl.uniformMatrix4fv(glSphereProgram.view, false, vMatrix);
79 gl.uniformMatrix4fv(glSphereProgram.perspective, false, pMatrix);
80
81 gl.activeTexture(gl.TEXTURE0);
82 gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTexID);
83 //gl.uniformMatrix4fv(glSphereProgram.mapCube, 0);
84
85 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereEBO);
86 gl.drawElements(gl.TRIANGLES, sphereEBO.numItems, gl.UNSIGNED_SHORT, 0);
87 gl.bindTexture(gl.TEXTURE_2D, null);
88 }
球体
可以看到,也是和立方体一样的三步,初始化着色器,初始化顶点与法线,绘画。下面给出着色器代码:
1 <script id="sphereshader-fs" type="x-shader/x-fragment">
2 precision mediump float;
3
4 varying vec3 normal;
5 varying vec3 eyevec;
6 uniform samplerCube mapCube;
7 void main( void )
8 {
9 gl_FragColor = textureCube(mapCube, reflect(normalize(-eyevec), normalize(normal)));
10 }
11 </script>
12
13 <script id="sphereshader-vs" type="x-shader/x-vertex">
14 attribute vec3 a_position;
15 attribute vec3 a_normal;
16
17 uniform mat4 model;
18 uniform mat4 view;
19 uniform mat4 perspective;
20 uniform vec3 eye;
21
22 varying vec3 normal;
23 varying vec3 eyevec;
24
25 void main( void )
26 {
27 gl_Position = perspective * view * model * vec4(a_position,1.0);
28 eyevec = -eye;// a_position.xyz;
29 normal = a_normal;
30 }
31 </script>
球体着色器
和前面立方体有点不同的是,球体有自己的模型矩阵,这也是一般正常的用法,然后传递眼睛对应球体顶点矢量与法线传递在片断着色器中,在片断着色器中,就有用到前面所生成的立方体纹理,我们根据眼睛经过顶点通过对应法向量反射到立体体纹理上的点来获取当前球体所对应的环境颜色,在这里,我们可以直接调用textureCube来完成上面所说的过程,不需要我们手动来计算。
其中GetShader函数的使用,参照了http://msdn.microsoft.com/zh-TW/library/ie/dn302360(v=vs.85) 这里的讲解。
可以说,上面主要的绘制函数已经完成,但是我们这个是能动的,所以需要模拟如客户端环境每隔多久绘制一次,主要代码如下:
1 function tick() {
2 Update();
3 OnDraw();
4 setTimeout(function () { tick() }, 15);
5 }
6 function OnDraw() {
7 //fbo rander CUBE_MAP
8 RenderFBO();
9 //element rander
10 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
11 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
12 mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 200.0);
13 mat4.lookAt(vMatrix, eyePos, eyeLookat, vec3.fromValues(0.0, 1.0, 0.0));
14 RenderCube();
15 RenderSphere();
16 }
17
18 var lastTime = new Date().getTime();
19 function Update() {
20 var timeNow = new Date().getTime();
21 if (lastTime != 0) {
22 var elapsed = timeNow - lastTime;
23 //3000控制人眼的旋转速度。8控制人眼的远近
24 eyePos[0] = Math.cos(elapsed / 3000) * 8;
25 eyePos[2] = Math.sin(elapsed / 2000) * 8;
26
27 spherePos[0] = Math.cos(elapsed / 4000) * 3;
28 spherePos[2] = Math.cos(elapsed / 4000) * 3;
29 }
30
31 }
动画
在上面,每隔15毫秒调用一次Update与Draw函数,其中Update用于更新眼睛与球体位置,Draw绘画。
有二年没做网页上的开发,可能其中javascript的用法让大家见笑了,动态语言实在太自由了,反而不好写。
在新的一年的第一天,祝大家事事如意。
WebGL 利用FBO完成立方体贴图。的更多相关文章
- Unity Shaders and Effects Cookbook (4-1)(4-2)静态立方体贴图的创建与使用
開始学习第4章 - 着色器的反射 看完了1.2节,来记录一下.反射主要是利用了 Cubemap 立方体贴图. 认识Cubemap 立方体贴图.就如同名字所说.在一个立方体上有6张图.就这样觉得吧. 假 ...
- OpenGL 核心技术之立方体贴图
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家.特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...
- 立方体贴图(Cubemap)
http://blog.csdn.net/asdjy123/article/details/51190643 点击打开链接 好东西保存方便查看 立方体贴图(Cubemap) 原文 Cubemaps 作 ...
- (转)OpenGL学习——立方体贴图
转自:https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/06%20Cubemaps/ 我们之前一直使用的是2 ...
- OpenGL+OpenCV实现立方体贴图
我屮艸芔茻,转眼就7月份了. 今天试了一下立方体贴图,比较简单,大概说下和平面贴图的区别. 1. 平面贴图需要的是纹理坐标vec2:立方体贴图需要的是一个方向向量vec3,长度没有关系,重要的是方向, ...
- threejs立方体贴图产生边缘锯齿问题
threejs立方体贴图产生边缘锯齿问题 立方体贴图边缘锯齿 解决后 经过试验测试发现, textureGrass.wrapS和 textureGrass.wrapT属性导致的. 解决方法1: 删掉t ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图 代码工程地址: https://github.c ...
- NGUI字体贴图压缩以及相关Shader解读
一般游戏中,字体贴图是游戏贴图压缩的一个重点,特别是对于中文的游戏.考虑的字体贴图的特殊性,一般我们输出的字体贴图是不含颜色信息的,所以正常情况下,我们输出的字体贴图RGBA每一个通道都是一样的.这样 ...
- 【Linux】利用Xvfb关闭chrome的图形化输出
利用Xvfb关闭chrome的图形化输出 #!/bin/bash . /home/fzuir/.profile # JAVA export JAVA_HOME=/usr/local/jdk1.7.0_ ...
随机推荐
- ES2017 中的 Async 和 Await
ES2017 在 6 月最终敲定了,随之而来的是广泛的支持了我最喜欢的最喜欢的JavaScript功能: async(异步) 函数.如果你也曾为异步 Javascript 而头疼,那么这个就是为你设计 ...
- openssl之EVP系列之13---EVP_Open系列函数介绍
openssl之EVP系列之13---EVP_Open系列函数介绍 ---依据openssl doc/crypto/EVP_OpenInit.pod翻译和自己的理解写成 (作者:Dra ...
- [Windows Azure] How to use the Windows Azure Blob Storage Service in .NET
How to use the Windows Azure Blob Storage Service in .NET version 1.7 version 2.0 This guide will de ...
- 《转》冯森林:手机淘宝中的那些Web技术(2014年)
Native APP与Web APP的技术融合已经逐渐成为一种趋势,使用标准的Web技术来开发应用中的某些功能,不仅可以降低开发成本,同时还可以方便的进行功能迭代更新.但是如何保证Web APP的流畅 ...
- (转) Lua: 给 Redis 用户的入门指导
可能你已经听说过Redis 中嵌入了脚本语言,但是你还没有亲自去尝试吧? 这个入门教程会让你学会在你的Redis 服务器上使用强大的lua语言. Hello, Lua! 我们的第一个Redis Lu ...
- 【ARM】定时器
PWM定时器 PWN:脉冲宽度调制 每个定时器都有一个专用的由定时器时钟驱动的16位递减计数器.当递减计数器的计数值达到0的时候,就会产生定时中断请求来通知CPU定时器操作完成.当定时器递减计数器达到 ...
- Leetcode:Interleaving String 解题报告
Interleaving StringGiven s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For ...
- Spring Batch中job的启动,停止,放弃操作
1,启动一个job 运行一个批处理任务至少有两点要求:一个 JobLauncher 和一个用来运行的 job .它们都包含了相同或是不同的 context .举例来说,从命令行来启动job,会为每一个 ...
- Oracle Database 11g Release 2 Standard Edition and Enterprise Edition Software Downloads
Oracle Database 11g Release 2 Standard Edition and Enterprise Edition Software DownloadsOracle 数据库 1 ...
- Tensorflow问题汇总
问题: Cannot assign a device for operation 'MatMul': Operation was explicitly assigned to /device:GPU: ...