http://www.reddit.com/r/gamedev/comments/2lyqki/three_techniques_to_procedurally_generate/
 Home
 » Viewing Profile: Reputation: spacerat
spacerat
Member Since 26 Oct 2006Offline Last Active Dec 13 2014 09:40 PM
Community Stats
 Group Members
 Active Posts 172
 Profile Views 2,817
 Submitted Links 0
 Member Title Member
 Age Age Unknown
 Birthday Birthday Unknown

Gender
Not Telling
#5192343 Procedural Map Generation
Posted by spacerat on 11 November 2014  07:47 PM
#5162779 Legal stuff when using free art / models in an own game
Posted by spacerat on 25 June 2014  09:27 AM
I am wondering how and to what extent free art / sprites / 3d models can be used in an own game.
For example, lets say in the case of an animated mickeymouse sprite, where the readme inside states:
"This sprite may be freely distributed UNALTERED. Which means, you can't pull the readme file out of the zip,or add your own stuff to it and pass it along as your own!"
I believe including it in the game an selling it bundled will not be allowed.
On the other hand, if the user downloads the free model himself and installs it in the gamefolder, there wont be any problem.
Now where is the boundary ?
Lets consider the following cases:
Like what happens if the game does not contain this sprite and
downloads and installs it automatically after installation ?
downloads and installs it on request (pushing a button) ?
contains a script to download and install the sprite ?
#5153872 High Speed Quadric Mesh Simplification without problems (Resolved)
Posted by spacerat on 15 May 2014  07:31 PM
Thank you Spiro!
I just updated the code
 Now everything is commented
 Borders are preserved well in the new version
 Added a new parameter (aggressiveness) to guide the collapsing speed. If the parameter is lower (5 instead of 7 e.g.), more iterations will be required and the result is closer to the optimum.
 The matrix is reduced from 16 to 10 elements since its symmetric
Here a comparison to other methods, and the updated Code (got a bit larger due to border tests) DOWNLOAD.
#5153306 High Speed Quadric Mesh Simplification without problems (Resolved)
Posted by spacerat on 13 May 2014  08:04 AM
Thanks a lot for the hints and the code. Now it works well
I have updated the DOWNLOAD
You are right  the error updating was the issue. I have resolved that now.
The main problem was apparently that i needed to compute the quadric per vertex from scratch each couple of iterations.
For the other iterations I simply added the quadric of the vertex to collapse to the target vertex and updated all edges.
Left to do is a check if a vertex is an border vertex and to add support for attributes.
Compared to Meshlab, its about 4x faster.
It is several times slower than vertex clustering ( Rapid Simplification of MultiAttribute Meshes HPG Paper ),
but has much higher quality due to the quadric metric.
Even there is no sorting and just a steadily increased threshold, the result is still good.
Left is the program output (5 seconds), right the Meshlab result (20 seconds) for reducing 2 million triangles down to 20k.
#5153215 High Speed Quadric Mesh Simplification without problems (Resolved)
Posted by spacerat on 12 May 2014  10:47 PM
Ok, now the new method almost works. I found two reasons why it didnt work before:
 I recalculated the normal after collapsing  there its better to keep the original
 Flipping happened after the triangle became almost line shaped and the normal was 0
The new version avoids this as follows:
 The new normal is always tested against the original normal
 The inner angle between 2 edges of the new triangle is tested to not get too line shaped (dot > 0.99)
Remaining problem:
 The edge collapse stops now even it does not reach the target number of triangles, as any further collapse would lead to violation of the above two tests.
