Any good examples of 3D vector programming?

The place for codemasters or beginners to talk about programming any language for the Spectrum.
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: Any good examples of 3D vector programming?

Post by catmeows »

Btw. the "Restoring 16 / 16 Unsigned" is actually "Restoring 16 / 15 Unsigned ", it has same flaw of losing bits when highest bit of divisor is set.
Proud owner of Didaktik M
Art
Manic Miner
Posts: 206
Joined: Fri Jul 17, 2020 7:21 pm

Re: Any good examples of 3D vector programming?

Post by Art »

catmeows wrote: Wed Jan 05, 2022 5:10 pm

Code: Select all

	.ORG 40000

	ld hl, 0  ;dividend
	ld c, 0   ;divisor
	ld b, 16
	xor a
loop	
	add hl, hl	;11
	rla 		;4
	jr c, divide1   ;7
	cp c		;4
	jr c, divide1a  ;7
divide1
	sub c           ;4
	inc hl          ;6 -> 43 ticks
divide1a
	djnz loop       
	ld l, c
	ld b, h
	ret
I believe you are able to unroll the code.
Speedwise, the longest branch is few ticks shorter than shortest branch of "Restoring 16 / 16 Unsigned", so there may be slight improvement.
Thank you, it works! Only I had to remove "ld l,c" and "ld b,h" at the end. I guess you wanted to copy hl to bc, so probably "ld l,c" should be "ld c,l".
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: Any good examples of 3D vector programming?

Post by catmeows »

Art wrote: Wed Jan 05, 2022 10:12 pm Thank you, it works! Only I had to remove "ld l,c" and "ld b,h" at the end. I guess you wanted to copy hl to bc, so probably "ld l,c" should be "ld c,l".
Sorry, it was typo, I put result into BC because Basic USR function returns BC register and I tested it from Basic.
Proud owner of Didaktik M
Art
Manic Miner
Posts: 206
Joined: Fri Jul 17, 2020 7:21 pm

Re: Any good examples of 3D vector programming?

Post by Art »

Some improvement:
http://phoenix.inf.upol.cz/~rachunl/test/3d15.mp4

I managed to make some computations a bit faster, line drawing a bit faster, repaired a drawing bug and added filled background mountains.

I still should figure out how to compute face visibility more precisely (I mutliply a face normal vector with a camera vector and look for the result sign), because sometimes a hidden face shows when it's on the edge of visibility, but on the other hand, I saw that it also hapens in Elite. So maybe it can't be more accurate if it must be fast.

As for line drawing, I tried several drawing routines. The first one computes screen pixel coordinates and then it converts them to screen addresses. It's probably partially based on the ROM draw routine, but faster, and the conversion of coordinates to addresses is definitely faster. I found it somewhere and I modified it for my game.

Then I rewrote it to compute directly with screen addresses without pixel coordinates, so it didn't use any conversion of coordinates to addresses. It's based on horizontal bit rotations and vertical screen line stepping. It's probably faster than the previous routine, but unfortunately I still need screen pixel coordinates, because I use height buffers, so finally I couldn't use it. But it could be useful if I will write another game with simple transparent wireframe graphics.

There is still some image tearing during movements, but I can't probably improve it on a Spectrum 48K. Or is it possible to transfer 6912 bytes between two screen frames?
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: Any good examples of 3D vector programming?

Post by catmeows »

Art wrote: Fri Jan 21, 2022 2:52 pm Some improvement:
http://phoenix.inf.upol.cz/~rachunl/test/3d15.mp4

I managed to make some computations a bit faster, line drawing a bit faster, repaired a drawing bug and added filled background mountains.
I really like the result, it is fast and nice looking engine. I mean, Elite is somewhat faster but it also looks less solid. Your engine feels more like Freescape but with double or triple framerate.
Art wrote: Fri Jan 21, 2022 2:52 pm I still should figure out how to compute face visibility more precisely (I mutliply a face normal vector with a camera vector and look for the result sign), because sometimes a hidden face shows when it's on the edge of visibility, but on the other hand, I saw that it also hapens in Elite. So maybe it can't be more accurate if it must be fast.
I was looking through video few times and I did not notice any glitch.
There is still some image tearing during movements, but I can't probably improve it on a Spectrum 48K. Or is it possible to transfer 6912 bytes between two screen frames?
Maybe you could resolve tearing by starting you copy routine at particular moment.

