这篇主要记录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完成立方体贴图。的更多相关文章

  1. Unity Shaders and Effects Cookbook (4-1)(4-2)静态立方体贴图的创建与使用

    開始学习第4章 - 着色器的反射 看完了1.2节,来记录一下.反射主要是利用了 Cubemap 立方体贴图. 认识Cubemap 立方体贴图.就如同名字所说.在一个立方体上有6张图.就这样觉得吧. 假 ...

  2. OpenGL 核心技术之立方体贴图

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家.特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  3. 立方体贴图(Cubemap)

    http://blog.csdn.net/asdjy123/article/details/51190643 点击打开链接 好东西保存方便查看 立方体贴图(Cubemap) 原文 Cubemaps 作 ...

  4. (转)OpenGL学习——立方体贴图

    转自:https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/06%20Cubemaps/ 我们之前一直使用的是2 ...

  5. OpenGL+OpenCV实现立方体贴图

    我屮艸芔茻,转眼就7月份了. 今天试了一下立方体贴图,比较简单,大概说下和平面贴图的区别. 1. 平面贴图需要的是纹理坐标vec2:立方体贴图需要的是一个方向向量vec3,长度没有关系,重要的是方向, ...

  6. threejs立方体贴图产生边缘锯齿问题

    threejs立方体贴图产生边缘锯齿问题 立方体贴图边缘锯齿 解决后 经过试验测试发现, textureGrass.wrapS和 textureGrass.wrapT属性导致的. 解决方法1: 删掉t ...

  7. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图 代码工程地址: https://github.c ...

  8. NGUI字体贴图压缩以及相关Shader解读

    一般游戏中,字体贴图是游戏贴图压缩的一个重点,特别是对于中文的游戏.考虑的字体贴图的特殊性,一般我们输出的字体贴图是不含颜色信息的,所以正常情况下,我们输出的字体贴图RGBA每一个通道都是一样的.这样 ...

  9. 【Linux】利用Xvfb关闭chrome的图形化输出

    利用Xvfb关闭chrome的图形化输出 #!/bin/bash . /home/fzuir/.profile # JAVA export JAVA_HOME=/usr/local/jdk1.7.0_ ...

随机推荐

  1. UIViewContrller之间切换的几种方式

    转自:http://blog.csdn.net/likendsl/article/details/7542296   1.UIViewContrller之间的切换有三种方式:     一.UIView ...

  2. 转:Android文件存储路径getFilesDir()与getExternalFilesDir的区别

    作为一个开发者,我们经常需要通过缓存一些文件到SD卡中,常见的方式就是,通过: File sdCard = Environment.getExternalStorageDirectory(); 获取S ...

  3. HHH

    https://data-artisans.com/flink-forward/resources/alibabas-common-algorithm-platform-on-flink https: ...

  4. numpy数组-标准化数据

    标准化数据的公式: (数据值 - 平均数) / 标准差 import numpy as np employment = np.array([ 55.70000076, 51.40000153, 50. ...

  5. windows远程连接mac配置方法

    1.开启mac共享服务,设置通过密码进行连接 [系统偏好设置]中选择[共享]打开[屏幕共享]服务,即可允许其他电脑的用户远程查看并控制此电脑.点击[电脑设置]配置访问密码 2. 下载TightVNC, ...

  6. Swift中Notification.Name这么难用怎么办

    Swift中Notification.Name这么难用怎么办 以前的发送通知的参数就是一个简单的字符串: NSNotificationCenter.defaultCenter().post(" ...

  7. SolrCloud基本过程

    转:http://www.data321.com/yunjisuan/20160514880/SolrZhiJieDuQuZKZhongDePeiZhiXin SolrCloud之分布式索引及与Zoo ...

  8. Notepad++中支持Markdown

    最近在学习Markdown语言的使用,很想在XP主机上使用Markdown的离线编辑器,但MarkdownPad.作业部分的离线客户端都不能再XP上运行,需要.Net 4.5 以上版本,可惜一台老主机 ...

  9. LeetCode: Balanced Binary Tree 解题报告

    Balanced Binary Tree Given a binary tree, determine if it is height-balanced. For this problem, a he ...

  10. mysql 添加外键时 error 150 问题总汇

    当你试图在mysql中创建一个外键的时候,这个出错会经常发生,这是非常令人沮丧的.像这种不能创建一个.frm 文件的报错好像暗示着操作系统的文件的权限错误或者其它原因,但实际上,这些都不是的,事实上, ...