D3D functional example.
Post by michael on Aug 27th, 2017, 06:30am
Before you run this program make sure you save it in a writable directory.
DDRM, or someone that has good knowledge on D3D, if you could help me figure how to make more than one object, I could advance this working example that creates a 3D image file and displays it.
If I get the answers I need, I can take the solutions and expand on them with special tools.
This really needs to be worked on to advance the community tools and make D3D more accessible for the average person.
Code: INSTALL @lib$+"D3DLIB"
PROCcreate3d
MODE 8
DIM l%(0), b%(1), n%(1), f%(1), s%(1), m%(1), t%(1), y(1), p(1), r(1), X(1), Y(1), Z(1), e(2), a(2)
ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:PRINT REPORT$:END
d% = FN_initd3d(@hwnd%, 1, 0)
IF d% = 0 ERROR 100, "Can't initialise Direct3D"
b%(0) = FN_load3d(d%, @dir$+"TRIANGLE.B3D", n%(0), f%(0), s%(0))
IF b%(0) = 0 ERROR 100, "Can't load TRIANGLE.B3D"
REM t%(0) = FN_loadtexture(d%, @dir$+"blue.BMP")
REM IF t%(0) = 0 ERROR 100, "Can't load face.JPG"
e() = 0, 0, -6
a() = 0, 0, 0
l%()=1
REPEAT
y() = 0:REM yaw (rotations around the Y axis)
REM pitch
p() = 0:REM TIME/100 (pitch angles rotations around the X axis)
REM roll
r() = 0:REM TIME/40 (roll angles (rotations around the Z axis)
REM X (right left)
X() = 0:REM SIN(TIME/200)
REM Y() up and down
Y() = 0
REM Z() depth
Z() = 10 :REM
REM PROC_render(d%, &FF7F7F7F, 0, l%(), 2, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000)
PROC_render(d%, &FF7F7F7F, 0, l%(), 2, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000) :REM experimental
REM 1 2 3 4 5 6 7 8 9 10 11 yaw pitch roll X Y Z eye0123 18 19 20 ^mcd ^( cam to farplane dist)
REM 1 Val returned from FN_init3D
REM 2 back color 3 #of lights 4 light pointers
REM mcd - minimum near cam distance
UNTIL INKEY(1)=0
END
DEF PROCcleanup
t%(1) += 0:IF t%(1) PROC_release(t%(1))
b%(0) += 0:IF b%(0) PROC_release(b%(0))
b%(1) += 0:IF b%(1) PROC_release(b%(1))
d% += 0 :IF d% PROC_release(d%)
ENDPROC
DEF PROCcreate3d
F% = OPENOUT"TRIANGLE.B3D"
PROC4(3):REM 3 vertices
PROC4(&100042):REM vertex size &10 and format &42
REM LL x LL y LL z
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF)
REM LR x LR y LR z
PROC4(FN_f4(1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF00FF00)
REM PEAK X PEAK Y PEAK Z
PROC4(FN_f4(0.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0)):PROC4(&FFFF0000)
CLOSE #F%
ENDPROC
DEF PROC4(A%):BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24:ENDPROC
Re: D3D functional example.
Post by DDRM on Aug 29th, 2017, 09:49am
Hi Michael,
The basic answer is that you just increase the number of vertex buffers you load (stored in the b%() array), and then tell the rendering engine how many you want to show. In this case, you've based your program on Richard's pyramid programme, which already has two objects, so all you need to do is load another one.
Here's an example, showing it in action. I've tidied up a bit (removing your remmed out bits of Richard's program) and added what I hope are helpful comments:
Code:
INSTALL @lib$+"D3DLIB"
REM Create a B3D object file - in this case a simple coloured triangle, and save to disk
PROCcreate3d
MODE 8
REM These are the parameters needed for the Direct3D rendering. See the manual for details
REM Of particular note, b%() holds buffers to the different 3D objects to be rendered
REM X(), Y() and Z() hold the translations in the three axes for each object
DIM l%(0), b%(1), n%(1), f%(1), s%(1), m%(1), t%(1), y(1), p(1), r(1), X(1), Y(1), Z(1), e(2), a(2)
REM SAfety precaultions to clean up the D3D system after use...
ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:PRINT REPORT$:END
REM OK, let's tell Windows to initiate the D3D system: it returns a handle to it (d%) which we later use to send instructions to it
d% = FN_initd3d(@hwnd%, 1, 0)
IF d% = 0 ERROR 100, "Can't initialise Direct3D"
REM Now we need to load some objects to render. In this case, I've loaded the triangle file we created earlier, twice. Note that the b%() array holds the handles to the separate instances.
b%(0) = FN_load3d(d%, @dir$+"TRIANGLE.B3D", n%(0), f%(0), s%(0))
b%(1) = FN_load3d(d%, @dir$+"TRIANGLE.B3D", n%(1), f%(1), s%(1))
REM We could avoid loading a second indentical copy by using the same actual buffer twice, by setting up the arrays like this:
REM b%(1)=b%(0):n%(1)=n%(0):f%(1)=f%(0):s%(1)=s%(0)
IF b%(0) = 0 ERROR 100, "Can't load TRIANGLE.B3D"
IF b%(0) = 1 ERROR 100, "Can't load second TRIANGLE.B3D"
REM The e() array holds the position of the eye/camera
e() = 0, 0, -6
REM The a() array holds the address of a point along the path we are looking down
a() = 0, 0, 0
l%()=1
REPEAT
REM I'm going to make the second object (b%(1)) move around the first object, by changing the X and Y offsets at which it is rendered
FOR angle=0 TO 2*PI STEP 0.01
X(1)=2*COS(angle)
Y(1)=2*SIN(angle)
REM Now render the 3D scene. Note that the number of objects (5th parameter) is 2, but all other arrays are 0-based (i.e. X(0) is the X position of the first object)
PROC_render(d%, &FF7F7F7F, 0, l%(), 2, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000) :REM experimental
WAIT 1
NEXT angle
UNTIL INKEY(1)=0
END
:
DEF PROCcleanup
REM Release the buffers etc we set up earlier
b%(0) += 0:IF b%(0) PROC_release(b%(0))
b%(1) += 0:IF b%(1) PROC_release(b%(1))
d% += 0 :IF d% PROC_release(d%)
ENDPROC
:
DEF PROCcreate3d
F% = OPENOUT"TRIANGLE.B3D"
PROC4(3):REM 3 vertices
PROC4(&100042):REM vertex size &10 and format &42
REM LL x LL y LL z LL colour
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF)
REM LR x LR y LR z LR colour
PROC4(FN_f4(1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF00FF00)
REM PEAK X PEAK Y PEAK Z Peak colour
PROC4(FN_f4(0.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0)):PROC4(&FFFF0000)
CLOSE #F%
ENDPROC
:
DEF PROC4(A%):BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24:ENDPROC
Here's a version with 5 objects, to show the changes you need to make:
Code:
INSTALL @lib$+"D3DLIB"
REM Create a B3D object file - in this case a simple coloured triangle, and save to disk
PROCcreate3d
MODE 8
REM note that I've increased the array sizes to allow for the new number of objects. Lights aren't changing, and the last 2 relate to the camera view
DIM l%(0), b%(4), n%(4), f%(4), s%(4), m%(4), t%(4), y(4), p(4), r(4), X(4), Y(4), Z(4), e(2), a(2)
ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:PRINT REPORT$:END
d% = FN_initd3d(@hwnd%, 1, 0)
IF d% = 0 ERROR 100, "Can't initialise Direct3D"
b%(0) = FN_load3d(d%, @dir$+"TRIANGLE.B3D", n%(0), f%(0), s%(0))
IF b%(0) = 0 ERROR 100, "Can't load TRIANGLE.B3D"
REM Here we make another 4 sets of pointers to the same buffer
FOR a%=1 TO 4
b%(a%)=b%(0):n%(a%)=n%(0):f%(a%)=f%(0):s%(a%)=s%(0)
NEXT a%
e() = 0, 0, -12 :REM Moved out a bit
a() = 0, 0, 0
l%()=1
REPEAT
REM I'm going to make objects 2-5 move around the first object (play with X(), Y() and Z())
REM and rotate oddly while they do it... (play with y(),p() and r(), which are yaw, pitch and roll
FOR angle=0 TO 2*PI STEP 0.01
FOR n%=1 TO 4
X(n%)=3*COS(angle+n%*PI/2)
Y(n%)=3*SIN(angle+n%*PI/2)
r(n%)=2*PI*COS(angle+n%*PI/2)
NEXT n%
REM Now render the 3D scene. Note that the number of objects (5th parameter) is now 5
PROC_render(d%, &FF7F7F7F, 0, l%(), 5, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000) :REM experimental
WAIT 1
NEXT angle
UNTIL INKEY(1)<>-1
END
:
DEF PROCcleanup
b%(0) += 0:IF b%(0) PROC_release(b%(0))
b%(1) += 0:IF b%(1) PROC_release(b%(1))
d% += 0 :IF d% PROC_release(d%)
ENDPROC
:
DEF PROCcreate3d
F% = OPENOUT"TRIANGLE.B3D"
PROC4(3):REM 3 vertices
PROC4(&100042):REM vertex size &10 and format &42
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF)
PROC4(FN_f4(1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF00FF00)
PROC4(FN_f4(0.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0)):PROC4(&FFFF0000)
CLOSE #F%
ENDPROC
:
DEF PROC4(A%):BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24:ENDPROC
Hope that's useful!
D
Re: D3D functional example.
Post by michael on Aug 30th, 2017, 04:20am
Thank you.
This will advance my efforts greatly.
I am still studying Richards Rubix 3D texture example.
I know how to create complex shapes and also I know how to fill a color in each triangle by defining the verticies color rrggbb.
I only need a simple example of adding a texture to each triangle. (the 2 triangles on the first example you supplied)
A note:
Richard suggested me using D3DLIBA which has a slight difference on the render. I had to add another value.
Aside from that, it works much the same.
I made this square and gave it a blue color. Perhaps you could use it to show a simple way to add a texture?
Code: IF INKEY$(-256)="W" INSTALL @lib$+"D3DLIBA" ELSE INSTALL @lib$+"OGLLIB"
PROCcreate3d
MODE 8
DIM l%(0), b%(1), n%(1), f%(1), s%(1), m%(1), t%(1), y(1), p(1), r(1), X(1), Y(1), Z(1), e(2), a(2)
ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:PRINT REPORT$:END
IF INKEY$(-256)="W" d% = FN_initd3d(@hwnd%, 1, 0) ELSE d% = FN_initgl(@hwnd%, 1, 0)
IF d% = 0 ERROR 100, "Can't initialise Direct3D"
b%(0) = FN_load3d(d%, @dir$+"TRIANGLE.B3D", n%(0), f%(0), s%(0))
IF b%(0) = 0 ERROR 100, "Can't load TRIANGLE.B3D"
t%(1) = FN_loadtexture(d%, @dir$+"purple.JPG")
IF t%(1) = 0 ERROR 100, "Can't load face.JPG"
e() = 0, 0, -6
a() = 0, 0, 0
l%()=1
REPEAT
y() +=.01:REM yaw (rotations around the Y axis)
REM pitch
p() =0:REM TIME/100 (pitch angles rotations around the X axis)
REM roll
r() = 0:REM TIME/40 (roll angles (rotations around the Z axis)
REM X (right left)
X() = 0:REM SIN(TIME/200)
REM Y() up and down
Y() = 0
REM Z() depth
Z() = 10:REM
REM PROC_render(d%, &FF7F7F7F, 0, l%(), 2, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000)
PROC_render(d%, &FF7F7F7F, 0, l%(), 2, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000, 0) :REM experimental
REM 1 2 3 4 5 6 7 8 9 10 11 yaw pitch roll X Y Z eye0123 18 19 20 ^mcd ^( cam to farplane dist)
REM 1 Val returned from FN_init3D
REM 2 back color 3 #of lights 4 light pointers
REM t%() - holds texture
REM mcd - minimum near cam distance
UNTIL INKEY(1)=0
END
DEF PROCcleanup
t%(1) += 0:IF t%(1) PROC_release(t%(1))
b%(0) += 0:IF b%(0) PROC_release(b%(0))
b%(1) += 0:IF b%(1) PROC_release(b%(1))
d% += 0 :IF d% PROC_release(d%)
ENDPROC
DEF PROCcreate3d
F% = OPENOUT"TRIANGLE.B3D"
PROC4(6):REM 3 vertices
PROC4(&100042):REM vertex size &10 and format &42
REM LL x LL y LL z
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF)
REM LR x LR y LR z
PROC4(FN_f4(1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF):REM PROC4(&FF00FF00)
REM PEAK X PEAK Y PEAK Z
PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF):REM PROC4(&FFFF0000)
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF):REM PROC4(&FF0000FF)
REM LR x LR y LR z
PROC4(FN_f4(-1)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF):REM PROC4(&FF00FF00)
REM PEAK X PEAK Y PEAK Z
PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(&FF0000FF):REM PROC4(&FFFF0000)
CLOSE #F%
ENDPROC
DEF PROC4(A%):BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24:ENDPROC
Re: D3D functional example.
Post by DDRM on Aug 30th, 2017, 09:07am
Hi Michael,
You need to change the vertex format to include U and V values (basically x and y coordinates) for the texture. Look at what I've done in PROCcreate3d below. These tell the D3D renderer which part of the texture image should be shown in the triangle. The U and V values should lie between 0 and 1, and the whole texture image is scaled to this.
So to map the whole image to your square, we set the UV coordinates for the bottom left of the square to (0.0 , 0.0), for the bottom right to (1.0 , 0.0), and for the top right to (1.0 , 1.0). The second triangle is similar, except that the second point (top left) has UV coordinates (0.0 , 1.0). Note that the coordinates need to be real numbers.
Note that you only have one object here, so I've amended your code to reflect that (though I haven't changed the declarations, which allow for 2...). I've amended your code for detecting a keypress so that it works.
Code:
IF INKEY$(-256)="W" INSTALL @lib$+"D3DLIBA" ELSE INSTALL @lib$+"OGLLIB"
PROCcreate3d
MODE 8
DIM l%(0), b%(1), n%(1), f%(1), s%(1), m%(1), t%(1), y(1), p(1), r(1), X(1), Y(1), Z(1), e(2), a(2)
ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:PRINT REPORT$:END
IF INKEY$(-256)="W" d% = FN_initd3d(@hwnd%, 1, 0) ELSE d% = FN_initgl(@hwnd%, 1, 0)
IF d% = 0 ERROR 100, "Can't initialise Direct3D"
b%(0) = FN_load3d(d%, @dir$+"TRIANGLE.B3D", n%(0), f%(0), s%(0))
IF b%(0) = 0 ERROR 100, "Can't load TRIANGLE.B3D"
t%(0) = FN_loadtexture(d%, @dir$+"box1_green.bmp"):REM Change this to a picture of your choice. This one is in the "images" for the "Triples" game
IF t%(0) = 0 ERROR 100, "Can't load texture"
e() = 0, 0, -6
a() = 0, 0, 0
REM l%()=1 :You aren't using any lighting, so don't need this.
REPEAT
y() +=.01:REM yaw (rotations around the Y axis)
REM Z() depth
Z() = 10:
REM Given this is constant, you don't need to have it inside the loop.
REM You could achieve the same end with one object by changing the eye position Z coordinate.
REM Better to use the Z array values to move objects relative to *each other* rather than relative to the eye position?
PROC_render(d%, &FF7F7F7F, 0, l%(), 1, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000, 0) :REM experimental
UNTIL INKEY(1)<>-1
PROCcleanup
END
:
DEF PROCcleanup
t%(0) += 0:IF t%(1) PROC_release(t%(1))
b%(0) += 0:IF b%(0) PROC_release(b%(0))
d% += 0 :IF d% PROC_release(d%)
ENDPROC
:
DEF PROCcreate3d
F% = OPENOUT"TRIANGLE.B3D"
PROC4(6):REM 3 vertices
PROC4(&140102):REM vertex size &18 and format &142 - change format to specify UV texture coordinates instead of colours,
REM and allow the extra 4 bytes that requires (+8 for texture address, -4 for no colour)
REM LL x LL y LL z u (x coord of texture) v (y coord of texture)
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0)):PROC4(FN_f4(0.0))
REM LR x LR y LR z
PROC4(FN_f4(1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0))
REM PEAK X PEAK Y PEAK Z
PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0))
PROC4(FN_f4(-1.0)):PROC4(FN_f4(-1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0)):PROC4(FN_f4(0.0))
REM LR x LR y LR z
PROC4(FN_f4(-1)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(0.0)):PROC4(FN_f4(1.0))
REM PEAK X PEAK Y PEAK Z
PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0)):PROC4(FN_f4(1.0))
CLOSE #F%
ENDPROC
:
DEF PROC4(A%):BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24:ENDPROC
Some other comments on texture coordinates:
If you want your picture to spread over several triangles/squares, you just map the triangles to the relevant bits of pictures. So if you wanted to map the picture over 4 squares, the UV coordinates for the bottom left square would lie in the range (0.0 , 0.0) to (0.5 , 0.5), the lower right ones would be from (0.5 , 0.0) to (1.0 , 0.5), and so on. There's not much point in doing that for a flat rectangle, but it allows you to map on image onto a more complex shape - and often the shape can therefore be simplified, with details just shown in the texture image. For example, you could make a house as a cuboid with a triangular prism for the roof, and show all the windows, doors, roof tiles, etc in the textures.
You can use the image partially, or multiple times: for example, your texture image could show one brick, and every pair of triangles could map the whole image, and it would look like a wall. More likely, your image would show a whole wall (would render much faster!), while if you wanted a single brick you could take a bit out of the texture.
I know I said the texture coordinates had to lie between 0 and 1, but if they get larger the renderer will (probably) tile the image appropriately. The Microsoft documentation says this, but doesn't promise it will necessarily work, or how big the numbers can be.
Coordinates can go "backwards" across the texture - so if you gave UV coordinates of (1.0 , 0.0) for the bottom left, and (0.0 , 1.0) for the top right, the texture image would be reversed. If you do this on adjacent squares, you could ensure that, for example, wood grain would line up perfectly.
Each object (defined by a vertex buffer) can only have one texture, but the texture could have different regions. So, for example, if you were covering a house, part of your texture image might show brick wall,part might be a window, part a door, and part roofing. Then you could map the relevant bits to the triangles making up your house. The window bit might get used several times.
Hope that's helpful!
D
Re: D3D functional example.
Post by michael on Aug 31st, 2017, 12:58am
That was awesome DDRM !
I will now work on my skills in D3D object creation and make a game piece library and work on a training video with a link to code for people who would like to make 3D creations.
This is a great plateau. "If we build it they will come."