When you copy data in single turn you first copy all pixels and then all attributes. But ULA reads both pixels and attribute when it generates video. So if you divide copy job into three sections: I) copy top half of pixels, II) copy all attributes, III) copy bottom half of pixels, you would have better chance that when ULA starts to read upper screen area, you have both pixels and attribute at place. And while ULA is displaying top half, you finish copy job to bottom half.
I really don't know if you can copy whole screen in time but I tried same thing for 22 character tall screen and it worked.
Proud owner of Didaktik M
Art
Manic Miner
Posts: 206
Joined: Fri Jul 17, 2020 7:21 pm

Re: Any good examples of 3D vector programming?

Post by Art »

catmeows wrote: Sat Jan 22, 2022 12:51 am I really like the result, it is fast and nice looking engine. I mean, Elite is somewhat faster but it also looks less solid. Your engine feels more like Freescape but with double or triple framerate.
Thank you! And I must also thank to several other people in this thread with their advices, helpful links and good ideas.

Yes, I wanted to create something with graphics like Elite or Cholo, but with hidden lines for the whole scene together, and with solid walls like Driller, but coloured and faster. At first, the colour fills looked quite ugly, but at least it hid the colour boundary between ground and sky. Finally I imrpoved it with roof dithering, moving colour fill down in the roof and careful horizontal shifting of the vertical lines near attribute boundaries. It's not perfect and maybe it can still be impoved a bit, but I am satisfied with the result.
catmeows wrote: Sat Jan 22, 2022 12:51 am
Art wrote: Fri Jan 21, 2022 2:52 pm I still should figure out how to compute face visibility more precisely (I mutliply a face normal vector with a camera vector and look for the result sign), because sometimes a hidden face shows when it's on the edge of visibility, but on the other hand, I saw that it also hapens in Elite. So maybe it can't be more accurate if it must be fast.
I was looking through video few times and I did not notice any glitch.
Fortunately it happens quite rarely. It can be seen for example here. The left face should be hidden.
Image
catmeows wrote: Sat Jan 22, 2022 12:51 am
Art wrote: Fri Jan 21, 2022 2:52 pm There is still some image tearing during movements, but I can't probably improve it on a Spectrum 48K. Or is it possible to transfer 6912 bytes between two screen frames?
Maybe you could resolve tearing by starting you copy routine at particular moment.

When you copy data in single turn you first copy all pixels and then all attributes. But ULA reads both pixels and attribute when it generates video. So if you divide copy job into three sections: I) copy top half of pixels, II) copy all attributes, III) copy bottom half of pixels, you would have better chance that when ULA starts to read upper screen area, you have both pixels and attribute at place. And while ULA is displaying top half, you finish copy job to bottom half.
I really don't know if you can copy whole screen in time but I tried same thing for 22 character tall screen and it worked.
Interesting idea! When I look at my game, it looks like the tearing always happens in the top part of the screen, so maybe it will help. I will try it. As for starting the copy routine at a particular moment, how does it work? Is it based on an interrupt? Now I have interrupt disabled during the whole game.
Image
User avatar
Stefan
Manic Miner
Posts: 822
Joined: Mon Nov 13, 2017 9:51 pm
Location: Belgium
Contact:

Re: Any good examples of 3D vector programming?

Post by Stefan »

The result looks fantastic! The use of colour makes it look much much better than any other 3D I’ve seen on the Speccy. While the full screen is also rather unseen, maybe you could see what the effect is of using a smaller window, obviously not as small as the ultimate isometric titles, but just to see what the effect is on frame rate.
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: Any good examples of 3D vector programming?

Post by catmeows »

Art wrote: Sat Jan 22, 2022 9:51 am
Interesting idea! When I look at my game, it looks like the tearing always happens in the top part of the screen, so maybe it will help. I will try it. As for starting the copy routine at a particular moment, how does it work? Is it based on an interrupt? Now I have interrupt disabled during the whole game.
Image
What you really need is to read this article (section Hardware/48K ZX Spectrum) : https://worldofspectrum.org/faq/referen ... erence.htm
ULA starts reading memory about 14336 ticks after interrupt and it displays one pixel line every 224 ticks. So it looks like this.

Code: Select all

 cycle 14436: generating video for top left byte (pixels at 16384, attribute 22528)
 cycle 14440: generating video for next byte on the right  (pixels at 16385, attribute 22529)
 ....
 cycle 14660: generating video for most left byte, second from top (pixels at 16384+256, attribute 22528)
 
