I decided to share a small shader that is designed to draw 3D lines on the screen. This is an alternative to the standard DrawLine method. Perhaps someone will find it useful.
This can be used to draw paths, or to display the wireframe of an object (if you get the coordinates of all vertices using a memblock).
Below is a small demo showing the shader in action. Shader files are generated directly from the AppGameKit code for convenience.
Transformation of 3D -> 2D coordinates is carried out in the shader itself. As initial data, we can set the coordinates of 2 points of the 3D line, as well as its color. It is also possible to set the line width in pixels, but I did not output this as an input parameter.
+ Code SnippetSetErrorMode(2)
SetWindowTitle("test")
SetWindowSize(1024,768,0)
SetWindowAllowResize(1)
MaximizeWindow()
global scr_w as integer : scr_w=GetMaxDeviceWidth()
global scr_h as integer : scr_h=GetMaxDeviceHeight()
global scr_ratio# as float
scr_ratio# = 1.0*scr_h/scr_w
if scr_ratio#>0.7:scr_w=1920:scr_h=1080:endif
SetVirtualResolution(scr_w,scr_h)
SetOrientationAllowed(1,1,1,1)
SetSyncRate(120,0)
SetScissor(0,0,0,0)
UseNewDefaultFonts(1)
SetPrintSize(28)
SetCameraRange(1,10,10000)
#constant true 1
#constant false 0
type coord
x as float
y as float
z as float
l as float
nx as float
ny as float
nz as float
endtype
type tcoord
u as float
v as float
endtype
global mousex# as float
global mousey# as float
global curcamx# as float
global curcamy# as float
global curcamz# as float
global cameraMove as integer
global cam_f as coord
global smes_spd# as float
global camR_old as float
global camR as float
global camRMin as float
global camRMax as float
global DeltaCamR as float
global camA as float
global camB as float
global camA_min as float
global camA_max as float
global camB_min as float
global camB_max as float
global camA_inn as float
global camB_inn as float
global camE as float
global camD as float
global camF as float
global mmx# as float
global mmy# as float
global nmx# as float
global nmy# as float
global foc_bound_left as float
global foc_bound_right as float
global foc_bound_up as float
global foc_bound_down as float
global pick_dist as float
global pick_dirX as float
global pick_dirY as float
global pick_dirZ as float
global pickID as integer
global pick_stat as integer
global pick_state as integer
global time_before as float
global time_begin as float
global time_lost as float
global time_curr as float
global inner_speed as float
global obj_foc : obj_foc = CreateObjectBox(1, 1, 1)
SetObjectPosition(obj_foc,0,0,0)
SetObjectVisible(obj_foc, 0)
cam_f.x = 0
cam_f.y = 0
cam_f.z = 0
camRMin = 1000
camRMax = 50
camR_old = camRMin
camR = camR_old
DeltaCamR= 50
camA = 30
camB = 0
camA_min = 0
camA_max = 89
camB_min = 0
camB_max = 0
camA_inn = camA
camB_inn = camB
camE = 0
camD = 0
camF = 0
mmx# = 0
mmy# = 0
nmx# = 0
nmy# = 0
foc_bound_left =-520
foc_bound_right = 520
foc_bound_up = 520
foc_bound_down =-520
SetObjectPosition( obj_foc, cam_f.x,cam_f.y,cam_f.z)
SetCameraPosition(1, cam_f.x+(CamR*cos(270-CamB)*cos(CamA)), cam_f.y+(CamR*sin(CamA)),cam_f.z+(CamR*sin(270-CamB)*cos(CamA)))
SetCameraLookAt( 1, cam_f.x, cam_f.y, cam_f.z, 0)
createVSShaderFile()
createPSshaderFile()
shader=LoadShader("vertex_shader.vs","pixel_shader.ps")
ground = CreateObjectPlane(1000,1000)
SetObjectRotation(ground,90,0,0)
SetObjectColor(ground,0,40,0,255)
global wp_dimx# as float = 200.0
global wp_dimy# as float = 50.0
global wp_dimz# as float = 200.0
obj3ID = CreateObjectBox(wp_dimx#,wp_dimy#,wp_dimz#)
SetObjectPosition(obj3ID,-150,25,150)
SetObjectCullMode(obj3ID,0)
obj2ID = CreateObjectSphere(60,24,24)
SetObjectPosition(obj2ID,-50,60,150)
setobjectcullmode(obj2ID,0)
global pla : pla = createobjectplane(5,5)
SetObjectRotation(pla,90,0,0)
SetObjectPosition(pla,0,100,0)
SetObjectShader(pla, shader)
global testob : testob = createobjectbox(5,5,100)
SetObjectPosition(testob,0,100,0)
SetObjectColor(testob,0,255,0,255)
global testob2 : testob2 = createobjectplane(5,5)
SetObjectRotation(testob2,90,0,0)
SetObjectPosition(testob2,100,100,0)
SetObjectShader(testob2, shader)
do
time#=timer()
time_begin = GetMilliseconds()
time_curr = time_begin - time_before
mousex# = GetPointerX()
mousey# = GetPointerY()
if ScreenFPS() > 30
inner_speed = ScreenFPS()/15.0
else
inner_speed = 10
endif
camera_control(1)
`SetObjectPosition(pla,GetCameraX(1),GetCameraY(1),GetCameraZ(1))
`SetObjectRotation(pla,GetCameraAngleX(1),GetCameraAngleY(1),GetCameraAngleZ(1))
`MoveObjectLocalZ(pla,50)
SetShaderConstantByName(shader,"ViewPortSize",GetWindowWidth(),GetWindowHeight(),0,0)
p1x#=GetObjectX(testob)
p1y#=GetObjectY(testob)
p1z#=GetObjectZ(testob)-50
p2x#=GetObjectX(testob)
p2y#=GetObjectY(testob)
p2z#=GetObjectZ(testob)+50
SetObjectShaderConstantByName(pla,"point1",p1x#,p1y#,p1z#,0)
SetObjectShaderConstantByName(pla,"point2",p2x#,p2y#,p2z#,0)
SetObjectShaderConstantByName(pla,"LineColor",255,0,0,0)
p1x2#=GetObjectX(testob2)
p1y2#=GetObjectY(testob2)
p1z2#=GetObjectZ(testob2)-50
p2x2#=GetObjectX(testob2)+50
p2y2#=GetObjectY(testob2)
p2z2#=GetObjectZ(testob2)+50
SetObjectShaderConstantByName(testob2,"point1",p1x2#,p1y2#,p1z2#,0)
SetObjectShaderConstantByName(testob2,"point2",p2x2#,p2y2#,p2z2#,0)
SetObjectShaderConstantByName(testob2,"LineColor",0,0,255,0)
if GetRawKeyPressed(27) then end
Print("To control the camera, use the mouse: LMB-shift, RMB-rotate, Scroll-zoom" )
Print("FPS="+ str(ScreenFPS()) )
Print("GetMaxDeviceWidth()="+ str(GetMaxDeviceWidth()) )
Print("GetMaxDeviceHeight()="+ str(GetMaxDeviceHeight()) )
Print("GetDeviceWidth()="+ str(GetDeviceWidth()) )
Print("GetDeviceHeight()="+ str(GetDeviceHeight()) )
Print("GetVirtualWidth()="+ str(GetVirtualWidth()) )
Print("GetVirtualHeight()="+ str(GetVirtualHeight()) )
Print("GetWindowWidth()="+ str(GetWindowWidth()) )
Print("GetWindowHeight()="+ str(GetWindowHeight()) )
Print("GetScreenBoundsLeft()="+ str(GetScreenBoundsLeft()) )
Print("GetScreenBoundsRight()="+ str(GetScreenBoundsRight()) )
Print("GetScreenBoundsTop()="+ str(GetScreenBoundsTop()) )
Print("GetScreenBoundsBottom()="+ str(GetScreenBoundsBottom()) )
Print("GetScreenBoundsSafeLeft()="+ str(GetScreenBoundsSafeLeft()) )
Print("GetScreenBoundsSafeRight()="+ str(GetScreenBoundsSafeRight()) )
Print("GetScreenBoundsSafeTop()="+ str(GetScreenBoundsSafeTop()) )
Print("GetScreenBoundsSafeBottom()="+ str(GetScreenBoundsSafeBottom()) )
Sync()
time_lost = GetMilliseconds() - time_begin
loop
function createVSShaderFile()
fw = OpenToWrite("vertex_shader.vs")
remstart
WriteLine(fw,"attribute highp vec3 position;")
WriteLine(fw,"attribute mediump vec3 normal;")
WriteLine(fw,"attribute mediump vec2 uv;")
WriteLine(fw,"varying highp vec3 posVarying;")
WriteLine(fw,"varying mediump vec3 normalVarying;")
WriteLine(fw,"varying mediump vec2 uvVarying;")
WriteLine(fw,"varying mediump vec3 lightVarying;")
WriteLine(fw,"uniform highp mat3 agk_WorldNormal;")
WriteLine(fw,"uniform highp mat4 agk_World;")
WriteLine(fw,"uniform highp mat4 agk_ViewProj;")
WriteLine(fw,"uniform mediump vec4 uvBounds0;")
WriteLine(fw,"mediump vec3 GetVSLighting( mediump vec3 normal, highp vec3 pos );")
WriteLine(fw,"void main()")
WriteLine(fw,"{")
WriteLine(fw," uvVarying = uv * uvBounds0.xy + uvBounds0.zw;")
WriteLine(fw," highp vec4 pos = agk_World * vec4(position,1.0);")
WriteLine(fw," gl_Position = agk_ViewProj * pos;")
WriteLine(fw," mediump vec3 norm = normalize(agk_WorldNormal * normal);")
WriteLine(fw," posVarying = pos.xyz;")
WriteLine(fw," normalVarying = norm;")
WriteLine(fw," lightVarying = GetVSLighting( norm, posVarying );")
WriteLine(fw,"}")
remend
WriteLine(fw,"attribute highp vec3 position;")
WriteLine(fw,"void main()")
WriteLine(fw,"{")
WriteLine(fw," gl_Position = vec4(position,1.0);")
WriteLine(fw,"}")
CloseFile(fw)
endfunction
function createPSshaderFile()
fw=OpenToWrite("pixel_shader.ps")
remstart
WriteLine(fw,"uniform sampler2D texture0;")
WriteLine(fw,"varying highp vec3 posVarying;")
WriteLine(fw,"varying mediump vec3 normalVarying;")
WriteLine(fw,"varying mediump vec2 uvVarying;")
WriteLine(fw,"varying mediump vec3 lightVarying;")
WriteLine(fw,"mediump vec3 GetPSLighting( mediump vec3 normal, highp vec3 pos );")
WriteLine(fw,"mediump vec3 ApplyFog( mediump vec3 color, highp vec3 pointPos );")
WriteLine(fw,"void main()")
WriteLine(fw,"{")
WriteLine(fw," mediump vec3 norm = normalize(normalVarying);")
WriteLine(fw," mediump vec3 light = lightVarying + GetPSLighting( norm, posVarying );")
WriteLine(fw," mediump vec3 color = texture2D(texture0, uvVarying).rgb * light;")
WriteLine(fw," color = ApplyFog( color, posVarying );")
WriteLine(fw," gl_FragColor = vec4(color,1.0);")
WriteLine(fw,"}")
remend
WriteLine(fw,"uniform mediump vec2 ViewPortSize;") // dimensions of the working area of the AGK window
WriteLine(fw,"uniform mediump vec3 point1;") // 3D coordinates of point ?1
WriteLine(fw,"uniform mediump vec3 point2;") // 3D coordinates of point ?2
WriteLine(fw,"uniform mediump vec3 LineColor;") // line color
WriteLine(fw,"uniform highp mat4 agk_ViewProj;") // combination of the View and Proj matrices transforms 3D world space into window space.
// "draw" line function
WriteLine(fw,"float drawLine2(vec2 p1, vec2 p2, vec2 uv, float aa)") // aa - line thickness
WriteLine(fw,"{")
// if the current point is on the line according to the distance, it should be the same as the current uv coordinates
WriteLine(fw," mediump float r = 1.0-floor(1.0-(aa/ViewPortSize.x)+distance(mix(p1, p2, clamp(distance(p1,uv)/distance(p1,p2), 0., 1.)), uv));")
WriteLine(fw,"return r;")
WriteLine(fw,"}")
WriteLine(fw,"void main()")
WriteLine(fw,"{")
WriteLine(fw," mediump vec2 uv = gl_FragCoord.xy/ViewPortSize.xy;") // current point of the screen
WriteLine(fw," mediump vec4 vp1 = agk_ViewProj*vec4(point1,1);") // convert the given 3D coordinates of point ?1 into 2D viewport coordinates
WriteLine(fw," mediump vec4 vp2 = agk_ViewProj*vec4(point2,1);") // convert the given 3D coordinates of point ?2 into 2D viewport coordinates
WriteLine(fw," mediump vec2 p1 = (vp1.xy/vp1.w)*0.5+0.5;") // transform from the interval [-1,1] to the interval [0,1]
WriteLine(fw," mediump vec2 p2 = (vp2.xy/vp2.w)*0.5+0.5;") // transform from the interval [-1,1] to the interval [0,1]
WriteLine(fw," mediump float px = drawLine2(p1,p2,uv,1.0);") // a pixel belonging to a line
WriteLine(fw," if (px == 0.0) {") // if pixel does not lie on line
WriteLine(fw," discard;") // don't draw it
WriteLine(fw," } else {") // if the pixel belongs to the line
WriteLine(fw," gl_FragColor=vec4(px*normalize(LineColor),1);") // draw it with color
WriteLine(fw," }")
WriteLine(fw,"}")
CloseFile(fw)
endfunction
function CurveValue( ar_dest as float , ar_cur as float , ar_smoot as float )
ar_cur = ar_cur + ( ( ar_dest - ar_cur ) / ar_smoot )
endfunction ar_cur
function lin_inp( arA1 as float , arA2 as float , arA3 as float , arB1 as float , arB3 as float )
ret_val as float : ret_val = arB1 - ( arB1 - arB3 ) * ( arA2 - arA1 ) / ( arA3 - arA1 )
endfunction ret_val
function camera_control(mode as integer)
curcamx# = getcamerax(1)
curcamy# = getcameray(1)
curcamz# = getcameraz(1)
if mousex# >= 0 and mousex# <= scr_w and mousey# >= 0 and mousey# <= scr_h
if CameraMove > 0 and GetRawMouseLeftState() = 0 and GetRawMouseRightState() = 0 then CameraMove = 0
if GetRawMouseLeftPressed() = 1 or GetRawMouseRightPressed() = 1
mmx# = GetRawMouseX()
mmy# = GetRawMouseY()
endif
if pick_state = 0
if CameraMove = 0
if (GetRawMouseLeftPressed() = 1 and GetRawMouseRightPressed() = 1) or (GetRawMouseLeftPressed() = 0 and GetRawMouseRightPressed() = 1)
if pick_stat = 0 then CameraMove = 1
endif
if GetRawMouseLeftPressed() = 1 and GetRawMouseRightPressed() = 0
if pick_stat = 0 then CameraMove = 2
endif
endif
endif
endif
if CameraMove = 1
nmx# = GetRawMouseX()
nmy# = GetRawMouseY()
inc CamA, 0.1*(nmy#-mmy#)
inc CamB, 0.1*(nmx#-mmx#)
mmx# = nmx#
mmy# = nmy#
endif
smes_spd# = 1.2 - (1.2 - 2.0) * (CamR - CamRMax) / (CamRMin - CamRMax)
if smes_spd# <= 1.2 then smes_spd# = 1.2
if smes_spd# >= 2.0 then smes_spd# = 2.0
if CameraMove = 2
nmx# = GetRawMouseX()
nmy# = GetRawMouseY()
dnmx# = nmx#-mmx#
dnmy# = nmy#-mmy#
if (dnmx#>0 and cam_f.x>foc_bound_left) or (dnmx#< 0 and cam_f.x<foc_bound_right)
if CamA<90
MoveObjectLocalX(obj_foc,-0.25*smes_spd#*dnmx#)
else
MoveObjectLocalX(obj_foc, 0.25*smes_spd#*dnmx#)
endif
endif
if mode=0
setobjectrotation(obj_foc,0,0,0)
if (dnmy#<0 and cam_f.y>foc_bound_down) or (dnmy#>0 and cam_f.y<foc_bound_up)
if CamA >= -70 and CamA <= 70 then MoveObjectLocalY(obj_foc,cos(camA)*0.25*smes_spd#*dnmy#)
endif
cam_f.x = curvevalue(GetObjectX(obj_foc),cam_f.x,inner_speed)
cam_f.y = curvevalue(GetObjectY(obj_foc),cam_f.y,inner_speed)
else
setobjectrotation(obj_foc,0,getcameraangley(1),0)
if (dnmy#<0 and cam_f.y>foc_bound_down) or (dnmy#>0 and cam_f.y<foc_bound_up)
if CamA<90
MoveObjectLocalZ(obj_foc,0.25*smes_spd#*dnmy#)
else
MoveObjectLocalZ(obj_foc,-0.25*smes_spd#*dnmy#)
endif
endif
cam_f.x = curvevalue(GetObjectX(obj_foc),cam_f.x,inner_speed)
cam_f.z = curvevalue(GetObjectZ(obj_foc),cam_f.z,inner_speed)
endif
mmx# = nmx#
mmy# = nmy#
main_status_camera_act = 1
endif
if GetRawMouseWheelDelta() < 0
CamR_old = CamR_old + DeltaCamR
endif
if GetRawMouseWheelDelta() > 0
CamR_old = CamR_old - DeltaCamR
endif
if CamR_old <= CamRMax then CamR_old = CamRMax
if CamR_old >= CamRMin then CamR_old = CamRMin
if CamA < camA_min then CamA = camA_min
if CamA > camA_max then CamA = camA_max
if camB_min = camB_max
if CamB < 0 then CamB = 360
if CamB > 360 then CamB = 0
else
if CamB < camB_min then CamB = camB_min
if CamB > camB_max then CamB = camB_max
endif
if cam_f.x < foc_bound_left then cam_f.x = foc_bound_left
if cam_f.x > foc_bound_right then cam_f.x = foc_bound_right
if mode=0
if cam_f.y < foc_bound_down then cam_f.y = foc_bound_down
if cam_f.y > foc_bound_up then cam_f.y = foc_bound_up
else
if cam_f.z < foc_bound_down then cam_f.z = foc_bound_down
if cam_f.z > foc_bound_up then cam_f.z = foc_bound_up
endif
CamR = curvevalue(CamR_old, CamR, inner_speed)
camA_inn = CamA
camB_inn = CamB
CamE = CamR * cos(270-CamB_inn)*cos(CamA_inn)
CamD = CamR * sin( CamA_inn)
CamF = CamR * sin(270-CamB_inn)*cos(CamA_inn)
SetObjectPosition( obj_foc, curvevalue(cam_f.x,GetObjectX(obj_foc),inner_speed), curvevalue(cam_f.y,GetObjectY(obj_foc),inner_speed), curvevalue(cam_f.z,GetObjectZ(obj_foc),inner_speed))
SetCameraPosition(1, cam_f.x+CamE , cam_f.y+CamD , cam_f.z+CamF )
if CamA<90
SetCameraLookAt( 1, cam_f.x, cam_f.y, cam_f.z, 0)
else
SetCameraLookAt( 1, cam_f.x, cam_f.y, cam_f.z, 180)
endif
endfunction