So a while ago I posted a topic
here that outlined larger terrain w/ terraforming. I got help from GG, Back Slash, Van B and Paul (among others) on how to use arrays to edit multiple objects in vertexdata. I finally got something I'd like to work with - but I am having issues with seams. Take a look, no media needed.
You need Sparky's Collision plugin and Ian M's Matrix Utility Plugin for the code to work. It is still a little sluggish - but good enough fps for what I need it for.
If you reach the corner of one plane with the brush (a point intersecting with the corners of 4 planes) - A small to medium sized seam appears. I am trying to fix this issue exactly. Any thoughts?
`enviroment set up
type ob
number as integer
endtype
Startup()
`*********************************
`declarations and setup starts here
`*********************************
`make the objects that make up the landscape and set up the size variables
`column and row size
GLOBAL sz AS INTEGER=64
`actual object size to be created centred at 0,0,0 when created
GLOBAL obj_sz AS FLOAT=128.0
`how many tiles per row/col
GLOBAL tile_sz AS INTEGER=8`change this to 256 and watch what happens
`first object
GLOBAL lod_first_obj AS INTEGER
global dim Objects(tile_sz+tile_sz) as Ob
col=128``used to make a checker board pattern
FOR y=0 TO tile_sz
FOR x=0 TO tile_sz
obj=free_object()
Objects(X+Y).number=obj
IF x=0 AND y=0 THEN lod_first_obj=obj
`ianm matrix1 command
MAKE OBJECT PLAIN obj,obj_sz,obj_sz,sz,sz,338
`SET OBJECT WIREFRAME obj,1
POSITION OBJECT obj,x*obj_sz,0,y*obj_sz
COLOR OBJECT obj,RGB(128,128,128)
SC_SETUPCOMPLEXOBJECT obj,0,2
NEXT x
NEXT y
`make object to use for raycasting
GLOBAL ray_cast_obj_target
ray_cast_obj_target=free_object()
MAKE OBJECT CUBE ray_cast_obj_target,1
HIDE OBJECT ray_cast_obj_target
`make object to use for marker
GLOBAL ray_cast_obj_marker
ray_cast_obj_marker=free_object()
MAKE OBJECT CUBE ray_cast_obj_marker,2
COLOR OBJECT ray_cast_obj_marker,RGB(255,0,0)
GLOBAL cx AS FLOAT
GLOBAL cy AS FLOAT
GLOBAL cz AS FLOAT
GLOBAL col_obj AS INTEGER
GLOBAL nx AS FLOAT
GLOBAL ny AS FLOAT
GLOBAL nz AS FLOAT
GLOBAL face_hit AS INTEGER
Global dist# as float
global Object as integer
global px# as float
global py# as float
global pz# as float
global locationX# as float
global locationY# as float
global locationZ# as float
Global Dim objNums(8)
`*********************************
`main loop starts here
DO
`check for raycast to landscape and place marker
Answer=raycast_landscape()
`show or hide the marker depending on collision
`move the camera
mouse_control(1.0)
`display info
TEXT 0,0,"marker on object "+STR$(col_obj)
TEXT 0,20,"At Position x="+STR$(cx)+" y="+STR$(cy)+" z="+STR$(cz)
TEXT 0,40,"screen fps="+STR$(SCREEN FPS())
TEXT 0,60,"object face hit="+STR$(face_hit)
TEXT 0, 80, "Object Returned= "+Str$(Answer)
SYNC
LOOP
`*********************************
`functions start here
FUNCTION mouse_control(speed AS FLOAT)
if mouseclick()=2
XROTATE CAMERA CAMERA ANGLE X()+MOUSEMOVEY()
YROTATE CAMERA CAMERA ANGLE Y()+MOUSEMOVEX()
endif
IF upkey()=1 THEN MOVE CAMERA speed
IF downkey()=1 THEN MOVE CAMERA (0-speed)
if mouseclick()=4
XROTATE CAMERA CAMERA ANGLE X()+MOUSEMOVEY()
ENDIF
if rightkey()=1
YROTATE CAMERA CAMERA ANGLE Y()+1
ENDIF
if leftkey()=1
YROTATE CAMERA CAMERA ANGLE Y()-1
ENDIF
If Mouseclick()=3
MOVE CAMERA speed
XROTATE CAMERA CAMERA ANGLE X()+MOUSEMOVEY()
YROTATE CAMERA CAMERA ANGLE Y()+MOUSEMOVEX()
ENDIF
dummy=MOUSEMOVEX()
dummy=MOUSEMOVEY()
Newmousez = MousemoveZ()
If oldmousez <> newmousez
If oldmousez < newmousez
mousezz=speed*5
endif
If oldmousez > newmousez
mousezz=-speed*5
endif
MOVE CAMERA mousezz
Oldmousez=Mousemovez()
Mousezz=0
endif
ENDFUNCTION
FUNCTION free_object()
i = FIND FREE OBJECT()
ENDFUNCTION i
FUNCTION raycast_landscape()
ObjectNumber=location()
If ObjectNumber>0
Answer=ObjectNumber
ENDIF
If ObjectNumber=0 then Answer=Ray_Cast_Obj_Marker
POSITION OBJECT ray_cast_obj_target, CAMERA POSITION X(), CAMERA POSITION Y(), CAMERA POSITION Z()
SET OBJECT TO CAMERA ORIENTATION ray_cast_obj_target
`MOVE OBJECT ray_cast_obj_target,10000
col_obj=SC_RAYCAST(0,OBJECT POSITION X(ray_cast_obj_target),OBJECT POSITION Y(ray_cast_obj_target),OBJECT POSITION Z(ray_cast_obj_target), locationX#, LocationY#, LocationZ#,0)
POSITION OBJECT ray_cast_obj_marker,LocationX#,LocationY#,LocationZ#
IF col_obj>0
cx = SC_GETSTATICCOLLISIONX() : nx = SC_GETCOLLISIONNORMALX()
cy = SC_GETSTATICCOLLISIONY() : ny = SC_GETCOLLISIONNORMALY()
cz = SC_GETSTATICCOLLISIONZ() : nz = SC_GETCOLLISIONNORMALZ()
POINT OBJECT ray_cast_obj_marker,cx,cy,cz
face_hit=SC_GETFACEHIT()
ELSE
cx=0.0
cy=0.0
cz=0.0
nx=0.0
ny=0.0
nz=0.0
face_hit=0
ENDIF
BrushSize#=25.0
Terraform(Objectnumber, Ray_Cast_Obj_Marker, BrushSize#)
ENDFUNCTION Answer
function Terraform(ObjectNumber, RayObjNum, BrushSize#)
If MouseClick()=1
if Objectnumber>0
objNums(0) = Objectnumber
objNums(1) = Objectnumber + 1
objNums(2) = Objectnumber - 1
objNums(3) = Objectnumber + tile_sz
objNums(4) = Objectnumber + tile_sz + 1
objNums(5) = Objectnumber + tile_sz - 1
objNums(6) = Objectnumber - tile_sz
objNums(7) = Objectnumber - tile_sz + 1
objNums(8) = Objectnumber - tile_sz - 1
ENDIF
for obj = 0 to 8
reCalculateNormals = 0
if objNums(obj) > 0 and objNums(obj) <= tile_sz*tile_sz
LOCK VERTEXDATA FOR LIMB objNums(obj), 0
Vcount=GET VERTEXDATA VERTEX COUNT()-1
For Array=0 to Vcount
VerX#=GET VERTEXDATA POSITION X(Array)
VerY#=GET VERTEXDATA POSITION Y(Array)
VerZ#=GET VERTEXDATA POSITION Z(Array)
`calculate the correct vertices on the object to check against the others
tempX# = VerX# + OBJECT POSITION X(objNums(obj))
tempY# = VerY# + OBJECT POSITION Y(objNums(obj))
tempZ# = VerZ# + OBJECT POSITION Z(objNums(obj))
length=1
D#=Distance(TempX#, TempY#, TempZ#, OBJECT POSITION X(RayObjNum), OBJECT POSITION Y(RayObjNum), OBJECT POSITION Z(RayObjNum))
If D#<BrushSize#
IncAmount#=cos(D#*2)
endif
If D#>BrushSize# or D#=<0.0
incAmount# = 0.0
endif
if incAmount# > 0.0 then SET VERTEXDATA POSITION Array, VerX#, VerY# + incAmount#, VerZ# : reCalculateNormals = 1
SC_UpdateObject objNums(obj)
NEXT ARRAY
UNLOCK VERTEXDATA
SC_UpdateObject objNums(obj)
if reCalculateNormals=1
SET OBJECT NORMALS objNums(obj)
reCalculateNormals=0
endif
endif
next obj
endif
ENDFUNCTION
FUNCTION needed_for_sparkys()
IF MEMBLOCK EXIST(1)
ENDIF
ENDFUNCTION
function Location()
Dist#=GET PICK DISTANCE()
Object=PICK OBJECT (mouseX(), mouseY(), Objects(0).number, Objects(tile_sz+tile_sz).number)
PX#=GET PICK VECTOR X()
PY#=GET PICK VECTOR Y()
PZ#=GET PICK VECTOR Z()
LocationX#=CAMERA POSITION X()+PX#
LocationY#=CAMERA POSITION Y()+PY#
LocationZ#=CAMERA POSITION Z()+PZ#
ENDFUNCTION Object
function Startup()
IF CHECK DISPLAY MODE(DESKTOP WIDTH(),DESKTOP HEIGHT(),32)
SET DISPLAY MODE DESKTOP WIDTH(),DESKTOP HEIGHT(),32
h=DESKTOP HEIGHT()
w=DESKTOP WIDTH()
posx=w/2-w/2
posy=h/2-h/2
ELSE
SET DISPLAY MODE 640,480,32
h=DESKTOP HEIGHT()
w=DESKTOP WIDTH()
posx=w/2-320
posy=h/2-240
ENDIF
SET WINDOW POSITION posx,posy
SYNC ON
SYNC RATE 60
AUTOCAM OFF
COLOR BACKDROP 0,0
SET TEXT FONT "Arial"
SET TEXT SIZE 12
SET TEXT TRANSPARENT
SET CAMERA RANGE 1,1000
POSITION CAMERA 50,50,-50
POINT CAMERA 0,0,0
POSITION MOUSE SCREEN WIDTH()/2,SCREEN HEIGHT()/2
dummy=MOUSEMOVEX()
dummy=MOUSEMOVEY()
TEXT 0,0,"PLEASE WAIT DURING SET UP"
SYNC
SYNC
ENDFUNCTION
Function distance(x1#,y1#,z1#,x2#,y2#,z2#)
If VECTOR EXIST(200)=0
Length=MAKE VECTOR3(200)
ENDIF
set vector3 200,x2#-x1#,y2#-y1#,z2#-z1#
D#=length vector3(200)
EndFunction d#
EDIT:
Here's an Image
EDIT 2:
I could make several arrays with types attached ( A(vertexnumber).X) and position them at the correct locations (AKA take the object width and height and determine which vertices are on the edges of each plane and then smooth them based on average... but that's something I've not done. I grasp how to, but if there is a method of doing so, someone let me know or I'm gonna reinvent the wheel here) That would solve the problem theoretically.
EDIT 3: I need to understand how to use the arrays... here's an example with a 'array fix' for the seams that IS NOT working correctly.
`enviroment set up
type ob
number as integer
endtype
Type Verposition
number as Integer
X as float
Y as float
Z as float
endtype
Startup()
`*********************************
`declarations and setup starts here
`*********************************
`make the objects that make up the landscape and set up the size variables
`column and row size
GLOBAL sz AS INTEGER=64
`actual object size to be created centred at 0,0,0 when created
GLOBAL obj_sz AS FLOAT=128.0
`how many tiles per row/col
GLOBAL tile_sz AS INTEGER=4`change this to 256 and watch what happens
`first object
GLOBAL lod_first_obj AS INTEGER
global dim Objects(tile_sz+tile_sz) as Ob
col=128``used to make a checker board pattern
FOR y=0 TO tile_sz
FOR x=0 TO tile_sz
obj=free_object()
Objects(X+Y).number=obj
IF x=0 AND y=0
lod_first_obj=obj
ENDIF
`ianm matrix1 command
MAKE OBJECT PLAIN obj,obj_sz,obj_sz,sz,sz,338
`SET OBJECT WIREFRAME obj,1
POSITION OBJECT obj,x*obj_sz,0,y*obj_sz
If X=0
LOCK VERTEXDATA FOR LIMB Objects(X+Y).number, 0
Amount=Get vertexdata vertex count()
unlock vertexdata
ENDIF
COLOR OBJECT obj,RGB(128,128,128)
SC_SETUPCOMPLEXOBJECT obj,0,2
NEXT x
NEXT y
global dim Obj1(Amount) as Verposition
global dim Obj2(Amount) as Verposition
global dim Obj3(Amount) as Verposition
global dim Obj4(Amount) as Verposition
global dim Obj5(Amount) as Verposition
`make object to use for raycasting
GLOBAL ray_cast_obj_target
ray_cast_obj_target=free_object()
MAKE OBJECT CUBE ray_cast_obj_target,1
HIDE OBJECT ray_cast_obj_target
`make object to use for marker
GLOBAL ray_cast_obj_marker
ray_cast_obj_marker=free_object()
MAKE OBJECT CUBE ray_cast_obj_marker,2
COLOR OBJECT ray_cast_obj_marker,RGB(255,0,0)
GLOBAL cx AS FLOAT
GLOBAL cy AS FLOAT
GLOBAL cz AS FLOAT
GLOBAL col_obj AS INTEGER
GLOBAL nx AS FLOAT
GLOBAL ny AS FLOAT
GLOBAL nz AS FLOAT
GLOBAL face_hit AS INTEGER
Global dist# as float
global Object as integer
global px# as float
global py# as float
global pz# as float
global locationX# as float
global locationY# as float
global locationZ# as float
Global Dim objNums(8)
`*********************************
`main loop starts here
DO
`check for raycast to landscape and place marker
Answer=raycast_landscape()
`show or hide the marker depending on collision
`move the camera
mouse_control(1.0)
`display info
TEXT 0,0,"marker on object "+STR$(col_obj)
TEXT 0,20,"At Position x="+STR$(cx)+" y="+STR$(cy)+" z="+STR$(cz)
TEXT 0,40,"screen fps="+STR$(SCREEN FPS())
TEXT 0,60,"object face hit="+STR$(face_hit)
TEXT 0, 80, "Object Returned= "+Str$(Answer)
SYNC
LOOP
`*********************************
`functions start here
FUNCTION mouse_control(speed AS FLOAT)
if mouseclick()=2
XROTATE CAMERA CAMERA ANGLE X()+MOUSEMOVEY()
YROTATE CAMERA CAMERA ANGLE Y()+MOUSEMOVEX()
endif
IF upkey()=1 THEN MOVE CAMERA speed
IF downkey()=1 THEN MOVE CAMERA (0-speed)
if mouseclick()=4
XROTATE CAMERA CAMERA ANGLE X()+MOUSEMOVEY()
ENDIF
if rightkey()=1
YROTATE CAMERA CAMERA ANGLE Y()+1
ENDIF
if leftkey()=1
YROTATE CAMERA CAMERA ANGLE Y()-1
ENDIF
If Mouseclick()=3
MOVE CAMERA speed
XROTATE CAMERA CAMERA ANGLE X()+MOUSEMOVEY()
YROTATE CAMERA CAMERA ANGLE Y()+MOUSEMOVEX()
ENDIF
dummy=MOUSEMOVEX()
dummy=MOUSEMOVEY()
Newmousez = MousemoveZ()
If oldmousez <> newmousez
If oldmousez < newmousez
mousezz=speed*5
endif
If oldmousez > newmousez
mousezz=-speed*5
endif
MOVE CAMERA mousezz
Oldmousez=Mousemovez()
Mousezz=0
endif
ENDFUNCTION
FUNCTION free_object()
i = FIND FREE OBJECT()
ENDFUNCTION i
FUNCTION raycast_landscape()
ObjectNumber=location()
If ObjectNumber>0
Answer=ObjectNumber
ENDIF
If ObjectNumber=0 then Answer=Ray_Cast_Obj_Marker
POSITION OBJECT ray_cast_obj_target, CAMERA POSITION X(), CAMERA POSITION Y(), CAMERA POSITION Z()
SET OBJECT TO CAMERA ORIENTATION ray_cast_obj_target
`MOVE OBJECT ray_cast_obj_target,10000
col_obj=SC_RAYCAST(0,OBJECT POSITION X(ray_cast_obj_target),OBJECT POSITION Y(ray_cast_obj_target),OBJECT POSITION Z(ray_cast_obj_target), locationX#, LocationY#, LocationZ#,0)
POSITION OBJECT ray_cast_obj_marker,LocationX#,LocationY#,LocationZ#
IF col_obj>0
cx = SC_GETSTATICCOLLISIONX() : nx = SC_GETCOLLISIONNORMALX()
cy = SC_GETSTATICCOLLISIONY() : ny = SC_GETCOLLISIONNORMALY()
cz = SC_GETSTATICCOLLISIONZ() : nz = SC_GETCOLLISIONNORMALZ()
POINT OBJECT ray_cast_obj_marker,cx,cy,cz
face_hit=SC_GETFACEHIT()
ELSE
cx=0.0
cy=0.0
cz=0.0
nx=0.0
ny=0.0
nz=0.0
face_hit=0
ENDIF
BrushSize#=sz/2
If mouseclick()=1
Terraform(Objectnumber, Ray_Cast_Obj_Marker, BrushSize#)
endif
ENDFUNCTION Answer
function Terraform(ObjectNumber, RayObjNum, BrushSize#)
if Objectnumber>0
objNums(0) = Objectnumber
objNums(1) = Objectnumber + 1
objNums(2) = Objectnumber - 1
objNums(3) = Objectnumber + tile_sz
objNums(4) = Objectnumber + tile_sz + 1
objNums(5) = Objectnumber + tile_sz - 1
objNums(6) = Objectnumber - tile_sz
objNums(7) = Objectnumber - tile_sz + 1
objNums(8) = Objectnumber - tile_sz - 1
ENDIF
for obj = 0 to 8
reCalculateNormals = 0
if objNums(obj) > 0 and objNums(obj) <= tile_sz*tile_sz
LOCK VERTEXDATA FOR LIMB objNums(obj), 0
Vcount=GET VERTEXDATA VERTEX COUNT()-1
For Array=0 to Vcount
VerX#=GET VERTEXDATA POSITION X(Array)
VerY#=GET VERTEXDATA POSITION Y(Array)
VerZ#=GET VERTEXDATA POSITION Z(Array)
`calculate the correct vertices on the object to check against the others
tempX# = VerX# + OBJECT POSITION X(objNums(obj))
tempY# = VerY# + OBJECT POSITION Y(objNums(obj))
tempZ# = VerZ# + OBJECT POSITION Z(objNums(obj))
length=1
D#=Distance(TempX#, TempY#, TempZ#, OBJECT POSITION X(RayObjNum), OBJECT POSITION Y(RayObjNum), OBJECT POSITION Z(RayObjNum))
If D#<BrushSize#
IncAmount#=cos(D#*2)
endif
If D#>BrushSize# or D#=<0.0
incAmount# = 0.0
endif
`the seamless array
`Center object
If Obj=0
Obj1(Array).X=TempX#
Obj1(Array).Y=TempY#
Obj1(Array).Z=TempZ#
obj1(array).number=objNums(obj)
endif
If Obj=1
Obj2(Array).X=TempX#
Obj2(Array).Y=TempY#
Obj2(Array).Z=TempX#
obj2(array).number=objNums(obj)
endif
If Obj=2
Obj3(Array).X=TempX#
Obj3(Array).Y=TempY#
Obj3(Array).Z=TempZ#
obj3(array).number=objNums(obj)
endif
If Obj=7
Obj4(Array).X=TempX#
Obj4(Array).Y=TempY#
Obj4(Array).Z=TempZ#
obj4(array).number=objNums(obj)
endif
If Obj=8
Obj5(Array).X=TempX#
Obj5(Array).Y=TempY#
Obj5(Array).Z=TempZ#
obj5(array).number=objNums(obj)
endif
IF Obj1(Array).X=Obj2(Array).X and Obj1(array).Z= Obj2(array).Z then Obj2(Array).Y=Obj1(Array).Y : VerY#=Obj1(array).Y
IF Obj1(Array).X=Obj3(Array).X and Obj1(array).Z= Obj3(array).Z then Obj3(Array).Y=Obj1(Array).Y : VerY#=Obj1(array).Y
IF Obj1(Array).X=Obj4(Array).X and Obj1(array).Z= Obj4(array).Z then Obj4(Array).Y=Obj1(Array).Y : VerY#=Obj1(array).Y
IF Obj1(Array).X=Obj5(Array).X and Obj1(array).Z= Obj5(array).Z then Obj5(Array).Y=Obj1(Array).Y : VerY#=Obj1(array).Y
if incAmount# > 0.0 then SET VERTEXDATA POSITION Array, VerX#, VerY# + incAmount#, VerZ# : reCalculateNormals = 1
SC_UpdateObject objNums(obj)
NEXT ARRAY
UNLOCK VERTEXDATA
SC_UpdateObject objNums(obj)
if reCalculateNormals=1
SET OBJECT NORMALS objNums(obj)
reCalculateNormals=0
endif
endif
next obj
ENDFUNCTION
FUNCTION needed_for_sparkys()
IF MEMBLOCK EXIST(1)
ENDIF
ENDFUNCTION
function Location()
Dist#=GET PICK DISTANCE()
Object=PICK OBJECT (mouseX(), mouseY(), Objects(0).number, Objects(tile_sz+tile_sz).number)
PX#=GET PICK VECTOR X()
PY#=GET PICK VECTOR Y()
PZ#=GET PICK VECTOR Z()
LocationX#=CAMERA POSITION X()+PX#
LocationY#=CAMERA POSITION Y()+PY#
LocationZ#=CAMERA POSITION Z()+PZ#
ENDFUNCTION Object
function Startup()
IF CHECK DISPLAY MODE(DESKTOP WIDTH(),DESKTOP HEIGHT(),32)
SET DISPLAY MODE DESKTOP WIDTH(),DESKTOP HEIGHT(),32
h=DESKTOP HEIGHT()
w=DESKTOP WIDTH()
posx=w/2-w/2
posy=h/2-h/2
ELSE
SET DISPLAY MODE 640,480,32
h=DESKTOP HEIGHT()
w=DESKTOP WIDTH()
posx=w/2-320
posy=h/2-240
ENDIF
SET WINDOW POSITION posx,posy
SYNC ON
SYNC RATE 60
AUTOCAM OFF
COLOR BACKDROP 0,0
SET TEXT FONT "Arial"
SET TEXT SIZE 12
SET TEXT TRANSPARENT
SET CAMERA RANGE 1,1000
POSITION CAMERA 50,50,-50
POINT CAMERA 0,0,0
POSITION MOUSE SCREEN WIDTH()/2,SCREEN HEIGHT()/2
dummy=MOUSEMOVEX()
dummy=MOUSEMOVEY()
TEXT 0,0,"PLEASE WAIT DURING SET UP"
SYNC
SYNC
ENDFUNCTION
Function distance(x1#,y1#,z1#,x2#,y2#,z2#)
If VECTOR EXIST(200)=0
Length=MAKE VECTOR3(200)
ENDIF
set vector3 200,x2#-x1#,y2#-y1#,z2#-z1#
D#=length vector3(200)
EndFunction d#
Jack and Jill went up a hill to fetch a pale of water... but Jill got tired of his s#%& so she shot him.