Now, what is the best solution to that ?
Here the new version : Simplify.h ( including sorting by error and stopping at a certain number of triangles )
#5153029 High Speed Quadric Mesh Simplification without problems (Resolved)
Posted by spacerat on 12 May 2014  03:40 AM
Thank you for both of your comments!
Based on what criteria do you prioritize one contraction over the other? I don't see you (re)sorting the list of triangles.
Its threshold based  one threshold for the edge length, and one for the quadric error. Once the triangle error problem is solved, I will try a sorted list for better quality.
Currently, the decision if a triangle is removed is performed in line 60 in the code above.
If you use a proper data structure (custom heap) for the edge list, you can get similar performance to your implementation, but with much better quality. This keeps the edge list sorted automatically, and if you store the position in the (arraybased) heap along with the edge, you can get O(log(N)) updates/removals with each iteration. The problem with not updating the list of edges on each iteration is that the algorithm no longer optimally picks the edge with the least error, so your results will not be as good as the original quadricerror edge collapse algorithm.
The problem you're probably seeing is that triangles can flip over during an edge collapse, causing overlap of mostly coplanar triangles. You can fix this by checking each triangle that shares the edge vertices to make sure that its normal does not change sign (dot product with old normal < 0).
The triangle flipping is a good point. I have spend a lot of time now to figure out how to efficiently do this test without slowing down the method too much. The result is a modified method that stores a list of triangles for each vertex, where each of these triangles has one reference to this vertex. It allows to efficiently test for flipping and collapsing one vertex.
In the code below, the list with ids named refs. It is referred to by tstart,tcount from vertex and contains the triangle ID (tid) and vertex offset inside the triangle (tvertex). (In the current version it just grows  but in the final version it needs to be reinitialized every couple of iterations to avoid using too much ram)
The problem is that even it prevents some errors, still flipped triangles occur somehow. I could not yet resolve the problem. Is there anything else that can cause the flipping error ? Or can you spot an error in the flipping test below ? ( function flipped )
Edit: Seems I found a hint: the problem seems to arise when the triangles get almost line  shaped, so all 3 points are along one line.
For the speed, the method can basically be even faster as it doesnt require so many iterations.
I first need to resolve the error however, before speeding up and improving the quality by sorting.
For the edge based structure, I have tried a edge based structure before, but since I had referenced to the triangles in the edges it got quite messy to update them after one triangle was removed. The speed might be equal, yes.
Here the new version ( Simplify.h )
struct Triangle{ int v[3];double err[3];bool deleted,dirty;vec3f n; }; struct Vertex{ vec3f p;int tstart,tcount;Matrix q; }; struct Ref { int tid,tvertex; }; std::vector<Triangle> triangles; std::vector<Vertex> vertices; std::vector<Ref> refs; double vertex_error(Matrix q, double x, double y, double z); double calculate_error(int id_v1, int id_v2, vec3f &p_result); bool flipped(vec3f p,int i0,int i1,Vertex &v0,Vertex &v1,std::vector<vec3f> &tmp_n) { // p : new vertex position ( (v0.p+v1.p)/2 for the most simple case ) // i0 : index of vertex 0 // i1 : index of vertex 1 // v0 : edge vertex 0 // v1 : edge vertex 1 // tmp_n : array to temporarily store normals to avoid recomputing them loopk(0,v0.tcount) { Triangle &t=triangles[refs[v0.tstart+k].tid]; int s=refs[v0.tstart+k].tvertex; int id1=t.v[(s+1)%3]; int id2=t.v[(s+2)%3]; if(id1==i1  id2==i1 ) // delete ? { tmp_n[k].x=10; continue; } vec3f p1 = vertices[id1].p; vec3f p2 = vertices[id2].p; vec3f n; n.cross(p1p,p2p); n.normalize(); tmp_n[k]=n; if(n.dot(t.n)<0.0) return true; } return false; } void update_triangles(int i0,Vertex &v,std::vector<vec3f> &tmp_n,int &deleted_triangles) { vec3f p; loopk(0,v.tcount) { Ref &r=refs[v.tstart+k]; Triangle &t=triangles[r.tid]; if(t.deleted)continue; if(tmp_n[k].x<5) { t.deleted=1; deleted_triangles++; continue; } t.v[r.tvertex]=i0; t.n=tmp_n[k]; t.dirty=1; t.err[0]=calculate_error(t.v[0],t.v[1],p); t.err[1]=calculate_error(t.v[1],t.v[2],p); t.err[2]=calculate_error(t.v[2],t.v[0],p); refs.push_back(r); } } void reduce_polygons() { printf("reduce_polygons  start\n"); int timeStart=timeGetTime(); // Init defaults loopi(0,vertices.size()) { Vertex &v=vertices[i]; v.q=Matrix(0.0); v.tstart=0; v.tcount=0; } loopi(0,triangles.size()) triangles[i].deleted= triangles[i].dirty=0; // init Reference ID list refs.resize(triangles.size()*3); loopi(0,triangles.size()) { Triangle &t=triangles[i]; loopj(0,3) vertices[t.v[j]].tcount++; } int tstart=0; loopi(0,vertices.size()) { Vertex &v=vertices[i]; v.tstart=tstart; tstart+=v.tcount; v.tcount=0; } loopi(0,triangles.size()) { Triangle &t=triangles[i]; loopj(0,3) { Vertex &v=vertices[t.v[j]]; refs[v.tstart+v.tcount].tid=i; refs[v.tstart+v.tcount].tvertex=j; v.tcount++; } } // Init Quadric by Plane loopi(0,triangles.size()) { Triangle &t=triangles[i]; vec3f n,p[3]; loopj(0,3) p[j]=vertices[t.v[j]].p; n.cross(p[1]p[0],p[2]p[0]); n.normalize(); t.n=n; loopj(0,3) vertices[t.v[j]].q = vertices[t.v[j]].q+Matrix(n.x,n.y,n.z,n.dot(p[0])); } // Calc Edge Error loopi(0,triangles.size()) { Triangle &t=triangles[i];vec3f p; loopj(0,3) t.err[j]=calculate_error(t.v[j],t.v[(j+1)%3],p); } int deleted_triangles=0; std::vector<vec3f> tmp_n0,tmp_n1; loopl(0,20) // iteration { // remove vertices & mark deleted triangles loopi(0,triangles.size()) if(!triangles[i].deleted) if(!triangles[i].dirty) { Triangle &t=triangles[i]; loopj(0,3) // all edges of one triangle { int i0=t.v[ j ]; Vertex &v0 = vertices[i0]; int i1=t.v[(j+1)%3]; Vertex &v1 = vertices[i1]; bool test1=t.err[j] < 0.00000001*l*l*l*l*l; bool test2=(v0.pv1.p).length()<0.3*l; // remove based on edgelength and quadric error if(test1 && test2) // remove edge ? { vec3f p; calculate_error(i0,i1,p); // quadric based new edge //p=(v1.p+v0.p)*0.5; // simple new edge for testing tmp_n0.resize(v0.tcount); // normals temporarily tmp_n1.resize(v1.tcount); // normals temporarily // dont remove if flipped if( flipped(p,i0,i1,v0,v1,tmp_n0) ) continue; if( flipped(p,i1,i0,v1,v0,tmp_n1) ) continue; // not flipped, so remove edge v0.p=p; v0.q=v1.q+v0.q; int tstart=refs.size(); update_triangles(i0,v0,tmp_n0,deleted_triangles); update_triangles(i0,v1,tmp_n1,deleted_triangles); int tcount=refs.size()tstart; v0.tstart=tstart; v0.tcount=tcount; break; } } } // clear dirty flag loopi(0,triangles.size()) triangles[i].dirty=0; } }
#5152662 High Speed Quadric Mesh Simplification without problems (Resolved)
Posted by spacerat on 10 May 2014  05:51 AM
Update May 13th: Download the working version here
MIT license, well documented and working without errors.
The latest source is also included in the lowermost reply.
Summary I am currently on a new implementation of a Quadric based mesh simplification algorithm. Its quite short (130 lines for the main part) , but apparently there is a bug somewhere. I searched already a while but couldnt find it yet. If one of you can spot it, any help is appreciated.
In turn, everyone gets a great mesh simplification method for free once it works
Its able to reduce 90% of 650.000 triangles in about 1 sec. (Single threaded) by using less memory than most other methods.
Algorithm Different from the original method, it does not store the peredgeerror in an edges list, but per triangle. This avoids the edges list completely as the edge list is slow creating and updating. On the other hand, every error is computed twice  but that's not so serious.
Methods :
calculate_error calculates the error between two vertices and output the vertex an edge might be reduced to.
reduce_polygons main function to reduce the mesh
The Problem Here a screenshot of the bug: Some faces are flipped and look displaced..
Here the source code
struct Triangle{ int v[3];double err[3];bool deleted; }; struct Vertex{ vec3f p,n;int dst,dirty;Matrix q; }; std::vector<Triangle> triangles; std::vector<Vertex> vertices; double vertex_error(Matrix q, double x, double y, double z); double calculate_error(int id_v1, int id_v2, vec3f &p_result); void reduce_polygons() { // Init defaults loopi(0,vertices.size()) { vertices[i].dst=1; vertices[i].q=Matrix(0.0); vertices[i].dirty=false; vertices[i].n=vec3f(0,0,0); } loopi(0,triangles.size()) triangles[i].deleted=0; // Init Quadric by Plane loopi(0,triangles.size()) { Triangle &t=triangles[i]; vec3f n,p[3]; loopj(0,3) p[j]=vertices[t.v[j]].p; n.cross(p[1]p[0],p[2]p[0]); n.normalize(); loopj(0,3) vertices[t.v[j]].q = vertices[t.v[j]].q+Matrix(n.x,n.y,n.z,n.dot(p[0])); } // Calc Edge Error loopi(0,triangles.size()) { Triangle &t=triangles[i];vec3f p; loopj(0,3) t.err[j]=calculate_error(t.v[j],t.v[(j+1)%3],p); } int deleted_triangles=0; loopl(0,25) // iteration { // remove vertices & mark deleted triangles loopi(0,triangles.size()) if(!triangles[i].deleted) { Triangle &t=triangles[i]; if(vertices[t.v[0]].dirty) continue; if(vertices[t.v[1]].dirty) continue; if(vertices[t.v[2]].dirty) continue; loopj(0,3) { int i0=t.v[ j ]; Vertex &v0 = vertices[i0]; int i1=t.v[(j+1)%3]; Vertex &v1 = vertices[i1]; bool test1=t.err[j] < 0.00000001*l*l*l*l*l; bool test2=(v0.pv1.p).length()<0.3*l; // remove based on edgelength and quadric error if(test1 && test2) { calculate_error(i0,i1,v0.p); //v0.p=(v1.p+v0.p)*0.5; v0.q=v1.q+v0.q; v1.dst=i0; v1.dirty=true; v0.dirty=true; t.deleted=1; deleted_triangles++; break; } } } // update connectivity loopi(0,triangles.size()) if(!triangles[i].deleted) { Triangle &t=triangles[i]; loopj(0,3) if(vertices[t.v[j]].dst>=0) { t.v[j]=vertices[t.v[j]].dst; if(t.v[j]==t.v[(j+1)%3]  t.v[j]==t.v[(j+2)%3] ) { // two equal points > delete triangle t.deleted=1; deleted_triangles++; break; } t.dirty=1; } if(!t.dirty)continue; // update error bool dirty=0; loopj(0,3) dirty=vertices[t.v[j]].dirty; if(!dirty)continue; // update error vec3f p; loopj(0,3) t.err[j]=calculate_error(t.v[j],t.v[(j+1)%3],p); } // clear dirty flag loopi(0,vertices.size()) vertices[i].dirty=0; } } double vertex_error(Matrix q, double x, double y, double z) { return q[0]*x*x + 2*q[1]*x*y + 2*q[2]*x*z + 2*q[3]*x + q[5]*y*y + 2*q[6]*y*z + 2*q[7]*y + q[10]*z*z + 2*q[11]*z + q[15]; } double calculate_error(int id_v1, int id_v2, vec3f &p_result) { Matrix q_bar = vertices[id_v1].q + vertices[id_v2].q; Matrix q_delta ( q_bar[0], q_bar[1], q_bar[2], q_bar[3], q_bar[4], q_bar[5], q_bar[6], q_bar[7], q_bar[8], q_bar[9], q_bar[10], q_bar[11], 0, 0, 0, 1); if ( double det = q_delta.det(0, 1, 2, 4, 5, 6, 8, 9, 10) ) { p_result.x = 1/det*(q_delta.det(1, 2, 3, 5, 6, 7, 9, 10, 11)); p_result.y = 1/det*(q_delta.det(0, 2, 3, 4, 6, 7, 8, 10, 11)); p_result.z = 1/det*(q_delta.det(0, 1, 3, 4, 5, 7, 8, 9, 11)); } else { vec3f p1=vertices[id_v1].p; vec3f p2=vertices[id_v1].p; vec3f p3=(p1+p2)/2; double error1 = vertex_error(q_bar, p1.x,p1.y,p1.z); double error2 = vertex_error(q_bar, p2.x,p2.y,p2.z); double error3 = vertex_error(q_bar, p3.x,p3.y,p3.z); double min_error = min(error1, min(error2, error3)); if (error1 == min_error) p_result=p1; if (error2 == min_error) p_result=p2; if (error3 == min_error) p_result=p3; } double min_error = vertex_error(q_bar, p_result.x, p_result.y, p_result.z); return min_error; }
You can download the full source+mesh data here DOWNLOAD
#5151475 400% Raytracing SpeedUp by ReProjection (Image Warping)
Posted by spacerat on 04 May 2014  03:01 PM
Yes, its related to temporal antialiasing techniques. However there, the geometry is not reused and needs to be rendered again. For the coordinates I also tried different ways but it turned out that using relative coordinates (such as the zbuffer) tend to accumulate the error over multiple frames, and the image is not consistent anymore then.
Transparency is not yet handled and might need special treatment indeed. Its just for opaque surfaces.
To still cache the pixels efficiently even lots of them get coveredup / overwritten, I am using a multi buffer cache. That means the result of a screen is alternately stored in either cache, while both caches are projected to the screen at the beginning before filling the holes by raycasting. That can keep the pixels efficiently, as pixels that are covered up in one frame might already be visible again in the next frame. In general the caching works well. Also its a relaxed caching theme, where not every empty pixel get filled by a ray. The method uses an image filter for filling small holes and only fills holes that are 2x2 pixels large (the threshold can be defined) by raycasting.
If the camera changes to a different view, then obviously the cache cannot be used and the first frame will render slower.
#5151336 400% Raytracing SpeedUp by ReProjection (Image Warping)
Posted by spacerat on 03 May 2014  09:42 PM
Intro I have been working a while on this technology and since realtime raytracing is getting faster like with the Brigade Raytracer e.g., I believe this can be an important contribution to this area, as it might bring raytracing one step closer to being usable for video games.
1. suppress unwanted pixels with a filter by analyzing the depth values in a small window around each pixel. In experiments it removed some artifacts but not all  also had quite an impact on the performance.
2. (not fully explored yet) Assign a speed value to each pixel and use that to filter out unwanted pixels
3. create a quadtreelike triangle mesh in screenspace from the raycasted result. the idea is to get a smoother frametoframe coherence with less pixel noise for far pixels and let the zbuffer do the job of overlapping pixels. Its sufficient to convert one tile from the raycasted result to a mesh per frame. Problem of this method : The mesh tiles dont fit properly together as they are raycasted at different time steps. Using raycasting to fill in holes was not very simple which is why I stopped exploring this method further
http://www.farpeek.com/papers/IIW/IIWEG2012.pdf fig 5b
** Untested Ideas **
4. compute silhouettes based on the depth discontinuity and remove pixels crossing them
5. somehow do a reverse trace in screenspace between two frames and test for intersection
6. use splats to rasterize voxels close to the camera so speckles will be covered
#5136674 Geometry Shaders
Posted by spacerat on 05 March 2014  08:53 PM
Edit / @mhagain:
I apologize. didnt read the question carefully.
Still i believe that here is an performance impact on using geometry shaders as it costs additional computations.
#5135876 GPU Skinned Skeletal Animation Tutorial
Posted by spacerat on 02 March 2014  12:01 PM
Today I completed a skinned skeletal animation tutorial, which is very helpful if you are just about to start with game development.
Different from the other tutorials I found in the web, this one is very light weight ( < 800 lines for the main mesh & animation code ) and works well with most modeling environments.
Summary
It has the following properties / features:
 GPU Skinning / Matrix Palette Skinning
 Bump Mapping (automatic normal map generation)
 Spheric environment mapping
 Ogre XML Based
 Shaders in GLSL
 Visual Studio 2010
 Select LOD level with F1..F5
It is ready to use, which means you can load and display the animated models in a few lines of code:
static Mesh halo("halo.material",// required material file) "halo.mesh.xml",// required mesh file "halo.skeleton.xml");// optional skeleton file int idle = halo.animation.GetAnimationIndexOf("idle"); halo.animation.SetPose(idle, // animation id (2 animations, 0 and 1, are available) time_elapsed); // time in seconds. animation loops if greater than animation time halo.Draw( vec3f(0,0,0), // position vec3f(0,0,0), // rotation 0); // LOD level
.
Also getting a bone matrix to put a weapon in the hand of the player e.g. is very simple:
int index = halo.animation.GetBoneIndexOf("joint1"); matrix44 m = halo.animation.bones[ index ].matrix;
.
Setting the arm joint individually for shooting a weapon e.g. works as follows:( press F6 in the demo ):
// get the index int index = halo.animation.GetBoneIndexOf("joint2"); // get / modify / set the matrix matrix44 m = halo.animation.bones[ index ].matrix; m.x_component()=vec3f(1,0,0); m.y_component()=vec3f(0,1,0); // set the rotation to identity m.z_component()=vec3f(0,0,1); halo.animation.bones[ index ].matrix=m; // reevaluate the child bones loopi(0,halo.animation.bones[ index ].childs.size()) { halo.animation.EvalSubtree( halo.animation.bones[ index ].childs[i], // bone id halo.animation.animations[0], // animation 1); // key frame 1 means not use the animation }
.
Workflow:
 Design the Model in Maya/MAX/Blender/etc.
 Export the model using the OgreExporter
 Convert the model from Ogre binary to Ogre XML (batch file is included)
 Load the model in the tutorial code
Main Skinning in GLSL:
The main skinning is done in the vertex shader and only requires a few lines.
For the shader, the skinning weights are stored in the color information as 3 floats.
The bone IDs are unpacked from the w coordinate of the position information.
The bone matrixes are stored as simple matrix array.
uniform mat4 bones[100]; uniform int use_skinning; void main(void) { mat4 mfinal = gl_ModelViewMatrix ; // skinning if(use_skinning==1) { vec3 weights= gl_Color.xyz; vec3 boneid = gl_Vertex.w * vec3( 1.0/128.0 , 1.0 , 128.0 ); boneid = (boneid  floor(boneid))*128.0; mat4 mskin = bones[int(boneid.x)]*weights.x+ bones[int(boneid.y)]*weights.y+ bones[int(boneid.z)]*weights.z; mfinal = mfinal * mskin; } gl_Position = gl_ProjectionMatrix * mfinal * vec4(gl_Vertex.xyz,1.0); }
#5127168 Geometry Clipmaps Terrain Tutorial with Source
Posted by spacerat on 29 January 2014  04:00 AM
After browsing the web for a usable terrain lib, I ended up writing one myself as the others were simply too bloated.
I am sharing the result now as a tutorial and hope it will help the one or other of you to get started with terrain rendering.
The main code as only 200 lines, so is easy to understand.
Performance is around 1000 fps.
Key settings:
Space : wireframe view
Enter : Topdown view
You can fetch the zip with all required includes from here or from the attachment.
Changelog:
Bugfix applied: glDrawArrays( GL_LINES, 0, vert.size()); (old) > glDrawArrays( GL_LINES, 0, vert.size()/3); (new / ok)
/////////////////////////////////////////// int grid= 64; // patch resolution int levels=5; // LOD levels int width=2048,height=2048; // heightmap dimensions /////////////////////////////////////////// void DrawScene() { if ( GetAsyncKeyState(VK_ESCAPE) ) exit(0); POINT cursor; GetCursorPos(&cursor); // mouse pointer position bool wireframe= GetAsyncKeyState(VK_SPACE); // render wireframe bool topdown = GetAsyncKeyState(VK_RETURN); // view topdown float viewangle= float(cursor.x)/5.0; vec3f viewpos ( (timeGetTime()>>2)&((1<<17)1) , (float(cursor.y)/1000.0)* 0.10.01 , 0 ); glClearDepth(1.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT  GL_DEPTH_BUFFER_BIT); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); static int tex_heightmap=0; static int tex_terrain=0; static bool init=true; static Shader shader("Shader"); static int vbo=0; static std::vector<float> vert; if(init) { /*+++++++++++++++++++++++++++++++++++++*/ // terrain heightmap Bmp bmp(width,height,32); loopj(0,height) loopi(0,width) { float x= float(i)/float(width); float y= float(j)/float(height); float h = (sin(4*M_PI*x)+sin(4*M_PI*y)+sin(16*M_PI*x)*sin(16*M_PI*y))*0.125+0.5; ((float*)bmp.data)[i+j*width]=h; } //bmp.load_float("../result.f32"); // < use this for loading raw float map from file tex_heightmap = ogl_tex_new(width,height,GL_LINEAR_MIPMAP_LINEAR,GL_REPEAT,GL_LUMINANCE16F_ARB,GL_LUMINANCE,bmp.data, GL_FLOAT); /*+++++++++++++++++++++++++++++++++++++*/ // terrain texture loopj(0,height) loopi(0,width) loopk(0,3) { bmp.data[(i+j*width)*3+k]=i^j^(k*192); } tex_terrain = ogl_tex_new(width,height,GL_LINEAR_MIPMAP_LINEAR,GL_REPEAT,GL_RGB,GL_RGB,bmp.data, GL_UNSIGNED_BYTE); /*+++++++++++++++++++++++++++++++++++++*/ // driver info std::cout << "GL_VERSION: " << glGetString(GL_VERSION) << std::endl; std::cout << "GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; std::cout << "GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; std::cout << "GLU_VERSION: " << gluGetString(GLU_VERSION) << std::endl; std::cout << "GLUT_API_VERSION: " << GLUT_API_VERSION << std::endl; /*+++++++++++++++++++++++++++++++++++++*/ // load shaders shader.attach(GL_VERTEX_SHADER,"../shader/vs.txt"); shader.attach(GL_FRAGMENT_SHADER,"../shader/frag.txt"); shader.link(); /*+++++++++++++++++++++++++++++++++++++*/ // make vbo quad patch loopj(0,grid+1) loopi(0,grid+2) { loopk(0, ((i==0) ? 2 : 1) ) { vert.push_back(float(i)/grid); vert.push_back(float(j)/grid); vert.push_back(0); } ++j; loopk(0, ((i==grid+1) ? 2 : 1) ) { vert.push_back(float(i)/grid); vert.push_back(float(j)/grid); vert.push_back(0); } j; } /*+++++++++++++++++++++++++++++++++++++*/ glGenBuffers(1, (GLuint *)(&vbo)); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vert.size(),&vert[0], GL_DYNAMIC_DRAW_ARB ); /*+++++++++++++++++++++++++++++++++++++*/ init=false; /*+++++++++++++++++++++++++++++++++++++*/ } glMatrixMode( GL_PROJECTION); glLoadIdentity(); if (topdown) { glOrtho(1.0, 1.0, 1.0, 1.0, 1.0, 1.0); glRotatef(180,1,0,0); wireframe^=1; } else { int vp[4]; glGetIntegerv(GL_VIEWPORT, vp); gluPerspective(90.0,float(vp[2])/float(vp[3]) , 0.0001, 1.0); glTranslatef(0,viewpos.y,0); // set height glRotatef(130,1,0,0); glRotatef(viewangle,0,0,1); // set rotation } matrix44 mat; glGetFloatv(GL_PROJECTION_MATRIX, &mat.m[0][0]); // Enable VBO glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer ( 3, GL_FLOAT,0, (char *) 0); glEnable(GL_TEXTURE_2D); glActiveTextureARB( GL_TEXTURE0 ); glBindTexture(GL_TEXTURE_2D, tex_heightmap); glEnable(GL_TEXTURE_2D); glActiveTextureARB( GL_TEXTURE1 ); glBindTexture(GL_TEXTURE_2D, tex_terrain); // Triangle Mesh shader.begin(); shader.setUniform1i("tex_heightmap",0); shader.setUniform1i("tex_terrain",1); float sxy=2; // scale x/y shader.setUniform4f("map_position", viewpos.x/float(2*512*grid), viewpos.z/float(2*512*grid),0,0); loopi(0,levels) { float ox=(int(viewpos.x*(1<<i))&511)/float(512*grid); float oy=(int(viewpos.z*(1<<i))&511)/float(512*grid); vec3f scale (sxy*0.25,sxy*0.25,1); shader.setUniform4f("scale" , scale.x,scale.y,1,1); loopk(2,2) loopj(2,2) // each level has 4x4 patches { if(i!=levels1) if(k==1k==0) if(j==1j==0) continue; vec3f offset(ox+float(j),oy+float(k),0); if(k>=0) offset.y=1.0/float(grid); // adjust offset for proper overlapping if(j>=0) offset.x=1.0/float(grid); // adjust offset for proper overlapping //cull int xp=0,xm=0,yp=0,ym=0,zp=0; looplmn(0,0,0,2,2,2) { vec3f v = scale*(offset+vec3f(l,m,float(n)*0.05)); // bbox vector vec4f cs = mat * vec4f(v.x,v.y,v.z,1); // clipspace if(cs.z< cs.w) zp++; if(cs.x<cs.w) xm++; if(cs.x>cs.w) xp++; if(cs.y<cs.w) ym++; if(cs.y>cs.w) yp++; } if(zp==0  xm==8  xp==8  ym==8  yp==8)continue; // skip if invisible //render shader.setUniform4f("offset", offset.x,offset.y,0,0); if(wireframe) glDrawArrays( GL_LINES, 0, vert.size()/3); else glDrawArrays( GL_TRIANGLE_STRIP, 0, vert.size()/3); } sxy*=0.5; } shader.end(); // Disable VBO glDisableClientState(GL_VERTEX_ARRAY); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glutSwapBuffers(); } /////////////////////////////////////////// int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA  GLUT_DOUBLE  GLUT_ALPHA  GLUT_DEPTH); glutInitWindowSize(1024, 512); glutInitWindowPosition(0, 0); glutCreateWindow("Geometry Clipmaps Example"); glutDisplayFunc(DrawScene); glutIdleFunc(DrawScene); glewInit(); wglSwapIntervalEXT(0); glutMainLoop(); return 0; } ///////////////////////////////////////////
Attached Files
 Terrain_GeometryClipmaps_compatible.zip 736.62KB 158 downloads
#5122944 C++ templates, are they worth it?
Posted by spacerat on 11 January 2014  05:40 PM
well, templates can partially be replaced by the new "auto" type in c++
#5086412 3D voxel painter  feedback appreciated
Posted by spacerat on 16 August 2013  01:20 AM
>> Could you add different starting sizes, so if I make a character I could work on the hand in a small file and import it to a larger file when done?