MiniB3d for FreeBasic

Headers, Bindings, Libraries for use with FreeBASIC, Please include example of use to help ensure they are tested and usable.
Post Reply
badidea
Posts: 2594
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: MiniB3d for FreeBasic

Post by badidea »

Trying out meshCsg (subtract and intersect). Works well:

Code: Select all

#include "fbgfx.bi"

#ifdef __FB_64BIT__
	#include "openb3d-64/openb3d.bi"
#else
	#include "openb3d-32_old/openb3d.bi"
#endif

const ENTITY_FX_NONE = 0
const ENTITY_FX_FULL_BRIGHT = 1
const ENTITY_FX_VERTEX_COLOR = 2
const ENTITY_FX_FLATSHADED = 4
const ENTITY_FX_NO_FOG = 8
const ENTITY_FX_NO_BACKFACE_CULLING = 16
const ENTITY_FX_FORCE_ALPHA_BLENDING = 32

const CSG_OP_SUBTRACT = 0
const CSG_OP_UNION = 1
const CSG_OP_INTERSECT = 2

const LIGHT_DIRECTIONAL = 1
const LIGHT_POINT = 2
const LIGHT_SPOT = 3

declare sub createRings(ring() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
declare sub createSamples(sample() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
declare sub createHeatsink(heatsink as any ptr, parent as any ptr, r as integer, g as integer, b as integer)

const SW = 800, SH = 600
screencontrol(FB.SET_GL_2D_MODE, FB.OGL_2D_MANUAL_SYNC)
screenres(SW, SH, 32, 1, FB.GFX_OPENGL or FB.GFX_MULTISAMPLE)
Graphics3d(SW, SH, 32, 1, 1)

'AntiAlias(true)

var cam = createCamera() 'any ptr
moveEntity(cam, 0, 0, -200)
cameraZoom(cam, 1.0)
CameraFogRange(cam, +100, +300.0)
CameraFogMode(cam, 1)

var light = createlight(LIGHT_DIRECTIONAL) 'any ptr
turnEntity(light, 0, 45, 0)

var pivot = CreatePivot()

dim as any ptr ring(0 to 4)
createRings(ring(), pivot, 100, 100, 100)

dim as any ptr sample(0 to 4)
createSamples(sample(), pivot, 50, 50, 50)

dim as any ptr heatsink
createHeatsink(heatsink, pivot, 150, 100, 50)

do
	turnEntity(pivot, 0.5, 0, 0.5)
	'turnEntity(pivot, 0.5, 0, 0) 'rotate around x-axis
	'turnEntity(pivot, 0, 0, 0.5) 'rotate around z-axis
	renderWorld()
	flip()
	sleep(1)
loop until multikey(1)

'-------------------------------------------------------------------------------

'create 5 clamping rings
sub createRings(ring() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	var cylOut = createCylinder(32, 1)
	scaleMesh(cylOut, 30, 2.5, 30)
	var cylIn = createCylinder(32, 1)
	scaleMesh(cylIn, 14, 10, 14)
	for i as integer = 0 to ubound(ring)
		ring(i) = meshCsg(cylOut, cylin, CSG_OP_SUBTRACT)
		positionMesh(ring(i), 0, 80, 0)
		rotateEntity(ring(i), i*45, 0, 0)
		entityParent(ring(i), parent)
		entityColor(ring(i), r, g, b)
	next
	freeEntity(cylOut)
	freeEntity(cylIn)
end sub

'samples / targets
sub createSamples(sample() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	for i as integer = 0 to ubound(sample)
		sample(i) = createCylinder(32, 1, parent)
		scaleMesh(sample(i), 15, 0.5, 15)
		positionMesh(sample(i), 0, 78, 0)
		rotateEntity(sample(i), i * 45, 0, 0)
		entityColor(sample(i), r, g, b)
	next
end sub

'copper heat sink
sub createHeatsink(heatsink as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	var cube1 = createcube()
	moveEntity(cube1, 0.0, 0.0, 0.0)
	scaleMesh(cube1, 32.0, 77.5, (32.0+77.5)/2)
	positionMesh(cube1, 0, 0, (32-77.5)/2)
	entityColor(cube1, 150, 100, 50)
	var cube2 = createcube()
	scaleMesh(cube2, 33.0, 77.5, 77.5)
	rotateEntity(cube2, 45, 0, 0)
	heatsink = meshCsg(cube1, cube2, CSG_OP_INTERSECT)
	entityParent(heatsink, parent)
	entityColor(heatsink, r, g, b)
	freeEntity(cube1)
	freeEntity(cube2)
end sub
badidea
Posts: 2594
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: MiniB3d for FreeBasic

Post by badidea »

Continuation of the project above.
Control keys: up/down, left/right, a/z.
Any idea how to best simulate a laser beam spot? A light cone with small angle does not look so nice.

Code: Select all

#include "fbgfx.bi"

#ifdef __FB_64BIT__
	#include "openb3d-64/openb3d.bi"
#else
	#include "openb3d-32_old/openb3d.bi"
#endif

const ENTITY_FX_NONE = 0
const ENTITY_FX_FULL_BRIGHT = 1
const ENTITY_FX_VERTEX_COLOR = 2
const ENTITY_FX_FLATSHADED = 4
const ENTITY_FX_NO_FOG = 8
const ENTITY_FX_NO_BACKFACE_CULLING = 16
const ENTITY_FX_FORCE_ALPHA_BLENDING = 32

const CSG_OP_SUBTRACT = 0
const CSG_OP_UNION = 1
const CSG_OP_INTERSECT = 2

const LIGHT_DIRECTIONAL = 1
const LIGHT_POINT = 2
const LIGHT_SPOT = 3

const SHAPE_SEGMENTS = 32
const SHAPE_SOLID = 1

declare sub createRings(ring() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
declare sub createSamples(sample() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
declare sub createHeatsink(heatsink as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
declare sub createTiltAxle(tiltAxle as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
declare sub createSideFork(sideFork as any ptr, parent as any ptr, r as integer, g as integer, b as integer)

const SW = 960, SH = 720
screencontrol(FB.SET_GL_2D_MODE, FB.OGL_2D_MANUAL_SYNC)
screenres(SW, SH, 32, 1, FB.GFX_OPENGL or FB.GFX_MULTISAMPLE)
Graphics3d(SW, SH, 32, 1, 1)

'AntiAlias(true)

'-------------------------------------------------------------------------------

var pivotCenter = CreatePivot() 'at pos 0,0,0 center of TEAC

'source camera
var cam1 = createCamera() 'any ptr
CameraViewport(cam1, 0, 0, SW\2, SH\2) 'bottom-left
moveEntity(cam1, 0, 0, -200) 'move cam back
cameraZoom(cam1, 1.0)
'CameraFogRange(sourceCam, +100, +1000.0)
'CameraFogMode(sourceCam, 1)
cameraClsColor(cam1, 20, 0, 0)

'top TEAC camera
var cam2 = createCamera(pivotCenter) 'any ptr
CameraViewport(cam2, SW\2, 0, SW\2, SH\2) 'bottom-right
turnEntity(cam2, -90, 0, 0)
moveEntity(cam2, 0, 0, -400) 'move cam back
cameraZoom(cam2, 1.0)
cameraClsColor(cam2, 0, 0, 20)

'LIBS / beam line cam
var cam3 = createCamera(pivotCenter) 'any ptr
CameraViewport(cam3, 0, SH\2, SW\2, SH\2) 'top-left
turnEntity(cam3, 0, -120, 0)
moveEntity(cam3, 0, 0, -200) 'move cam back
cameraZoom(cam3, 1.0)
cameraClsColor(cam3, 0, 0, 20)

'East view 60 degC
var cam4 = createCamera(pivotCenter) 'any ptr
CameraViewport(cam4, SW\2, SH\2, SW\2, SH\2) 'top-right
turnEntity(cam4, 0, +60, 0)
moveEntity(cam4, 0, 0, -200) 'move cam back
cameraZoom(cam4, 1.0)
cameraClsColor(cam4, 20, 0, 0)

'-------------------------------------------------------------------------------

var light1 = createlight(LIGHT_DIRECTIONAL) 'any ptr
turnEntity(light1, 0, 45, 0)
lightColor(light1, 200, 150, 150)

var light2 = createlight(LIGHT_DIRECTIONAL) 'any ptr
turnEntity(light2, 45, 0, 0)
lightColor(light2, 150, 200, 150)

'plasma light, not so good
var light3 = createlight(LIGHT_SPOT) 'any ptr
turnEntity(light3, 0, 0, 0)
moveEntity(light3, 0, 0, -300) 'move back
lightConeAngles(light3, 0, 2)
lightColor(light3, 155, 0, 155) 'pink

'ion beam light, not so good
var light4 = createlight(LIGHT_SPOT) 'any ptr
turnEntity(light4, 0, 0, 0)
turnEntity(light4, 0, -120, 0)
moveEntity(light4, 0, 0, -300) 'move back
lightConeAngles(light4, 0, 2)
lightColor(light4, 0, 155, 0) 'green

'-------------------------------------------------------------------------------

var pivotTube = CreatePivot() 'Also at pos 0,0,0, but z can be different

dim as any ptr tiltAxle
createTiltAxle(tiltAxle, pivotTube, 125, 125, 125)

dim as any ptr sideFork
createSideFork(sideFork, pivotTube, 150, 150, 150)

'-------------------------------------------------------------------------------

var pivotHolder = CreatePivot(pivotTube) 'at pos 0,0,0

dim as any ptr ring(0 to 4)
createRings(ring(), pivotHolder, 100, 100, 100)

dim as any ptr sample(0 to 4)
createSamples(sample(), pivotHolder, 50, 50, 50)

dim as any ptr heatsink
createHeatsink(heatsink, pivotHolder, 150, 100, 50)

'-------------------------------------------------------------------------------

dim as double dpitch, dyaw, droll, dz
dim as double pitch, yaw, roll, z
do
	dpitch = 0 'rotate around x-axis
	dyaw = 0 'rotate around y-axis
	droll = 0 'rotate around z-axis
	dz = 0
	if multikey(FB.SC_UP) then
		if pitch < 95.1 then dpitch = +1.0
	end if
	if multikey(FB.SC_DOWN) then
		if pitch > -95.1 then dpitch = -1.0
	end if
	if multikey(FB.SC_LEFT) then
		if roll < 120.1 then droll = +1.0
	end if
	if multikey(FB.SC_RIGHT) then
		if roll > -120.1 then droll = -1.0
	end if
	if multikey(FB.SC_A) then
		if z < 290.1 then dz = +1.0
	end if
	if multikey(FB.SC_Z) then
		if z > -290.1 then dz = -1.0
	end if
	'if multikey(FB.SC_SPACE) then turnEntity(cam2, 1, 0, 0)
	if dpitch <> 0 then
		turnEntity(pivotHolder, dpitch, 0, 0)
		pitch += dpitch
	end if
	if droll <> 0 then
		turnEntity(pivotTube, 0, 0, droll)
		roll += droll
	end if
	if dz <> 0 then
		moveEntity(pivotTube, 0, 0, dz)
		z += dz
	end if
	renderWorld()
	flip()
	sleep(1)
loop until multikey(1)

'-------------------------------------------------------------------------------

'create 5 clamping rings
sub createRings(ring() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	var cylOut = createCylinder(SHAPE_SEGMENTS, SHAPE_SOLID)
	scaleMesh(cylOut, 30, 2.5, 30)
	var cylIn = createCylinder(SHAPE_SEGMENTS, SHAPE_SOLID)
	scaleMesh(cylIn, 14, 10, 14)
	var cone = createCone(SHAPE_SEGMENTS, SHAPE_SOLID)
	scaleMesh(cone, 30, 30, 30)
	rotateMesh(cone, 0, 0, 180)
	positionMesh(cone, 0, 82, 0)
	for i as integer = 0 to ubound(ring)
		var ring1 = meshCsg(cylOut, cylin, CSG_OP_SUBTRACT) '<<<<<<<<<<<<< CHANGE THIS !!!!!!!!!!!!!!!!!!!!!!!!
		positionMesh(ring1, 0, 80, 0)
		ring(i) = meshCsg(ring1, cone, CSG_OP_SUBTRACT)
		freeEntity(ring1)
		rotateEntity(ring(i), i*45, 0, 0)
		entityParent(ring(i), parent)
		entityColor(ring(i), r, g, b)
	next
	freeEntity(cone)
	freeEntity(cylOut)
	freeEntity(cylIn)
end sub

'samples / targets
sub createSamples(sample() as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	for i as integer = 0 to ubound(sample)
		sample(i) = createCylinder(SHAPE_SEGMENTS, SHAPE_SOLID, parent)
		scaleMesh(sample(i), 15, 0.5, 15)
		positionMesh(sample(i), 0, 78, 0)
		rotateEntity(sample(i), i * 45, 0, 0)
		entityColor(sample(i), r, g, b)
	next
end sub

'copper heat sink
sub createHeatsink(heatsink as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	var cube1 = createcube()
	moveEntity(cube1, 0.0, 0.0, 0.0)
	scaleMesh(cube1, 32.0, 77.5, (32.0+77.5)/2)
	positionMesh(cube1, 0, 0, (32-77.5)/2)
	entityColor(cube1, 150, 100, 50)
	var cube2 = createcube()
	scaleMesh(cube2, 33.0, 77.5, 77.5)
	rotateEntity(cube2, 45, 0, 0)
	heatsink = meshCsg(cube1, cube2, CSG_OP_INTERSECT)
	freeEntity(cube1)
	freeEntity(cube2)
	entityParent(heatsink, parent)
	entityColor(heatsink, r, g, b)
end sub

sub createTiltAxle(tiltAxle as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	tiltAxle = createCylinder(SHAPE_SEGMENTS, SHAPE_SOLID, parent)
	rotateMesh(tiltAxle, 0, 0, 90)
	scaleMesh(tiltAxle, 60, 20/2, 20/2)
	positionMesh(tiltAxle, -25, 0, 0)
	entityColor(tiltAxle, r, g, b)
end sub

sub createSideFork(sideFork as any ptr, parent as any ptr, r as integer, g as integer, b as integer)
	'mamipulator tube flange
	var flange = createCylinder(SHAPE_SEGMENTS, SHAPE_SOLID)
	rotateMesh(flange, 90, 0, 0)
	scaleMesh(flange, 160/2, 160/2, 10/2)
	positionMesh(flange, 0, 0, +250)
	'fork head
	var forkHead = createCube()
	scaleMesh(forkHead, 40/2, 120/2, 60/2) 'x,y,z
	positionMesh(forkHead, -(40+40/2), 0, 0) 'move left (-x)
	'add fork stems, front (at head)
	var stem1 = createCube()
	scaleMesh(stem1, 20/2, 30/2, 120/2) 'x,y,z
	positionMesh(stem1, -(40+40/2), (40+30)/2, (120+60)/2)
	'middle
	var stem1b = createCube()
	scaleMesh(stem1b, 20/2, 30/2, 60/2) 'x,y,z
	rotateMesh(stem1b, 0, -45, 0)
	positionMesh(stem1b, -40, (40+30)/2, 190-60/2)
	addMesh(stem1b, stem1)
	freeEntity(stem1b)
	'back (at flange)
	var stem1c = createCube()
	scaleMesh(stem1c, 20/2, 30/2, 80/2) 'x,y,z
	positionMesh(stem1c, -40/2, (40+30)/2, 250-(80/2))
	addMesh(stem1c, stem1)
	freeEntity(stem1c)
	'second fork
	var stem2 = copyMesh(stem1)
	positionMesh(stem2, 0, -(40+30), 0)
	'merge all
	var sideForkA = meshCsg(flange, stem1, CSG_OP_UNION)
	freeEntity(flange)
	freeEntity(stem1)
	var sideForkB = meshCsg(forkHead, stem2, CSG_OP_UNION)
	freeEntity(stem2)
	freeEntity(forkHead)
	'merge the 2 parts
	sideFork = meshCsg(sideForkA, sideForkB, CSG_OP_UNION)
	freeEntity(sideForkA)
	freeEntity(sideForkB)
	entityParent(sideFork, parent)
	entityColor(sideFork, r, g, b)
end sub
angros47
Posts: 2331
Joined: Jun 21, 2005 19:04

Re: MiniB3d for FreeBasic

Post by angros47 »

I think you already achieved the best you could, with the default fixed function pipeline. The reason it doesn't look nice is that light is computed per vertex: basically, a surface is rendered as a group of triangles, for each triangle the incidence it is computed how the light affect each of the three vertices, and the result is interpolated per every pixel (actually, pixels are called "fragments" in this situation) of the rendered triangle. That approach allows to reduce the amount of calculations needed, and makes the rendering faster, but it doesn't work well when the light source is small, and close, because if the light cone falls in the middle of a triangle, but its vertices are outside, it won't be rendered (since all vertices are not lightened, the interpolation will erroneously suppose all the triangle is not lightened)

The only way to avoid this issue is to calculate how the light affect each pixel individually, and this can be done by reprogramming the rendering on the GPU: it can be done with a shader, specifically, you need a shader to perform "per fragment lightning"
badidea
Posts: 2594
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: MiniB3d for FreeBasic

Post by badidea »

Ok, I will also try a particle emitter.
Gunslinger
Posts: 107
Joined: Mar 08, 2016 19:10
Location: The Netherlands

Re: MiniB3d for FreeBasic

Post by Gunslinger »

I have a new project the physics got to complex with mij space game. (for the time i have)
Make a tile world now but run into shadow problems.
Everting looks fine when i set camera view range bigger then my world.
When i set the view range to max 60 then shadow have problems close to edge before becoming invisible.
Think something is wrong, look at screenshot
https://ac1.servegame.com:88/screenshot2304204.PNG

The green bloks dont have shadow on them.
Only stone and white bloks have dynamic createchadow on them.

As i don't know if shadow becomes child of the parent mesh.
I think because if will disappear outside of view range.
Why is it going wrong at edge of view range.
Maybe setting the view range of shadow to 30 wil fix this problem?
This not possible now i think?
Shadow is not needed most of the time at edge of view anyway.
angros47
Posts: 2331
Joined: Jun 21, 2005 19:04

Re: MiniB3d for FreeBasic

Post by angros47 »

Shadows are not children of a mesh, they are managed aside. From the screenshot I cannot tell for sure what happens, although I can make a hypothesis: the algorithm used by OpenB3D is called Stencil Shadows, and it basically work by creating a mesh that is not visible, and is shaped like the shadow volume: such mesh is rendered on the stencil buffer (that is not visible), and it is rendered twice: once using front face culling, and once using back face culling: one rendering pass increases the value in the buffer, the other pass decreases it. As result, most of the volume of the shadow does not change the buffer value. But if the shadow volume intersects any visible surface, the front and back face rendered don't overlap anymore, and the mismatching area has the stencil buffer altered. In the last pass, the altered areas (that are the ones where the shadow is visible) are darkened.

When a shadow is close to the edge of the camera, I guess it's possible that the back faces are beyond the camera range, and not rendered, while the front face are within the range, and rendered, and that is misinterpreted as an object affected by the shadow

I guess the best solution would be to increase the camera range
Gunslinger
Posts: 107
Joined: Mar 08, 2016 19:10
Location: The Netherlands

Re: MiniB3d for FreeBasic

Post by Gunslinger »

Thanks, camera bigger range works not a real solution for everything.
So i have to add some kind of chunk world system again like i did with my other game.

One other thing, shadow and fog is not working nice together.
When object is complete in think fog it is still darker in shadow looks strange.
Result of the stencil buffer..

Later in the project i try to search for shader code for shadow.
angros47
Posts: 2331
Joined: Jun 21, 2005 19:04

Re: MiniB3d for FreeBasic

Post by angros47 »

An example of shader code for shadows (although pretty bare) is included in OpenB3D Plus add on

Regarding the chunk world system. have also a look at built in octrees (blocks cannot cast shadows, but meshes inside octrees can, I think)
Gunslinger
Posts: 107
Joined: Mar 08, 2016 19:10
Location: The Netherlands

Re: MiniB3d for FreeBasic

Post by Gunslinger »

angros47 wrote: Apr 30, 2024 21:59 An example of shader code for shadows (although pretty bare) is included in OpenB3D Plus add on

Regarding the chunk world system. have also a look at built in octrees (blocks cannot cast shadows, but meshes inside octrees can, I think)
Sorry i cant not find OpenB3D plus add-on examples.
i know i seen some in the past on sourceforge, looking forward to find good example, best way for my to learn.
plus v0.13 has no example with it, here -> https://sourceforge.net/projects/minib3 ... p/download

Also on your github it only source code.
do you mean this one?
https://github.com/angros47/OpenB3D-Plu ... shadow.cpp

Octrees yes, i still have find hard to work with them, don't like resolution update in close front of the camera.
there seem a way to set octrees parameters to change that by setting near to higher value.
Maybe near is it visible range, i don't know.
angros47
Posts: 2331
Joined: Jun 21, 2005 19:04

Re: MiniB3d for FreeBasic

Post by angros47 »

Yes, that's the file, a demo could be something like:

Code: Select all

#include "ob3dplus.bi"

declare function CreateShadowMap cdecl alias "CreateShadowMap" (byval light as any ptr) as any ptr
declare sub UpdateShadows cdecl alias "UpdateShadows" () 


screen 18,  32, , &h10002 

	
Graphics3d 640,480,32,1,1

var camera=createcamera(0)
cameraclscolor camera,0,0,255





var cube=createcube()
entitycolor cube,255,0,0

var plane=createplane()'cube():scaleentity plane, 100,.1,100
moveentity plane,0,-1.4,15
scalemesh plane, .001,1,.001


var light=createlight()



moveentity light,10,10,-3
pointentity light,cube
moveentity camera,-2,0,-5

var shadow=createshadowmap(light)
shadeentity plane, shadow

shadeentity cube, shadow
entitytexture cube, loadtexture("diffuse.png")


dim key as string
do

	'depthbuffertotex ShadowMap, CamLight
	updateshadows

	key=inkey
        if key="a" then moveentity cube,0,0,1
        if key="z" then moveentity cube,0,0,-1

        if key=chr(255)+"H" then turnentity cube,1,0,0,0
        if key=chr(255)+"P" then turnentity cube,-1,0,0,0
        if key=chr(255)+"M" then turnentity cube,0,-1,0,0
        if key=chr(255)+"K" then turnentity cube,0,1,0,0
	updateworld 1
	renderworld
sleep 1
	flip
loop until key=chr(27)

Regarding Octrees, the rule is: "any node closer than Near won’t be rendered. Any node fartherthan Far will stop the recursive rendering, so blocks smaller than it won’t be rendered"
Post Reply