This paper illustrates the method of WebGL using FBO to finish the cube mapping effect. Share to everyone for your reference, specific as follows:
This main record WebGL some of the basic points, incidentally also learn how to use FBO and environment mapping. First look at the effect map (need to support Webgl,chrome, Firefox, IE11).
The main realization process is as follows, first with FBO output the current environment in the cube texture, then draw the current cube, and finally draw the ball, and the FBO associated with the texture on the sphere.
Start WebGL, it is best to have some OpenGL basis, in front of the MD2 and the improvement of obj, we may have found, because the addition of the shader, some of the original OpenGL API has not been used. WebGL is similar to this, most of the function is the shader to complete the main function, record the main process, you can compare the front, to see if it is very similar, in order to familiarize themselves with the basic functions of WEBGL, this article does not use a more complete framework, but only to use a matrix to help compute Gl-matrix.js).
As with OpenGL, we want to initialize the usage environment and extract some of the global usage. The relevant code is as follows:
Class
var gl;//webglrenderingcontext var cubevbo;//cube buffer ID var spherevbo;//sphere vbo var sphereebo;//sphere ebo var cubetexid;//li Square Texture ID var fbobuffer;//frame cache object var glcubeprogram;//cube shader apply var glsphereprogram;//sphere shader Apply var fbowidth = 512;//Frame Cache binding Texture Width VA R fboheight = 512;//Frame Cache binding Texture Height var targets;//cube map Six directions var Pmatrix = mat4.create (); pivot matrix var vmatrix = Mat4.create ();//View Moment Array var eyepos = vec3.fromvalues (0.0, 1.0, 0.0);//eye position var Eyelookat = vec3.fromvalues (0.0,-0.0, 0.0);//eye direction var Spherepos
= Vec3.fromvalues (0.0,-0.0, 0.0);//sphere position var canvanname;
function Webglstart (cName) {canvanname = CName;
Initwebgl ();
Initcubeshader ();
Initsphereshader ();
Initcubebuffer ();
Initspherebuffer ();
Initfbocube ();
RENDERFBO ();
Gl.clearcolor (0.0, 0.0, 0.0, 1.0); Gl.enable (GL.
Depth_test);
Tick ();
function Initwebgl () {//var canvas = document.getElementById (canvanname);
INITGL (Canvanname); } function Initgl (canvas) {try {//webglrenderingcontext gl = canvas.getcontext ("ExpErimental-webgl ");
Gl.viewportwidth = Canvas.width;
Gl.viewportheight = Canvas.height; Targets = [GL. Texture_cube_map_positive_x, GL. Texture_cube_map_negative_x, GL. Texture_cube_map_positive_y, GL. Texture_cube_map_negative_y, GL. Texture_cube_map_positive_z, GL.
TEXTURE_CUBE_MAP_NEGATIVE_Z];
catch (e) {} if (!GL) {alert ("Your browser does not support WebGL");}
Here, we initialize the WEBGL environment in the Web page and give a series of initialization processes. The following is the first room, which is the relevant code of the cube.
Cube:
function Initcubeshader () {//webglshader var Shader_vertex = Getshader ("Cubeshader-vs");
var shader_fragment = Getshader ("Cubeshader-fs");
Webglcubeprogram Glcubeprogram = Gl.createprogram ();
Gl.attachshader (Glcubeprogram, Shader_vertex);
Gl.attachshader (Glcubeprogram, shader_fragment);
Gl.linkprogram (Glcubeprogram); if (!gl.getprogramparameter) (Glcubeprogram, GL.
Link_status)) {alert ("Shader hava error.");
} gl.useprogram (Glcubeprogram);
Glcubeprogram.positionattribute = Gl.getattriblocation (Glcubeprogram, "a_position");
Glcubeprogram.normalattribute = Gl.getattriblocation (Glcubeprogram, "a_normal");
Glcubeprogram.texcoordattribute = Gl.getattriblocation (Glcubeprogram, "A_texcoord");
Glcubeprogram.view = Gl.getuniformlocation (Glcubeprogram, "view");
glcubeprogram.perspective = Gl.getuniformlocation (Glcubeprogram, "perspective"); function Initcubebuffer () {var cubedata = [-10.0,-10.0,-10.0, 0.0, 0.0,-10.0, 1.0, 0.0,-10.0, 10.0,-10.0, 0.0, 0.0,-10.0, 1.0, 1.0, 10.0, 10.0,-10.0, 0.0, 0.0,-10.0, 0.0, 1.0, 10.0, 10.0,-10.0, 0.0, 0.0 ,-10.0, 0.0, 1.0, 10.0,-10.0,-10.0, 0.0, 0.0,-10.0, 0.0, 0.0,-10.0,-10.0,-10.0, 0.0, 0.0,-10.0, 1.0, 0 .0,-10.0,-10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0,-10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 0.0, 10.0, 10. 0, 10.0, 0.0, 0.0, 10.0, 1.0, 1.0, 10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 1.0,-10.0, 10.0, 10.0, 0.0, 0.0, 10
.0, 0.0, 1.0,-10.0,-10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0,-10.0,-10.0,-10.0, 0.0,-10.0, 0.0, 0.0, 0.0, 10.0,-10.0,-10.0, 0.0,-10.0, 0.0, 1.0, 0.0, 10.0,-10.0, 10.0, 0.0,-10.0, 0.0, 1.0, 1.0, 10.0,-10.0, 10.0, 0.0,-10.0, 0.0, 1.0, 1.0,-10.0,-10.0, 10.0, 0.0,-10.0, 0.0, 0.0, 1.0,-10.0,-10.0,-10.0, 0.0,-10.
0, 0.0, 0.0, 0.0, 10.0,-10.0,-10.0, 10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 10.0,-10.0, 10.0, 0.0, 0.0, 1.0, 0.0, 10.0, 10.0, 10.0, 1.0.0, 0.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 1.0, 1.0, 10.0,-10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 1 .0, 10.0,-10.0,-10.0, 10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 10.0,-10.0, 0.0, 10.0, 0.0, 0.0, 0.0,-10.0, 10 .0,-10.0, 0.0, 10.0, 0.0, 1.0, 0.0,-10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 1.0, 1.0,-10.0, 10.0, 10.0, 0.0, 10.0
, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 0.0, 1.0, 10.0, 10.0,-10.0, 0.0, 10.0, 0.0, 0.0, 0.0, -10.0, 10.0,-10.0,-10.0, 0.0, 0.0, 0.0, 0.0,-10.0,-10.0,-10.0,-10.0, 0.0, 0.0, 1.0, 0.0,-10.0,-10.0, 10.0,-10.0, 0.0, 0.0, 1.0, 1.0,-10.0,-10.0, 10.0,-10.0, 0.0, 0.0, 1.0, 1.0,-10.0, 10.0, 10.0,-10.0, 0.0
, 0.0, 0.0, 1.0,-10.0, 10.0,-10.0,-10.0, 0.0, 0.0, 0.0, 0.0,];
Cubevbo = Gl.createbuffer (); Gl.bindbuffer (GL.
Array_buffer, Cubevbo); Gl.bufferdata (GL. Array_buffer, New Float32array (Cubedata), GL.
Static_draw); function Rendercube () {Gl.useprogram(Glcubeprogram); Gl.bindbuffer (GL.
Array_buffer, Cubevbo); Gl.vertexattribpointer (Glcubeprogram.positionattribute, 3, GL.)
FLOAT, False, 32, 0);
Gl.enablevertexattribarray (Glcubeprogram.positionattribute); Gl.vertexattribpointer (Glcubeprogram.normalattribute, 3, GL.)
FLOAT, False, 32, 12);
Gl.enablevertexattribarray (Glcubeprogram.normalattribute); Gl.vertexattribpointer (Glcubeprogram.texcoordattribute, 2, GL.)
FLOAT, False, 32, 24);
Gl.enablevertexattribarray (Glcubeprogram.texcoordattribute);
GL.UNIFORMMATRIX4FV (Glcubeprogram.view, False, Vmatrix);
GL.UNIFORMMATRIX4FV (Glcubeprogram.perspective, False, Pmatrix); Gl.drawarrays (GL.
Triangles, 0, 36);
}
The above code is mainly divided into the initialization of the cube shader object, initialize the relevant cache, and then draw the cube, can be said in OpenGL, if the shader to paint, the process is similar, in OpenGL, There are no fixed pipeline features such as interleavedarrays to specify whether vertices or normals or textures, unified use Vertexattribpointer to pass the data between the application and shader. In front of the MD2 frame animation implementation of the back of the parameter transfer improved version also has related applications.
The corresponding cube shader main code is as follows:
Cube Shader Implementation:
<script id= "Cubeshader-fs" type= "x-shader/x-fragment" > Precision mediump float;
Varying vec3 normal;
Varying VEC3 tex1;
Varying VEC3 tex2; void Main (void) {float x = tex1.x * 6.28 * 8.0;//2 Wu * 8 float y = tex1.y * 6.28 * 8.0;//2 Wu * 8//cos ( x) = 8 (1-1 1) gl_fragcolor = VEC4 (tex2,1.0) * VEC4 (sign (cos (x) +cos (y)));
Gl_fragcolor = VEC4 (NORMAL*VEC3 (0.5) +VEC3 (0.5), 1);
} </script> <script id= "Cubeshader-vs" type= "X-shader/x-vertex" > attribute vec3 a_position;
Attribute VEC3 A_normal;
Attribute VEC2 A_texcoord;
Uniform MAT4 View;
Uniform MAT4 Perspective;
Varying vec3 normal;
Varying VEC3 tex1;
Varying VEC3 tex2;
void Main (void) {gl_position = perspective * View * VEC4 (a_position,1.0);
normal = A_normal;
Tex1 = VEC3 (a_texcoord,0.0);
Tex2 = Normalize (a_position) *0.5+0.5; } </script>
In the shader, there is no ftransform () function to call, you have to pass such as model, view, Perspective Matrix, here, the model is based on the origin of the center to paint, meaning model view matrix is the view matrix, so the screen position calculation only need view and perspective matrix. In the fragment shader, X,y is from the vertex shader in the texture of the coordinates passed, the corresponding process 6.28*8.0, equivalent to 8 360 degrees, used to control the box on the cube display, and TEX2 is the shader in the vertex map [0,1] value, respectively, to the cube six sides respectively set different meanings, The two-vector product is then mixed with the two-color display, Gl_fragcolor = VEC4 (tex2,1.0) * VEC4 (sign (cos (x) +cos (y)).
Before the sphere is displayed, should mister into the current environment of the cube drawing, where the use of FBO, Mr. Frame cache and Cube painting, and association, and then to the origin of the center, respectively, up and down the right and left to draw, and then use the frame buffer output to the cube on the six surface, the main code as follows:
FBO and Cube textures:
function Initfbocube () {//Webglframebuffer Fbobuffer = Gl.createframebuffer (); Gl.bindframebuffer (GL.
Framebuffer, Fbobuffer);
Fbobuffer.width = 512;
Fbobuffer.height = 512;
Cubetexid = Gl.createtexture (); Gl.bindtexture (GL.
Texture_cube_map, CUBETEXID); Gl.texparameteri (GL. Texture_cube_map, GL. texture_wrap_s, GL.
Clamp_to_edge); Gl.texparameteri (GL. Texture_cube_map, GL. texture_wrap_t, GL.
Clamp_to_edge); Gl.texparameteri (GL. Texture_cube_map, GL. Texture_min_filter, GL.
LINEAR); Gl.texparameteri (GL. Texture_cube_map, GL. Texture_mag_filter, GL.
LINEAR); for (var i = 0; i < targets.length i++) {gl.teximage2d (targets[i), 0, Gl. RGBA, Fbobuffer.width, fbobuffer.height, 0, GL. RGBA, GL.
Unsigned_byte, NULL); } gl.bindframebuffer (GL.
Framebuffer, NULL); function Renderfbo () {gl.disable (GL.
Depth_test);
Gl.viewport (0, 0, fbobuffer.width, fbobuffer.height);
Gl.clearcolor (0.0, 0.0, 0.0, 1.0); Gl.bindframebuffer (GL.
Framebuffer, Fbobuffer); for (var i = 0;i < targets.length; i++) {gl.framebuffertexture2d (GL. Framebuffer, GL.
Color_attachment0, Targets[i], CUBETEXID, NULL); Gl.clear (GL. Color_buffer_bit | Gl.
Depth_buffer_bit);
Mat4.perspective (Pmatrix, Fbobuffer.width/fbobuffer.height, 0.1, 100.0); for (var i = 0; i < targets.length i++) {gl.framebuffertexture2d (GL. Framebuffer, GL.
Color_attachment0, Targets[i], CUBETEXID, NULL);
var LookAt = Vec3.create ();
var up = Vec3.create ();
UP[1] = 1.0;
if (i = = 0) {Lookat[0] =-1.0;
else if (i = = 1) {lookat[0] = 1.0;
else if (i = = 2) {Lookat[1] =-1.0;
Up[0] = 1.0;
else if (i = = 3) {lookat[1] = 1.0;
Up[0] = 1.0;
else if (i = = 4) {Lookat[2] = = 1.0;
else if (i = = 5) {lookat[2] = 1.0;
} else {}//vec3.fromvalues (0.0, 0.0, 0.0) Vmatrix = Mat4.create ();
Mat4.lookat (Vmatrix, vec3.fromvalues (0.0, 0.0, 0.0), LookAt, up); Mat4. Scale (Vmatrix, Vmatrix, Vec3.fromvalues (-1.0,-1.0,-1.0));
Mat4.translate (Vmatrix, Vmatrix, Spherepos);
Rendercube (); } gl.bindframebuffer (GL.
Framebuffer, NULL); Gl.enable (GL.
Depth_test);
}
In the above is not know is Gl-matrix provided by the matrix algorithm is problematic, or should be so, in the following time generated texture map is not correct, need to deflect the camera upward vector. Because this is the camera position and the target generated z-axis and set up axis parallel, so that the x axis can not be correctly computed, and then the corresponding up axis can not be computed, the corresponding view matrix error.
Finally, the ball of the painting, the code is mainly the same as the cube, attention to the vertex algorithm of the sphere.
Sphere:
function Initsphereshader () {//webglshader var Shader_vertex = Getshader ("Sphereshader-vs");
var shader_fragment = Getshader ("Sphereshader-fs");
Webglcubeprogram Glsphereprogram = Gl.createprogram ();
Gl.attachshader (Glsphereprogram, Shader_vertex);
Gl.attachshader (Glsphereprogram, shader_fragment);
Gl.linkprogram (Glsphereprogram); if (!gl.getprogramparameter) (Glsphereprogram, GL.
Link_status)) {alert ("Shader hava error.");
} Glsphereprogram.positionattribute = Gl.getattriblocation (Glsphereprogram, "a_position");
Glsphereprogram.normalattribute = Gl.getattriblocation (Glsphereprogram, "a_normal");
Glsphereprogram.eye = Gl.getuniformlocation (Glsphereprogram, "eye");
Glsphereprogram.mapcube = Gl.getuniformlocation (Glsphereprogram, "Mapcube");
Glsphereprogram.model = Gl.getuniformlocation (Glsphereprogram, "model");
Glsphereprogram.view = Gl.getuniformlocation (Glsphereprogram, "view"); glsphereprogram.perspective = Gl.getuniformlocation (GlsphereprograM, "perspective");
function Initspherebuffer () {var radius = 1;
var segments = 16;
var rings = 16;
var length = segments * rings * 6;
var spheredata = new Array ();
var sphereindex = new Array ();
for (var y = 0; y < rings; y++) {var phi = (Y/(rings-1)) * MATH.PI;
for (var x = 0; x < segments + +) {var theta = (x/(SEGMENTS-1)) * 2 * MATH.PI;
Spheredata.push (RADIUS * Math.sin (PHI) * Math.Cos (theta));
Spheredata.push (RADIUS * Math.Cos (PHI));
Spheredata.push (RADIUS * Math.sin (PHI) * Math.sin (theta));
Spheredata.push (Math.sin (PHI) * Math.Cos (theta));
Spheredata.push (RADIUS * Math.Cos (PHI)) Spheredata.push (Math.sin (PHI) * Math.sin (theta)); (var y = 0; y < rings-1; y++) {for (var x = 0; x < segments-1 x + +) {Sphereindex.push (y
+ 0) * segments + x);
Sphereindex.push ((y + 1) * segments + x);
Sphereindex.push ((y + 1) * segments + x + 1); Sphereindex.push ((Y+ 1) * segments + x + 1);
Sphereindex.push ((y + 0) * segments + x + 1) sphereindex.push ((y + 0) * segments + x);
} Spherevbo = Gl.createbuffer (); Gl.bindbuffer (GL.
Array_buffer, Spherevbo); Gl.bufferdata (GL. Array_buffer, New Float32array (Spheredata), GL.
Static_draw);
Spherevbo.numitems = segments * rings;
Sphereebo = Gl.createbuffer (); Gl.bindbuffer (GL.
Element_array_buffer, Sphereebo); Gl.bufferdata (GL. Element_array_buffer, New Uint16array (Sphereindex), GL.
Static_draw);
Sphereebo.numitems = Sphereindex.length;
function Rendersphere () {Gl.useprogram (Glsphereprogram); Gl.bindbuffer (GL.
Array_buffer, Spherevbo); Gl.vertexattribpointer (Glsphereprogram.positionattribute, 3, GL.)
FLOAT, False, 24, 0);
Gl.enablevertexattribarray (Glsphereprogram.positionattribute); Gl.vertexattribpointer (Glsphereprogram.normalattribute, 3, GL.)
FLOAT, False, 24, 12);
Gl.enablevertexattribarray (Glsphereprogram.normalattribute);
var Mmatrix = Mat4.create (); mat4.tRanslate (Mmatrix, Mmatrix, Spherepos);
gl.uniform3f (Glsphereprogram.eye, eyepos[0],eyepos[1],eyepos[2]);
GL.UNIFORMMATRIX4FV (Glsphereprogram.model, False, Mmatrix);
GL.UNIFORMMATRIX4FV (Glsphereprogram.view, False, Vmatrix);
GL.UNIFORMMATRIX4FV (Glsphereprogram.perspective, False, Pmatrix); Gl.activetexture (GL.
TEXTURE0); Gl.bindtexture (GL.
Texture_cube_map, CUBETEXID);
GL.UNIFORMMATRIX4FV (glsphereprogram.mapcube, 0); Gl.bindbuffer (GL.
Element_array_buffer, Sphereebo); Gl.drawelements (GL. Triangles, Sphereebo.numitems, GL.
Unsigned_short, 0); Gl.bindtexture (GL.
texture_2d, NULL);
}
As you can see, the three steps are the same as the cube, initializing the shader, initializing the vertices and normals, drawing. The shader code is given below:
Sphere Shader:
<script id= "Sphereshader-fs" type= "x-shader/x-fragment" >
precision mediump float;
Varying vec3 normal;
Varying vec3 Eyevec;
Uniform Samplercube Mapcube;
void main (void)
{
Gl_fragcolor = Texturecube (Mapcube, Reflect (normalize (-eyevec), normalize (normal));
}
</script>
<script id= "Sphereshader-vs" type= "X-shader/x-vertex" >
attribute vec3 a_ Position;
Attribute VEC3 A_normal;
Uniform MAT4 model;
Uniform mat4 view;
Uniform MAT4 Perspective;
Uniform vec3 Eye;
Varying vec3 normal;
Varying vec3 Eyevec;
void main (void)
{
Gl_position = perspective * View * model * VEC4 (a_position,1.0);
Eyevec =-eye;//a_position.xyz;
normal = A_normal;
}
</script>
A bit different from the front cube is that the sphere has its own model matrix, which is also the normal use, and then pass the eye corresponding to the ball vertex vector and normal pass in the fragment shader, in the fragment shader, to the previous generated cube texture, We can get the ambient color of the current sphere according to the point of the eye passing through the vertex through the corresponding normal vector to the texture of the stereo body, where we may call the Texturecube to complete the process mentioned above, and we do not need to calculate it manually.
The use of the Getshader function, referring to the http://msdn.microsoft.com/zh-TW/library/ie/dn302360 (v=vs.85) here explained.
It can be said that the main drawing function has been completed, but we are active, so we need to simulate how often the client environment is drawn once, the main code is as follows:
Animation:
function tick () {
Update ();
OnDraw ();
settimeout (function () {tick ()},);
}
function OnDraw () {
//fbo rander cube_map
renderfbo ();
Element Rander
gl.viewport (0, 0, gl.viewportwidth, gl.viewportheight);
Gl.clear (GL. Color_buffer_bit | Gl. Depth_buffer_bit);
Mat4.perspective (Pmatrix, Gl.viewportwidth/gl.viewportheight, 0.1, 200.0);
Mat4.lookat (Vmatrix, Eyepos, Eyelookat, Vec3.fromvalues (0.0, 1.0, 0.0));
Rendercube ();
Rendersphere ();
}
var lasttime = new Date (). GetTime ();
function Update () {
var timenow = new Date (). GetTime ();
if (lasttime!= 0) {
var elapsed = Timenow-lasttime;
3000 control the rotation speed of the human eye. 8 control of the human eye near and far
eyepos[0] = Math.Cos (elapsed/3000) * 8;
EYEPOS[2] = Math.sin (elapsed/2000) * 8;
Spherepos[0] = Math.Cos (elapsed/4000) * 3;
SPHEREPOS[2] = Math.Cos (elapsed/4000) * 3;
}
}
On top, the update and draw functions are called every 15 milliseconds, where update is used to update the position of the eye and sphere, draw painting.
Full instance code click here to download the site.
More about JS effects related content Readers can view the site topics: "jquery animation and special effects usage Summary" and "jquery Common classic Effects Summary"
I hope this article will help you with JavaScript programming.