Here is a technique which is quite cool. Here's how it works.
Let's say that you have four corners of a square..
;D :) :) :) ;D
:) :) :) :) :)
:) :) :) :) :)
:) :) :) :) :)
;D :) :) :) ;D
And you wanted to make it more detailed I figured that you could just divide the opposite corners like;
centrex = (x1+x2) / 2
centrey = (y1+y2) / 2
And easily get this;
;D :) ;D :) ;D
:) :) :) :) :)
;D :) :) :) ;D
:) :) :) :) :)
;D :) ;D :) ;D
From the four original points. I figured that this technique would be quite useful for making low overhead dot cubes, it would be possible to make a cube out of the 8 corner points and recursively subdivide the points to make the cube as detailed as you wanted but only ever having to rotate the original 8 corner points.
Then I thought that wasn't even the best way of doing it so I decided to interpolate, almost as if I was writing a texture mapping routine and I've got the listing below so far.. I am going to apply it to some 3D models in my next intro and do some transformations and other stuff to them.
First and unoptimised test;
'
' This technique is going to form the basis for a demo effect.
' Basically it uses an interpolation technique to subdivide the 4 corners
' Of a cube,this will make it possible to do relly complex dot cubes and make transformations
' a simple matter and also save the overheads of rotating all those points as only the corners
' will ever need to be rotated.
'
' Coded by Shockwave / DBF
' Do not rip without credit :-)
'
' See you in the finished intro..
'
'---------------------------------------------------------------------------
OPTION STATIC
OPTION EXPLICIT
'-------------------------------------------------------------------------
' Includes.
'-------------------------------------------------------------------------
'#define PTC_WIN
#Include Once "tinyptc.bi"
Const XRES=640 'Screen Width
Const YRES=480 'Screen Height
const SUBDIVISIONS = 20 ' How many dots per line?
DECLARE SUB DRAW_DOT_FACE(BYVAL X1 AS DOUBLE , BYVAL Y1 AS DOUBLE,BYVAL X2 AS DOUBLE , BYVAL Y2 AS DOUBLE , BYVAL X3 AS DOUBLE , BYVAL Y3 AS DOUBLE , BYVAL X4 AS DOUBLE , BYVAL Y4 AS DOUBLE)
DIM SHARED AS INTEGER BUFFER ( XRES * YRES )
If( ptc_open( "DBF SCREEN", XRES, YRES ) = 0 ) Then
End -1
End If
DIM XA,XB,XC,XD,YA,YB,YC,YD
DIM SHARED GADD,GADD2 AS DOUBLE
DO
GADD=GADD+.004
GADD2=GADD2+.005
XA = 320+(200*SIN(GADD ))
XB = 320+(200*SIN(GADD + 90))
XC = 320+(200*SIN(GADD2 + 180))
XD = 320+(200*SIN(GADD2 + 270))
YA = 240+(200*COS(GADD2))
YB = 240+(200*COS(GADD2 + 90))
YC = 240+(200*COS(GADD + 70))
YD = 240+(200*COS(GADD + 40))
DRAW_DOT_FACE(XA,YA, XB,YB, XC,YC, XD,YD )
PTC_UPDATE@BUFFER(0)
ERASE BUFFER
SLEEP 1
LOOP UNTIL INKEY$=CHR$(27)
SUB DRAW_DOT_FACE(BYVAL X1 AS DOUBLE , BYVAL Y1 AS DOUBLE,BYVAL X2 AS DOUBLE , BYVAL Y2 AS DOUBLE , BYVAL X3 AS DOUBLE , BYVAL Y3 AS DOUBLE , BYVAL X4 AS DOUBLE , BYVAL Y4 AS DOUBLE)
DIM AS INTEGER SA,SB
DIM AS DOUBLE INTERX,INTERY , XXP , YYP
DIM AS DOUBLE TOPX (SUBDIVISIONS)
DIM AS DOUBLE TOPY (SUBDIVISIONS)
DIM AS DOUBLE BOTX (SUBDIVISIONS)
DIM AS DOUBLE BOTY (SUBDIVISIONS)
'
' CALCULATE TOP LINE.
'
INTERX = (X1-X2) / SUBDIVISIONS
INTERY = (Y1-Y2) / SUBDIVISIONS
XXP = X1
YYP = Y1
FOR SA = 1 TO SUBDIVISIONS
TOPX(SA) = INT(XXP)
TOPY(SA) = INT(YYP)
XXP=XXP-INTERX
YYP=YYP-INTERY
BUFFER(TOPX(SA)+(TOPY(SA) * XRES)) = &HFFFFFF
BUFFER(TOPX(SA)+((TOPY(SA)-1) * XRES)) = &HFFFFF
BUFFER(TOPX(SA)+((TOPY(SA)+1) * XRES)) = &HFFFFFF
BUFFER((TOPX(SA)-1)+(TOPY(SA) * XRES)) = &HFFFFFF
BUFFER((TOPX(SA)+1)+(TOPY(SA) * XRES)) = &HFFFFFF
NEXT
'
' CALCULATE BOTTOM LINE.
'
INTERX = (X3-X4) / SUBDIVISIONS
INTERY = (Y3-Y4) / SUBDIVISIONS
XXP = X3
YYP = Y3
FOR SA = 1 TO SUBDIVISIONS
BOTX(SA) = INT(XXP)
BOTY(SA) = INT(YYP)
XXP=XXP-INTERX
YYP=YYP-INTERY
BUFFER(BOTX(SA)+(BOTY(SA) * XRES)) = &HFFFFFF
BUFFER(BOTX(SA)+((BOTY(SA)+1) * XRES)) = &HFFFFFF
BUFFER(BOTX(SA)+((BOTY(SA)-1) * XRES)) = &HFFFFFF
BUFFER((BOTX(SA)-1)+(BOTY(SA) * XRES)) = &HFFFFFF
BUFFER((BOTX(SA)+1)+(BOTY(SA) * XRES)) = &HFFFFFF
NEXT
'
' CALCULATE MIDDLES;
'
FOR SB=1 TO SUBDIVISIONS
INTERX = (TOPX(SB)-BOTX(SB)) / SUBDIVISIONS
INTERY = (TOPY(SB)-BOTY(SB)) / SUBDIVISIONS
XXP = TOPX(SB)
YYP = TOPY(SB)
FOR SA = 1 TO SUBDIVISIONS-1
XXP=XXP-INTERX
YYP=YYP-INTERY
BUFFER(INT(XXP)+(INT(YYP) * XRES)) = &HFFFFFF
BUFFER(INT(XXP-1)+(INT(YYP) * XRES)) = &HFFFFFF
BUFFER(INT(XXP+1)+(INT(YYP) * XRES)) = &HFFFFFF
BUFFER(INT(XXP)+(INT(YYP-1) * XRES)) = &HFFFFFF
BUFFER(INT(XXP)+(INT(YYP+1) * XRES)) = &HFFFFFF
NEXT
NEXT
END SUB
To give you an example of how powerful this is, check this 200 * 200 Dot poly square or 40,000 dots in other words! Imaging how slow it would be to rotate 40,000 vertices, this could be drawn at this speed (faster when I've removed the fpu math) from just rotating 4 corners..
'
' This technique is going to form the basis for a demo effect.
' Basically it uses an interpolation technique to subdivide the 4 corners
' Of a cube,this will make it possible to do relly complex dot cubes and make transformations
' a simple matter and also save the overheads of rotating all those points as only the corners
' will ever need to be rotated.
'
' Coded by Shockwave / DBF
' Do not rip without credit :-)
'
' See you in the finished intro..
'
'---------------------------------------------------------------------------
OPTION STATIC
OPTION EXPLICIT
'-------------------------------------------------------------------------
' Includes.
'-------------------------------------------------------------------------
'#define PTC_WIN
#Include Once "tinyptc.bi"
Const XRES=640 'Screen Width
Const YRES=480 'Screen Height
const SUBDIVISIONS = 200 ' How many dots per line?
DECLARE SUB DRAW_DOT_FACE(BYVAL X1 AS DOUBLE , BYVAL Y1 AS DOUBLE,BYVAL X2 AS DOUBLE , BYVAL Y2 AS DOUBLE , BYVAL X3 AS DOUBLE , BYVAL Y3 AS DOUBLE , BYVAL X4 AS DOUBLE , BYVAL Y4 AS DOUBLE)
DIM SHARED AS INTEGER BUFFER ( XRES * YRES )
If( ptc_open( "DBF SCREEN", XRES, YRES ) = 0 ) Then
End -1
End If
DIM XA,XB,XC,XD,YA,YB,YC,YD
DIM SHARED AS DOUBLE GADD,GADD2, GADD3,GADD4, GADD5
DO
GADD=GADD+.004
GADD2=GADD2+.008
GADD3=GADD3+.007
GADD4=GADD4+.005
GADD5=GADD5+.01
XA = 320+(300*SIN(GADD5))
XB = 320+(300*SIN(GADD4))
XC = 320+(300*SIN(GADD3))
XD = 320+(300*SIN(GADD))
YA = 240+(238*COS(GADD2 ))
YB = 240+(238*COS(GADD3 ))
YC = 240+(238*COS(GADD4 ))
YD = 240+(238*COS(GADD5 ))
DRAW_DOT_FACE(XA,YA, XB,YB, XC,YC, XD,YD )
PTC_UPDATE@BUFFER(0)
ERASE BUFFER
LOOP UNTIL INKEY$=CHR$(27)
SUB DRAW_DOT_FACE(BYVAL X1 AS DOUBLE , BYVAL Y1 AS DOUBLE,BYVAL X2 AS DOUBLE , BYVAL Y2 AS DOUBLE , BYVAL X3 AS DOUBLE , BYVAL Y3 AS DOUBLE , BYVAL X4 AS DOUBLE , BYVAL Y4 AS DOUBLE)
DIM AS INTEGER SA,SB
DIM AS DOUBLE INTERX,INTERY , XXP , YYP
DIM AS DOUBLE TOPX (SUBDIVISIONS)
DIM AS DOUBLE TOPY (SUBDIVISIONS)
DIM AS DOUBLE BOTX (SUBDIVISIONS)
DIM AS DOUBLE BOTY (SUBDIVISIONS)
'
' CALCULATE TOP LINE.
'
INTERX = (X1-X2) / SUBDIVISIONS
INTERY = (Y1-Y2) / SUBDIVISIONS
XXP = X1
YYP = Y1
FOR SA = 1 TO SUBDIVISIONS
TOPX(SA) = INT(XXP)
TOPY(SA) = INT(YYP)
XXP=XXP-INTERX
YYP=YYP-INTERY
BUFFER(TOPX(SA)+(TOPY(SA) * XRES)) = &HFFFFFF
NEXT
'
' CALCULATE BOTTOM LINE.
'
INTERX = (X3-X4) / SUBDIVISIONS
INTERY = (Y3-Y4) / SUBDIVISIONS
XXP = X3
YYP = Y3
FOR SA = 1 TO SUBDIVISIONS
BOTX(SA) = INT(XXP)
BOTY(SA) = INT(YYP)
XXP=XXP-INTERX
YYP=YYP-INTERY
BUFFER(BOTX(SA)+(BOTY(SA) * XRES)) = &HFFFFFF
NEXT
'
' CALCULATE MIDDLES;
'
FOR SB=1 TO SUBDIVISIONS
INTERX = (TOPX(SB)-BOTX(SB)) / SUBDIVISIONS
INTERY = (TOPY(SB)-BOTY(SB)) / SUBDIVISIONS
XXP = TOPX(SB)
YYP = TOPY(SB)
FOR SA = 1 TO SUBDIVISIONS-1
XXP=XXP-INTERX
YYP=YYP-INTERY
BUFFER(INT(XXP)+(INT(YYP) * XRES)) = &HFFFFFF
NEXT
NEXT
END SUB
Sweet little idea. Look forward to seeing the finished version....
Can you post the .exe examples if you get a chance. thanks. O0 O0
Yep, no problem, I'll get a dotcube working with it and post it later :)
Ok, well it works with a cube no problem, I have attached an exe to this post :)
Welldone and all, that dot cube looks amazing dude. :)
Cheers,
Clyde.
Now, think about ANY point inside your cube. You can get to it by adding only! Just rotate 3 points x=(0,0,1), y=(0,1,0), z=(1,0,0) and then multiply x, y and z by the scale factors of the points you're interested in and you can get any point inside the cube (right now you've only used 1/2). And then see that those x,y and z scale factors are actually just the x,y and z positions of the points inside the object.
I think you've just had an epiphany.
Jim
Wow! Thats stunning - how the hell did you come up with that? My head hurts (although I do understand how its done!).
Looks wicked . . . what about setting fire to that now? lol?
Drew
Quote from: Jim on August 18, 2006
Now, think about ANY point inside your cube. You can get to it by adding only! Just rotate 3 points x=(0,0,1), y=(0,1,0), z=(1,0,0) and then multiply x, y and z by the scale factors of the points you're interested in and you can get any point inside the cube (right now you've only used 1/2). And then see that those x,y and z scale factors are actually just the x,y and z positions of the points inside the object.
I think you've just had an epiphany.
Jim
Shit, that's so simple that it's sick :) I am going to have to re-write most of my 3D code to take advantage of this now. Cheers Jim.
Quote from: DrewPee on August 18, 2006
Wow! Thats stunning - how the hell did you come up with that? My head hurts (although I do understand how its done!).
Looks wicked . . . what about setting fire to that now? lol?
Drew
Burning it would be pretty easy, I'll add an example of it after I have finished doing the cracktro I am working on.
As far as working out how to do this I was just thinking about how it must be possible to calculate a cube from the corners if it was possible to calculate a texture from the same data so it just clicked.
I think I've been waiting to have an idea lately to be Honest Drew :)
Transformations are in :)
Nice one :)
holy shit that is good!
i was gonna try one of these but i had it down a totally diffrent way, whats better is i understand it too.
Yeah, I am really happy with the way this worked out and the extra understanding of how this may be applied to a 3D engine (thanks Jim, Thanks Stonemonkey). Glad that you like it guys, I'll surely do something cute with this technique soon.
Very smart :)
Can you make a jelly cube effect ? Would be nice too
Let's see if I can drive the nail in a little further...
When you multiply (0,0,1) (0,1,0) and (1,0,0) by your matrix to get the vectors you need to add together in your new technique, all you are really doing is extracting rows from the matrix.
So
(x,y,z) * (a b c)
(d e f)
(g h i)
=(xa+yd+zg, xb+ye+ zh, xc+yf+zi)
But if x=0, y=0, z=1 that's just
(0a+0d+1g, 0b+0e+1h, 0c+0f+1i)=(g,h,i)
which is exactly the bottom row of the matrix. x is the top row (a,b,c) and y is the middle row (d,e,f).
That tells you that the rows of the matrix are just 3 vectors. vectors which point along the bottom edges of your cube.
All you are doing when you rotate a vector by a matrix is applying an x,y,z scale to the 3 vectors that point along the bottom edges of your cube.
In the immortal words of Paul Daniels "Now that's magic!"
Jim
I still need to inspect and see whats occuring.
Goes without saying though, Very cool and impressive transformers Shockwave.
Good old small daniels :) And thanks Jim, this has been a revelation to me, I'm glad I shared this code now.
It is also having another completely seperate side effect too. In the Flame intro I used Delta timing for the text writer because I wanted to make sure that it was in synch to the music, I am applying delta timing to this routine and it still looks smooth right down to about 30fps, I'm hoping that I will be able to use this to make something really oldschool without the glitches I've come to accept as part of tinyptc.
Yep looks real good...... must study that a bit my maths is pants....
Quote from: Shockwave on August 17, 2006
Ok, well it works with a cube no problem, I have attached an exe to this post :)
Very nice indeed. Now the hard part, I must examine the code and learn! O0 O0
The routine was quite easy to code for me, but that is because I already had something to base it upon. It's not unlike coding an affine texture map. Don't be scared, it's pretty easy.
First of all you need to look at the information you have on the face you are about to draw.
All you know are where the 4 corners are, so you have 4 pairs of X+Y co-ordinates.
To make it very simple, class two of them as the top and two as the bottom.
From these we can calculate the top and bottom edges.
In the program a constant is set for the amount of subdivisions, it works something like this.
This pseudo code would calculate one of the edges;
x_top = X1
y_top = X1
Reciprocal_ X = (X1 - X2 ) / Subdivisions
Reciprocal_ Y = (Y1 -Y2 ) / Subdivisions
for loop = 1 to subdivisions
TOP_X_EDGE_STORE (LOOP) = x_top
TOP_Y_EDGE_STORE (LOOP) = y_top
ytop = ytop+Reciprocal_Y
xtop = ytop+Reciprocal_X >:D
next
Do the same for the bottom, these are the only points we need to physically store for the face, they can be plotted while they are being calculated.
Then another process to interpolate between the edges happens to draw the middle of the face and voila.
See it's not too bad.