What's your preference for rendering/drawing your models/sprites

Started by col, March 23, 2021, 16:09:02

Previous topic - Next topic

col

Hi all,

I'm after some feedback in respect of how you prefer to do your rendering/drawing.

As an example, with Blitz3D you create your objects and they are added to a 'render list'. When you call RenderWorld() it loops through the list draws your 3d models - there is no such command such as 'DrawModel' in Blitz3D.

By contrast, in BlitzMax you are responsible for creating your own 'render list' and are responsible for drawing your 'scene' during the main loop via the appropriate Draw* calls - more of an 'immediate' mode style (because it's primarily 2d?)

Which style do you prefer? The Blitz3D style (which I believe AGK also uses) or the BlitzMax style?

Cheers!
PS There is a genuine reason for asking other than just being nosey :D
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

GrindalfGames

I have never used the Bmax style but I also wonder how it is useful. It just sounds like an extra step of unnecessary coding.

Derron

I would prefer both.


So you have a stage which allows attaching stuff like layers or so - so similar to the "canvas" of mojo - or what ProPuke discussed in the NG-discord channel last year (am not sure if you were there at that time already).
These layers could be used to do different stuff (maybe one is the "blend" layer or a "mask" or such stuff).


The "render order decided by order of draw commands" approach suits me well too.


To have "optimization" available (batching) it would be good to have manual ability to "batch" stuff together. Kind of "render groups". Maybe similary (keep it simple) done like your render2texture code. So you get a "CreateRenderBatchGroup()", "SetRenderBatchGroup(thisGroup or null for none)" chain of commands...
Batch groups could simply become "layers" then ... which you can use to mask stuff etc.


If you have some time ask ProPuke in the discord channel for his ideas - he wrote an almost complete 3D renderer and has done some brainstorming on how to approach it - making stuff "flexible" and extendable. He surely has some good ideas.

It is just... are we talking about 2D or 3D or both?


For 3D stuff the "DrawModel()" does something different - it places the model into the world, invalidating any existing node tree, requiring recomputation of lighting caches etc. So here it might be better to use a "attach/remove" approach (node tree, "world" in which you attach your objects). 



PS: now you opened your top button already ... time to expose more stuff!


bye
Ron

Steve Elliott

Quote
Which style do you prefer? The Blitz3D style (which I believe AGK also uses) or the BlitzMax style?

Interesting question.   ;D

AGK allows both in a way, you can either draw your sprites with the DrawSprite() command - then Swap().  Or they are drawn automatically unless you 'hide them' - then Sync().  Hiding sprites is a real pain and is bug prone.

Quote
It is just... are we talking about 2D or 3D or both?

The question asks about Sprites and Models - so both.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

STEVIE G

While I'm using b3d, my sprite system is single surface 3d so its a sort of hybrid.  So everything is drawn automatically on renderworld. Anything inactive is positioned far from the viewport rather than deleted as that means a reconstruction of the whole mesh just to remove a quad. I much prefer auto rendering but full control of each sprite in terms of zorder. I am effectvely maintaining a list of quads to render.

RemiD

using EntityOrder(), it is possible to do manual z-ordering (of separate entities) with Blitz3d...

i use entityorder(), on far way things like skybox, several layers terrain, water (to prevent z-ordering artifacts), and also for particles (smoke / mist) (to not go through floors/walls), and in some cases for flares (to no go through floors/walls/furnitures)

STEVIE G

Quote from: RemiD on March 23, 2021, 18:26:57
using EntityOrder(), it is possible to do manual z-ordering (of separate entities) with Blitz3d...

i use entityorder(), on far way things like skybox, several layers terrain, water (to prevent z-ordering artifacts), and also for particles (smoke / mist) (to not go through floors/walls), and in some cases for flares (to no go through floors/walls/furnitures)

I can't use entityorder on a single surface but I can and do change the z position of individual quads to do the same thing.

iWasAdam

Blitzmax does use a render list - it's just hidden from you

Derron

Quote from: iWasAdam on March 23, 2021, 20:26:29
Blitzmax does use a render list - it's just hidden from you

Sure?
In Max2d it is immediate rendering ... except for the bufferedGL one which tries to do some render batching.


bye
Ron

Steve Elliott

Quote
Anything inactive is positioned far from the viewport rather than deleted as that means a reconstruction of the whole mesh just to remove a quad.

That sounds similar to AGK's hiding of Sprites with SetSpriteVisible() which I found a pain and can lead to bugs if you're not careful.  In general terms (rather than your more complicated example) I just find a DrawSprite() type command obvious and clear.  If you don't want something drawn then you simply omit the DrawSprite() command, and maybe use a flag within the type/class to decide if the DrawSprite() line is executed.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

col

So how we could have both methods? Can you give a pseudo code example?

In my mind I see something like this for the B3D/AGK style, if you want to NOT render an object you need to HideEntity on it:

'camera
cam:Camera = CreateCamera()
SetEntityPosition(cam, 0, 0, -5)

' light
L1:Light = CreateDirectionalLight()

' Create 2 cubes
cube1:Model = CreateCube()
cube2:Model = CreateCube()
SetEntityPosition(cube1, -2, 0, 0)
SetEntityPosition(cube2, 2, 0, 0)

While Not KeyDown(KEY_ESCAPE) And Not AppTerminate()
    ' Update
    TurnEntity(cube1, 0, -.1, 0)
    TurnEntity(cube2, 0, 1. ,0)

    ' Render
    RenderWorld() ' will take all cameras and render the world for each one

    ' Present to screen
    Flip()
Wend


Or you could go the whole hog and have something like this (BMax style) where you have explicit control of what happens in the render loop - no need for a HideEntity function?

'camera
cam:Camera = CreateCamera()
SetEntityPosition(cam, 0, 0, -5)

' light
L1:Light = CreateDirectionalLight()

' Create 2 cubes
cube1:Model = CreateCube()
cube2:Model = CreateCube()
SetEntityPosition(cube1, -2, 0, 0)
SetEntityPosition(cube2, 2, 0, 0)

While Not KeyDown(KEY_ESCAPE) And Not AppTerminate()
    ' Update
    TurnEntity(cube1, 0, -.1, 0)
    TurnEntity(cube2, 0, 1 ,0)

    ' Prepare to render
    SetGraphicsPipeline(Default3DPipeline())
    SetRenderTarget(BackBufferRenderTarget(), BackBufferDepthTarget())
    SetCamera(cam)
    ClearRenderTarget(BackBufferRenderTarget(), .2, .3, .6, 1) ' RGBA
    ClearDepthTarget(BackBufferDepthTarget(), 1, -1) ' Depth, Stencil

    ' Render
    RenderModel(cube1)
    RenderModel(cube2)

    ' Present to screen
    Flip()
Wend



As you can see it's just the render part that is different... One gives you little control, the other gives you lots of control (Maybe even too much?).

Somehow I think somewhere inbetween these 2 would be ideal? Any thoughts?
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

iWasAdam

It can be done, but you would need to write the render system yourself. E.G.

UseShader( shaderGfxPure )

DrawModel( OBJ_COPTER, Color.White,  8*time,0.75+time,0,  1,0.8,1,   0, time*1.5, 0 )
DrawModel( OBJ_BLADES, Color.White,  8*time,0.75+time,0,  1,0.8,1,   0, _gameTime * 0.1, 0 )

DrawModel( OBJ_ICEBASE, Color.White,  0,0,0,  1.5, 1, 1.5,   0, 0, 0 )

DrawModel( OBJ_LAND, Color.White,  0,0,0,  6, 1.5, 6,   0, 0, 0 )
DrawModel( OBJ_LAND, Color.White,  0,0,0,  12, 2, 12,   0, Pi, 0 )
DrawModel( OBJ_LAND, Color.White,  0,0,0,  33, 6, 33,   0, PiHalf, 0 )


Where models were being precached and then instanced as needed

col

Thank you all for your feedback.
I think I can come up with a system that will allow both.

I'm not so keen on the Sync() and Swap() method that's mentioned in AGK - it seems confusing already just thinking about it.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Baggey

BlitzMax 1.5  ;D

Wish there was a proper full screen stretch function instead of a Fullscreen 4:3 ratio!

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

iWasAdam

Render to a custom canvas and then render the custom canvas image to the output :)