The whole magic of avoiding tearing is that you write into video RAM between two passes ULA readings. It seems impossible, as ULA starts reading screen at time X and at time X+70000 cycles it starts again and 70K cycles is not enough to copy whole screen. BUT: focus what is real state of things at time X+70000 cycles: ULA starts reading screen, your copy routine meanwhile copies bytes for bottom of screen. That means that ULA will reach byte you are copying right now after some time - it needs to generate display for all lines that are above your current copy position. That gives you more time to finish copy.
An idealized version would look like this:

Code: Select all

TIME 0: ULA reads first byte of video (with old content)
TIME 4: ULA reads second byte of video (with old content), your copy routine copies first byte (new content)
....
TIME 70000: ULA reads first byte of video (with new content), your copy routine copies Xth byte (new content)
TIME 70000+?: ULA reads Xth byte of video (with new content), your copy routine copies (X + ?)th byte (new content)
Eventually, you may be able to finish copy before ULA reach last byte of screen.

But there is a catch, pixel area is not linear and attribute area goes after pixels. But you want to have both new pixels and attribute at place when ULA starts reading top of screen.
Handling attributes is quite easy, you copy top half of screen pixels and then attributess and if you manage do that before TIME 70000, there will be no tearing. Then you copy bottom half of pixels and if you manage do that before TIME 70000+192lines*224tick per line= TIME 113000, there will be no tearing in bottom half.

Handling pixels is more tricky. Pixel area is non linear, bytes 16384-16415 describe first line, bytes 16416-16447 describe 8th line and so on. But ULA reads line at 16384, then line at 16640 and so on.
What really happens at your screenshot is that for first third of screen, you copy about 1500 bytes, 6 pixel lines for each character line when ULA catch you and starts displaying old content. Next frame is copy finished and ULA displays new content for whole screen.
Simply said, thanks to screen non linear layout, your copy routine sometimes writes to memory already processed by ULA and sometimes writes to memory that will be processed by ULA.

One thing you could do is change your copy routine to copy line after line (32 bytes to 16384, then 32 bytes to 16640 and so on) and start your copy about 14500 cycles after interrupt. That would secure that copy routine will always copy to memory that was processed by ULA already.

Second solution is to postpone your copy routine to time when ULA generates second third of screen. That is to time about 28800 cycles after interrupt. That completely discards problems with non linearity, as ULA displays second third of screen when you copy into first third.

Both solutions have clear disadvantage, you introduce delay into your loop, either 14.5K or 28.8K cycles . If you don't want to waste that time completely, you can spend that time by doing something that takes always same amount time. It could be beeper sound routine that is designed to take exact time or some house cleaning routine with almost constant running time.
Proud owner of Didaktik M
Art
Manic Miner
Posts: 206
Joined: Fri Jul 17, 2020 7:21 pm

Re: Any good examples of 3D vector programming?

Post by Art »

Thank you, it works! I've just added this before the screen copy:

Code: Select all

        pop iy
        ei
        halt
        di
        push iy
        ld bc,1000
copy1   dec bc
        ld a,b
        or c
        jr nz,copy1
The waiting value of 1000 was just for testing, but the image tearing completely diappeared. So if I understand well: If I want to do something else instead of wasting time for waiting, I should wait for an interrupt, then count cycles for every instruction to be sure that it takes about 14500 cycles after the interrupt, and after that part copy the screen.

As for "pop iy" and "push iy", I am not sure if it's necessary, but I figured out during programming 3D computations that if I don't use "push iy" after "di" and "pop iy" before "ei", the iy register is messed up.
Art
Manic Miner
Posts: 206
Joined: Fri Jul 17, 2020 7:21 pm

Re: Any good examples of 3D vector programming?

Post by Art »

Stefan wrote: Sat Jan 22, 2022 10:42 am The result looks fantastic! The use of colour makes it look much much better than any other 3D I’ve seen on the Speccy. While the full screen is also rather unseen, maybe you could see what the effect is of using a smaller window, obviously not as small as the ultimate isometric titles, but just to see what the effect is on frame rate.
Thank you! Yes, it looks better with colours like this and it would be a little faster in a smaller window, but I think that the attribute fill (black and blue) would be too blocky in a smaller window. But if I will make another game without a colour fill, I will experiment with smaller window.
Post Reply