Gradient of a triangle
Blitz3D Forums/Blitz3D Programming/Gradient of a triangle
| ||
Hello, Does anyone have an algorithm that finds the gradient/slope of a 3D triangle, or know how to do this? I want to use it to create a function that will split a terrain mesh into 2 surfaces, one containing triangles with a slope less than a critical gradient and ones with triangles with steeper slopes. In other words, it will split a terrain mesh into a surface for a cliff texture, and a surface for a grass texture with great ease. I'll post the code in the archives when it's written. |
| ||
Try this. Not tested but the theory is sound, so just play with it.function triGrad#(surface,tri,axis) local vx#,vy#,vz#,sx#,sy#,sz# local bx#,by#,bz# for v=0 to 2 vert =triangleVertex(surface,tri,v) vx#=vertexX(surface,vert) vy#=vertexY(surface,vert) vz#=vertexZ(surface,vert) if vx<sx sx=vx if vx>bx bx=vx if vy<sy sy=vy if vy>by by=vy if vz<sz sz=vz if vz>bz bz=vz next select axis case 1 ;X return bx-sx case 2 ;Y return by-sy case 3 ;Z return bz-sz end select end function The grad will always be positive, as there's no real way(that I know of) to tell if a tri is going up or going down as it's entirely down to perception...But still, the bigger the grad, the more steep it is..so it makes no diff in your case I don't think. To get the grad of a tri regardless of axis, try this 'wrapper' function triangleGradient#( surface,triangle) for j=0 to 2 tl=tl+triGrad(surface,triangle,j) next return (tl/3.) end function |
| ||
hmmm. doesn't seem like that really works I'm afraid. I hope it is that simple though :O) It needs to work out the maximum gradient of the plane that the 3 points in the triangle define. I've a feeling that this will require a bit of matrix algebra. I've just found this which gives the equation of a plane. http://astronomy.swin.edu.au/~pbourke/geometry/planeeq/ I'm now just trying find something that can link this equation to the plane's gradient. . . Perhaps though, I'm just missing something and it is much simpler. . . if someone thinks of a simple way - please put me out of my misery :O) |
| ||
Oh well, the above returns the averaged grad of all 3, not max. Max/biggest grad would be, function maxGrad(surface,triangle) for v=0 to 2 grad#=triGrad(surface,triangle,v) if grad>big_grad# big_grad=grad next return big_grad end function If that doesn't do the trick we're clearly thinking of differant things ;) |
| ||
Yep, we are thinking of different things - your function returns the x,y or z dimension (size) of the triangle. i.e. the width, length or height of the space it occupies, not the gradient. Thanks for the suggestion though. . . unless I can figure out the maths to calculate the gradient, I might have use the height! |
| ||
Well this what happens when I try to act smart. I end up looking stupid. ;) Good luck, but other than this I'm not sure how else to do it. |
| ||
for any 2 points in 3d x = x2-x1 y = y2-y1 z = z2-z1 d = sqr(x*x+z*z) ; flat distance from pt1 to pt2 slope = abs(y)/d ; 1=45 degree slope to find the steepest slope on a triangle, do for each pair of points and take the max slope |
| ||
Thanks, that's closer to the mark i think - i had already considered this, but it is possible to have a triangle who's plane is vertical (infinite gradient) but the gradient of each edge could be really small. For example: (0,0,0)-(10,1,0)-(20,0,0) In this case, the steepest edge has a gradient of 0.1 but clearly the triangle is vertical. However, I think I've just thought out a method of calculating the actual gradient without any really nasty maths - just using simple geometry. It's tricky to visualise or describe without diagrams, but here is the outline as best as I can put it in words. *NOTE: x(v), y(v) and z(v) are the respective x,y and z coordinates of vertex/point v. Step1: sort out vertices in order of height (y-axis), v0=bottom, v1=middle, v2=top Step2: find point a, such that y(a) = y(v1) and a is on the line (v0,v2) step3: find point b, such that y(b) = y(v1) and x(b) = x(v2) and z(b) = z(v2) step4: find point c, such that c is on the line (v1, a) and the angle (v1,b,c) = 90 degrees step5: dy = y(v2) - y(v1) dx = x(b) - x(c) dz = z(b) - z(c) dxz = sqr(dx*dx + dz*dz) GRADIENT = dy/dxz I think I can manage to implement this. If it works, I'll put it in the archives. . . |
| ||
Sorry -- I made the assumption that your terrain was originally constructed from height map data such that true vertical surfaces wouldnt be possible. The general solution is: 1. translate lowest point to 0,0,0 2. extend line between other 2 points to touch y=0 3. touch point becomes new middle point of triangle 4. rotate triangle so that bottom 2 points are at x=0, y=0 5. highest point y/z = slope, if z=0, its vertical |
| ||
Thanks ZombieWoof, that looks reasonable to code too. Probably even simpler than my method. I'll give it a try. . . |
| ||
cant you get the normals of the 3 vertices of the triangle and take an average, then compare triangles by normals rather than gradient? |
| ||
Thats what I get for not being that deep into 3D mesh stuff simpler solution, average the normals of the vertices, the normal the opposite of the slope, compute: x = (nx1+nx2+nx3)/3 y = (ny1+ny2+ny3)/3 z = (nz1+nz2+nz3)/3 d = sqr(x*x+z*z) s = d/y ; was y/d in last version if y=0, the triangle is flat, no slope slope = 1 is 45 deg, higher numbers are steeper |
| ||
I have just finished coding the solution using ZombieWoof's second method. This is more precise than using the normals, because it's possible for the vertex normals to be wrong, or used differently for various unusual lighting effects etc. The code is here: http://blitzbasic.com/codearcs/codearcs.php?code=1093 |