Stuck in Projection

Blitz3D Forums/Blitz3D Programming/Stuck in Projection

jfk EO-11110(Posted 2016) [#1]
I am currently prototyping a simple softrenderer and I got stuck in a problem, that is when some vertices of a triangle are in front of and some others are behind the camera. As the camera is the focus point, x/y is flipped behind it, well, I don't know how to handle that. Here's the code, quite a piece, the important sections are labeled with "STUCK", just use Search.

Thanks.




jfk EO-11110(Posted 2016) [#2]
btw. just fixed 1 bug.


Flanker(Posted 2016) [#3]
Nice little engine :)

Here what I can see is that when you walk in one direction, close to walls, one half of the walls are rendered correctly, and when you inverse your direction the other half is rendered correctly. And it's always every 2 walls.


jfk EO-11110(Posted 2016) [#4]
Thanks, yes, that is when you/the first person rotates, the triangle / quad in front of you at some point is more beside you and one part of the vertices slips behind the camera. Currently these special triangles are not rendered, which is why they pop in and out, depending on camera angle. That is precisely the issue.


Flanker(Posted 2016) [#5]
On the screenshot, every white wall is rendered if I go forward next to them. If I turn 180°, it's the other half that will be rendered correctly. So what's the difference beetween one half and the other ?




jfk EO-11110(Posted 2016) [#6]
Flanker, thanks for "going in there" ^^, I see where your mistake is: such a white wall is only half an actual wall, or quad in this simple wolfenstennoid mesh. So now reading again my prev. explanation makes sense: as you slide along the wall, the closer two corners of one wall-quad will at some point be behind the camera. Then it won't be rendered, because I coded it so, because it would look messed up, wrong. You can try that, somewhere after one of the "STUCK!!!" comments its says "unrem this line to see the mess" or something similar. Have a look at the code, I tried to comment everything. That being said, this source does contain a fully functional perspectivecorrected texturemapper, I'll post that one in the archive I think.
Thanks again.

Edit: arrrgh I am so impatient, just sneaking around, waiting for some help but I may find some examples elsewhere (any links to eg. cpp sources? like fps mouselook all software rendering)


Bobysait(Posted 2016) [#7]
You've got a mispelled variable on your camera gameplay
;' turn
If KeyDown(203) ;' Left
fam_a#=cam_a#+5

fam_a against cam_a

Whatever, It will surely not fix the issue
I (maybe) managed to fix the issue by rebuilding the projection according to the z value (just pushing the z to fit the viewport, then remapping the 3 coords and finally recomputing the 2d projections witht the new coordinates)

If (zw[i]<clip0) Or (zw[i+1]<clip0) Or (zw[i+2]<clip0) Or (zw[i+3]<clip0) Then
			;' STUCK!!!
			;' this polygon has some vertices in front of the camera And some behind it. The problem is, those behind the camera
			;' have totally messed up 2D coords, what am I doing wrong?
			
			Local Isbehind:Int[] = [zw[i]<clip0, zw[i+1]<clip0, zw[i+2]<clip0, zw[i+3]<clip0]
			Local SegZ:Float, Zclip0:Float, DVz:Float;
			' find the point(s) behind the camera
			Local iX:Int, iY:Int;
			For iX = 0 To 3
				' for all points behind the camera, find another one that is front of the camera
				' then translate the vertex along the segment from the vertex behind to the vertex front
				If (Isbehind[iX])
					Local iN0:Int = i+iX;
					For iY = 0 To 3
						' find any other that is front (obviously, don't compare to itself)
						' also, don't project along the diagonal of the polygon or it will make a hole.
						If (iX<>iY) And (Abs(iX-iY)<2)
							' don't use another point that was previously behind
							If (Isbehind[iY] = 0)
								' found one
								Local iN1:Int = i+iY;
								' distance from point behind to point front (on Z axis)
								SegZ = zw[iN1]-zw[iN0];
								' distance from point behind to clip0 (and a little bit further)
								Zclip0 = (clip0+1) - zw[iN0];
								' ratio of small segment by full segment
								DVz = Zclip0/SegZ;
								' new z is the clip0 value (+ a small gap)
								zw[iN0] = clip0+1;
								' then rebuild projection
								Local x__:Float = xwww[iN0] + (xwww[iN1]-xwww[iN0]) * DVz
								Local y__:Float = ywww[iN0] + (ywww[iN1]-ywww[iN0]) * DVz
								Local z__:Float = zwww[iN0] + (zwww[iN1]-zwww[iN0]) * DVz
								ProjectCoords ( res, cam_xx, cam_zz, CamZoom, l_Ca, l_Sa, x__,y__,z__ )
								xw[iN0] = res[0]
								yw[iN0] = res[1]
								zw[iN0] = res[2]
								' found a good projection point, don't test further.
								Exit;
							EndIf;
						EndIf;
					Next;
				EndIf;
			Next


(i've put the conversion in a function, else it was a bit messy)

Function ProjectCoords(pResult:Float[], pXx:Float, pZz:Float, pZoom:Float, pCa:Float,pSa:Float, pX:Float,pY:Float,pZ:Float)
	Local xl3:Float = (pX+pXx)*pCa + (pZ+pZz)*pSa;
	Local yl3:Float = pY;
	Local zl3:Float = (pZ+pZz)*pCa - (pX+pXx)*pSa;
	Local zl3_640:Float = zl3+real640
	If (zl3_640=0) Then zl3_640=.000001 ;' prevent division by zero
	zl3_640 = 1.0/zl3_640
	Local xloc:Float, yloc:Float;
	If (zl3_640>0)
		yloc = yl3*real640 * zl3_640
		xloc = xl3*real640 * zl3_640
	Else
		yloc = -yl3*real640 * zl3_640
		xloc = -xl3*real640 * zl3_640
	EndIf
	pResult[0] = (pZoom*xloc) +160 ;' additional onscreen zoom factor camZoom
	pResult[1] = (pZoom*yloc) +120
	pResult[2] = (zl3+realb640) ;' remember this For Z-sorting
End Function



And here is the full code (it's blitzmax, sorry for that, I'm not on windows so I had to translate it for blitzmax on the mac)




jfk EO-11110(Posted 2016) [#8]
Wow, that must have been quite some work, thanks a lot! As far as i see, you are doing something similar like it dawned to me late yesterday. Basicly just prevent any relevant vertices from landing behind the camera at all, keep them in a positive Zone, in terms of transformed Z...?

I'll study this closely, thank you very much.


Bobysait(Posted 2016) [#9]

that must have been quite some work


not that much actually, I'd say half an hour, the translation in blitzmax is more "Find and replace" so it's pretty fast (then I enabled the superstrict mode so I replaced some variables and used a pixmap for rendering, but it's not really a hard task)
In the end, I find this really interesting and entertaining ^_^


Basicly just prevent any relevant vertices from landing behind the camera at all, keep them in a positive Zone, in terms of transformed Z...?


Yes, it's exactly that

If it can help hilighting the process, this is what I've done :


I projected the z in 2D then used the "Z to Clip / Z Dist" on the 3D coords using a simple linear interpolation (v' = v0 + (v1-v0) * Dz )
I finally used the new 3d coords to compute the new 2D coords.
There is probably a faster way to do it using the 2D coords, but I didn't really investigate how the engine works, so I've almost no idea where the formulas come from :)



ps : Notice that the projection will probably make the texture projection stretch, so it should be usefull to check the edges length to render to recompute the UVs on the rendering of the textures.


jfk EO-11110(Posted 2016) [#10]
Ok, thanks, yes, that texture distortion thing does pop in occassionally when I mess with the projection values by Toshi. I thought perspective correction would solve it, but it does so only within certain parameters.

Ok, got some fascinating work in front of me ^^