Omnimaga

Calculator Community => Other Calc-Related Projects and Ideas => TI-Nspire => Topic started by: Chockosta on September 24, 2011, 09:01:10 am

Title: [Lua] Tiny3D
Post by: Chockosta on September 24, 2011, 09:01:10 am
Hello guys !

I haven't done anything for two weeks, because of my homework :(
But I have a new project ! This is a small 3D engine.
I know that there is already Make3D by Levak, which is amazing, but I have to train with 3D. Moreover, mine is supposed to be a game engine, because it is very small. (I don't know if Lua is fast enough to use it)

So if anyone's interested, I post my engine...
I also add screenshots of a little 3D viewer made with that engine.
For now, it only draw vertices and edges. I'll try to add triangles...

________________________________________________________________________________

EDIT

10/01/2011 : The engine is finished...
New code :
Spoiler For Spoiler:
Code: [Select]
--Lua Tiny3D - By Loic Pujet

function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2,count={},1
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     faces2[count]=faces[j]
     count=count+1
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces,offset)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e+offset,zsum/#e}
   dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3]
  distTbl[i]=dist
  facesTbl[i]=dist
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function chooseColor(gc,vertices,face,color)
 if #face<3 then
  gc:setColorRGB(color[1],color[2],color[3])
 else
  local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3]
  local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3]
  local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)}
  local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2])
  local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50
  R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B
  R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B
  gc:setColorRGB(R,G,B)
 end
end

function renderFaces(gc,vertices,faces,pos,mode,color,offset)
 local polygon,size,faces2={},0,{}
 if mode==4 or mode==5 or mode==6 then
  faces2=sortFaces(vertices,faces,offset)
 else
  faces2=faces
 end
 for i,e in pairs(faces2) do
  polygon,size={},0
  drawPoly=true
  for j,f in pairs(faces2[i]) do
   if not pos[f] then
    drawPoly=false
   else
    polygon[j*2-1]=pos[f][1]
    polygon[j*2]=pos[f][2]
    size=size+2
   end
  end
  if drawPoly then
   polygon[size+1]=pos[faces2[i][1]][1]
   polygon[size+2]=pos[faces2[i][1]][2]
   if mode==4 then
    gc:setColorRGB(color[1],color[2],color[3])
    gc:fillPolygon(polygon)
   elseif mode==5 or mode==6 then
    chooseColor(gc,vertices,e,color)
    gc:fillPolygon(polygon)
   end
   if mode==2 or mode==3 or mode==4 or mode==5 then
    gc:setColorRGB(0,0,0)
    gc:setPen("thin","smooth")
    gc:drawPolyLine(polygon)
   end
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

----------------------------------------------------------------------------

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function render(gc,vertices,faces,mode,color,offset)
 local yDist,pos=0,{}
 for i,e in pairs(vertices) do
  if e[2]>-offset then
   yDist=offset/(e[2]+offset)
   pos[i]={e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25}
  else
   pos[i]=false
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if #faces>0 and (mode==2 or mode==3 or mode==4 or mode==5 or mode==6) then
  renderFaces(gc,vertices,faces,pos,mode,color,offset)
 end
end

----------------------------------------------------------------------------
New screenshots :
(http://www.omnimaga.org/index.php?action=dlattach;topic=10581.0;attach=9644;image)(http://www.omnimaga.org/index.php?action=dlattach;topic=10581.0;attach=9645;image)
Title: Re: [Lua] Tiny3D
Post by: Eiyeron on September 24, 2011, 09:15:38 am
Great work! Is it enough fast?
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 24, 2011, 09:21:49 am
I think I can get 100 FPS...
If I draw 200 cubes, It's more like 5-10 FPS
Title: Re: [Lua] Tiny3D
Post by: Levak on September 24, 2011, 09:36:30 am
Note : it is fast without fill-face-algorithms :D
If you're not sure of the speed (because 100fps is really fast) just make an animation of a turn around, like 10 turns, and calculate the time it took.

Then, calculate the number of frames it requires to make this turnaround.
Like if the increment is 5°, it will take 360/5 frames to make a complete turn.

And then : fps=(number of frames)/(seconds) :D
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 24, 2011, 09:59:00 am
48 FPS...
With "timer.start(0.01)" to repeat the rotation.
Title: Re: [Lua] Tiny3D
Post by: Levak on September 24, 2011, 10:07:56 am
On CX ? ClickPad/TouchPad ? Computer Software ?
Because each of those values are differents =)
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 24, 2011, 10:09:44 am
On my Clickpad.
Which one is the slowest ?
Title: Re: [Lua] Tiny3D
Post by: Levak on September 24, 2011, 10:10:08 am
On my Clickpad.
Which one is the slowest ?
The CX =)

Computer Software > ClickPad/TouchPad > CX
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 24, 2011, 10:13:50 am
And, by the way, what is the fastest way to draw faces ?
With a lot of gc:fillRect(x,y,1,height) ?
Or with gc:fillPolygon ?
Title: Re: [Lua] Tiny3D
Post by: Levak on September 24, 2011, 10:18:22 am
And, by the way, what is the fastest way to draw faces ?
With a lot of gc:fillRect(x,y,1,height) ?
Or with gc:fillPolygon ?

Hummm ... I really don't know, but let's think ...
 - Lua methods are implemented in C directly in the OS.
 - how a fillpolygon method works ? by filling horizontal or vertical lines. I don't know other methods.
 - How a fillRect method works ? by filling hozintal or vertical lines.

Basicly it uses the same underground methods don't you think ?
So I guess using fillPolygon is smarter.

It is the one I use with Make3D
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 24, 2011, 10:20:42 am
Yes, I think you're right.
I'll try to add this to my engine... Tomorrow.
Title: Re: [Lua] Tiny3D
Post by: Jim Bauwens on September 24, 2011, 11:36:10 am
Looks very nice, good job :)
Title: Re: [Lua] Tiny3D
Post by: Loulou 54 on September 24, 2011, 01:59:28 pm
Quote
but I have to train with 3D
lol %)

Great job indeed ! :)
Title: Re: [Lua] Tiny3D
Post by: mrmprog on September 24, 2011, 02:04:32 pm
Wow, that looks very good. 3d stuff on calc always amazes me.
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 25, 2011, 08:01:53 am
Quote
but I have to train with 3D
lol %)
Er... What's fun ?

__________________
Now my engine displays faces !

New code :
Spoiler For Spoiler:
Code: [Select]
function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2={}
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     table.insert(faces2,faces[j])
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e-5,zsum/#e}
   dist=math.sqrt(middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3])
  table.insert(distTbl,dist)
  table.insert(facesTbl,dist)
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function renderFaces(gc,vertices,faces,pos,mode)
 local polygon={}
 local faces2=sortFaces(vertices,faces)
 for i,e in pairs(faces2) do
  polygon={}
  for j,f in pairs(faces2[i]) do
   table.insert(polygon,pos[f][1])
   table.insert(polygon,pos[f][2])
  end
  table.insert(polygon,pos[faces2[i][1]][1])
  table.insert(polygon,pos[faces2[i][1]][2])
  if mode==4 or mode==5 then
   gc:setColorRGB(200,200,200)
   gc:fillPolygon(polygon)
  end
  if mode==2 or mode==3 or mode==4 then
   gc:setColorRGB(0,0,0)
   gc:drawPolyLine(polygon)
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

function render(gc,vertices,faces,mode)
 local ray,dist,nb,pos={},0,0,{}
 for i,e in pairs(vertices) do
  if e[2]<5 then
   ray={e[1],e[2]-5,e[3]}
    dist=math.sqrt(ray[1]*ray[1]+ray[2]*ray[2]+ray[3]*ray[3])
   nb=((dist*5)/(ray[2]))/dist
   table.insert(pos,{ray[1]*nb*25+width()/2,ray[3]*nb*25+height()/2})
  else
   table.insert(pos,false)
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if mode==2 or mode==3 or mode==4 or mode==5 then
  renderFaces(gc,vertices,faces,pos,mode)
 end
end
Title: Re: [Lua] Tiny3D
Post by: Loulou 54 on September 25, 2011, 10:20:33 am
Quote
but I have to train with 3D
lol %)
Er... What's fun ?
Indeed you've never made 3D.. x)
http://ourl.ca/12034
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 25, 2011, 11:29:33 am
:)

Actually, raycasting is not real 3D.
Moreover, I followed a tutorial to do my raycaster whereas I'm doing tiny3D without any help.

EDIT :
Now it's also possible to draw 3D function...
Title: Re: [Lua] Tiny3D
Post by: Adriweb on September 26, 2011, 01:57:34 pm
nice ! :D
Title: Re: [Lua] Tiny3D
Post by: Scipi on September 26, 2011, 02:23:46 pm
How do you use this library? Like, how should you store the data to render a 3D object?
Title: Re: [Lua] Tiny3D
Post by: Spyro543 on September 26, 2011, 02:27:33 pm
Heh, tesseract. Love it  :D
Title: Re: [Lua] Tiny3D
Post by: Levak on September 26, 2011, 02:32:51 pm
How do you use this library? Like, how should you store the data to render a 3D object?
Two ways I guess :
1) library, like I made for Make3D (http://ourl.ca/10565/243018)
2) Using its source code
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 26, 2011, 02:33:09 pm
For now, to render 3D object with tiny3D library, you have to send them to the render() function in the Lua code.
I've made a 3D-viewer in which you can modify vertices and faces with TI-Nspire-Basic. (You can also modify them with the spreadsheet application)
I'll release it soon...
Title: Re: [Lua] Tiny3D
Post by: Scipi on September 26, 2011, 04:02:13 pm
Well, what I meant was, I assume you send two tables to the render() function, one for vertices and one for edges. How are those tables formatted?

Suppose I had 8 points in space to make a cube:

[0,0,0][1,0,0][,1,1,0][0,1,0]
[0,0,1][1,0,1][,1,1,1][0,1,1]

How should that data look inside the tables that go to the render function?
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 27, 2011, 01:08:36 pm
New ! Color is supported (and some optimizations) ! I think that it's finished...
New code :
Spoiler For Spoiler:
Code: [Select]
--Lua Tiny3D - By Loic Pujet

function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2={}
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     table.insert(faces2,faces[j])
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e+5,zsum/#e}
   dist=math.sqrt(middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3])
  table.insert(distTbl,dist)
  table.insert(facesTbl,dist)
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function renderFaces(gc,vertices,faces,pos,mode,color)
 local polygon={}
 local faces2=sortFaces(vertices,faces)
 for i,e in pairs(faces2) do
  polygon={}
  drawPoly=true
  for j,f in pairs(faces2[i]) do
   if not pos[f] then
    drawPoly=false
   else
    table.insert(polygon,pos[f][1])
    table.insert(polygon,pos[f][2])
   end
  end
  if drawPoly then
   table.insert(polygon,pos[faces2[i][1]][1])
   table.insert(polygon,pos[faces2[i][1]][2])
   if mode==4 or mode==5 then
    gc:setColorRGB(color[1],color[2],color[3])
    gc:fillPolygon(polygon)
   end
   if mode==2 or mode==3 or mode==4 then
    gc:setColorRGB(0,0,0)
    gc:drawPolyLine(polygon)
   end
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

function render(gc,vertices,faces,mode,color)
 local yDist,pos=0,{}
 for i,e in pairs(vertices) do
  if e[2]>-5 then
   yDist=5/(e[2]+5)
   table.insert(pos,{e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25})
  else
   table.insert(pos,false)
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if mode==2 or mode==3 or mode==4 or mode==5 then
  renderFaces(gc,vertices,faces,pos,mode,color)
 end
end

HOMER-16 :
Here is how the (latest) function render works :
render(gc,vertices,faces,mode,color)
-gc is the graphic context (given in on.paint(gc))
-color is a table which contains RGB values
    ex : {200,200,200}
-mode :
    1 to render vertices only
    2 to render vertices and edges
    3 to render edges only
    4 to render edges and faces
    5 to render faces only
-vertices is a table which contains vertices pos
    ex : {{0,0,0},{1,1,1},{1,2,1},{0,1,2}}
-faces is a table which contains table of vertices.
    ex : {{1,2,3,4},{1,2,3}}

To render your cube, you should use
Code: [Select]
cubeVertices={{0,0,0},{1,0,0},{1,1,0},{0,1,0},{0,0,1},{1,0,1},{1,1,1},{0,1,1}}
cubeFaces={{1,2,3,4},{1,2,6,5},{2,3,7,6},{3,4,8,7},{4,1,5,8},{5,6,7,8}}
color={200,200,200}

function on.paint(gc)
 render(gc,cubeVertices,cubeFaces,4,color)
end
Title: Re: [Lua] Tiny3D
Post by: Scipi on September 27, 2011, 01:24:40 pm
Thank you! That helps alot :D
Title: Re: [Lua] Tiny3D
Post by: DJ Omnimaga on September 27, 2011, 01:55:26 pm
Looks nice Chokosta. I wonder if eventually it could be used for simple models in games like Space Dementia?
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 27, 2011, 02:21:09 pm
That's the point of this engine : games.
I'll try, and I will see if it's fast enough...
Title: Re: [Lua] Tiny3D
Post by: DJ Omnimaga on September 27, 2011, 02:30:26 pm
That's good to hear. I hope you don't have too much troubles with speed. :) I think Space Dementia ran at about 5 FPS and was very playable.
Title: Re: [Lua] Tiny3D
Post by: aeTIos on September 28, 2011, 09:53:24 am
:O
just :O
Title: Re: [Lua] Tiny3D
Post by: calc84maniac on September 28, 2011, 12:20:39 pm
On my Clickpad.
Which one is the slowest ?
The CX =)

Computer Software > ClickPad/TouchPad > CX
I thought CX was faster because it didn't have to do grayscale conversion. Or is that just for gc:drawImage()?
Title: Re: [Lua] Tiny3D
Post by: Levak on September 28, 2011, 12:40:55 pm
On my Clickpad.
Which one is the slowest ?
The CX =)

Computer Software > ClickPad/TouchPad > CX
I thought CX was faster because it didn't have to do grayscale conversion. Or is that just for gc:drawImage()?

I don't use drawImage() in Make3D and it is farly slower on the CX. With both Nspires rendering the same thing, the ClickPad goes faster to animate my default scene.
Title: Re: [Lua] Tiny3D
Post by: calc84maniac on September 28, 2011, 12:44:25 pm
On my Clickpad.
Which one is the slowest ?
The CX =)

Computer Software > ClickPad/TouchPad > CX
I thought CX was faster because it didn't have to do grayscale conversion. Or is that just for gc:drawImage()?

I don't use drawImage() in Make3D and it is farly slower on the CX. With both Nspires rendering the same thing, the ClickPad goes faster to animate my default scene.

Hmm, in that case it is probably related to the screen buffer copy which is 4 times as much data on the CX, and TI had a pretty darn unoptimized memcpy() the last time I checked.
Title: Re: [Lua] Tiny3D
Post by: Chockosta on September 30, 2011, 12:27:41 pm
New !
Mode 5 now has shading !
It can do beautiful things :)

And I've started a small game with that, it is fast enough to be fun. (see screenshots)

EDIT : Oops, forgot the code... Fixed.
Spoiler For Spoiler:
Code: [Select]
--Lua Tiny3D - By Loic Pujet

function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2={}
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     table.insert(faces2,faces[j])
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e+5,zsum/#e}
   dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3]
  distTbl[i]=dist
  facesTbl[i]=dist
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function chooseColor(gc,vertices,face,color)
 if #face<3 then
  gc:setColorRGB(color[1],color[2],color[3])
 else
  local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3]
  local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3]
  local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)}
  local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2])
  local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50
  R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B
  R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B
  gc:setColorRGB(R,G,B)
 end
end

function renderFaces(gc,vertices,faces,pos,mode,color)
 local polygon={}
 local faces2=sortFaces(vertices,faces)
 for i,e in pairs(faces2) do
  polygon={}
  drawPoly=true
  for j,f in pairs(faces2[i]) do
   if not pos[f] then
    drawPoly=false
   else
    table.insert(polygon,pos[f][1])
    table.insert(polygon,pos[f][2])
   end
  end
  if drawPoly then
   table.insert(polygon,pos[faces2[i][1]][1])
   table.insert(polygon,pos[faces2[i][1]][2])
   if mode==4 then
    gc:setColorRGB(color[1],color[2],color[3])
    gc:fillPolygon(polygon)
   elseif mode==5 then
    chooseColor(gc,vertices,e,color)
    gc:fillPolygon(polygon)
   end
   if mode==2 or mode==3 or mode==4 then
    gc:setColorRGB(0,0,0)
    gc:setPen("thin","smooth")
    gc:drawPolyLine(polygon)
   end
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

function render(gc,vertices,faces,mode,color)
 local yDist,pos=0,{}
 for i,e in pairs(vertices) do
  if e[2]>-5 then
   yDist=5/(e[2]+5)
   table.insert(pos,{e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25})
  else
   table.insert(pos,false)
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if mode==2 or mode==3 or mode==4 or mode==5 then
  renderFaces(gc,vertices,faces,pos,mode,color)
 end
end
Title: Re: [Lua] Tiny3D
Post by: Levak on September 30, 2011, 05:44:14 pm
Does your Shading mode use the crappy table.sort() I saw in previous versions ? or did you change it ?
I just wish to find what method you used to render that as fast as you say (I didn't tried yet, you just judges that it is fast :D).
Title: Re: [Lua] Tiny3D
Post by: Chockosta on October 01, 2011, 07:00:53 am
It does not... It only calculates the angle with the camera.
But to choose which polygon I draw first, I use table.sort(). Is that bad ?
And I don't say that it's fast, but it is fast enough to be playable...
(Actually It's just a bit faster than Make3D, so I think I could optimize)
Title: Re: [Lua] Tiny3D
Post by: Levak on October 01, 2011, 07:40:25 am
It does not... It only calculates the angle with the camera.
I wasn't talking about that, but I think I will look at it since I think Make3D uses an old and heavy method with face normal calculations.

Quote
But to choose which polygon I draw first, I use table.sort(). Is that bad ?
It depends on how table.sort() is implemented. We have to make benches about that :
 - insert element at it right place with table.insert(e, n) while computing it (mine)
 - compute elements, then table.sort(l, fun) (your)

Quote
And I don't say that it's fast, but it is fast enough to be playable...
(Actually It's just a bit faster than Make3D, so I think I could optimize)
Make3D really slows down in shading view when we reach the limit of 200 faces displayed. It comes really fast since a 15*15 grid is 225 points and about 200 faces.
This is why I was curious of what method you used without looking at your sources :D
Title: Re: [Lua] Tiny3D
Post by: Chockosta on October 01, 2011, 09:08:14 am
Let's try with 441 vertices and 400 faces...
 Video here  (http://www.youtube.com/watch?v=uDLrHEOw_4A)

Not really fast...
Title: Re: [Lua] Tiny3D
Post by: Levak on October 01, 2011, 10:32:11 am
line 49 : I think you'd better use

count = 0
...
for ...
 count = count + 1
 faces2[count] = faces[j]
end
...
table.setn(faces2, count)

instead of table.insert which is 7 times slower.

EDIT : it seems that table.setn is depreaciated. Just test that without it and only if #faces2 is egual to 0, use it.
Title: Re: [Lua] Tiny3D
Post by: Chockosta on October 01, 2011, 12:07:21 pm
I removed all table.insert()...
But the speed did not changed at all.
I think nSpire Lua doesn't work exactly like PC Lua.

However, here is the new code :
Spoiler For Spoiler:
Code: [Select]
--Lua Tiny3D - By Loic Pujet

function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2,count={},1
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     faces2[count]=faces[j]
     count=count+1
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e+5,zsum/#e}
   dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3]
  distTbl[i]=dist
  facesTbl[i]=dist
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function chooseColor(gc,vertices,face,color)
 if #face<3 then
  gc:setColorRGB(color[1],color[2],color[3])
 else
  local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3]
  local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3]
  local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)}
  local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2])
  local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50
  R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B
  R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B
  gc:setColorRGB(R,G,B)
 end
end

function renderFaces(gc,vertices,faces,pos,mode,color)
 local polygon,size={},0
 local faces2=sortFaces(vertices,faces)
 for i,e in pairs(faces2) do
  polygon,size={},0
  drawPoly=true
  for j,f in pairs(faces2[i]) do
   if not pos[f] then
    drawPoly=false
   else
    polygon[j*2-1]=pos[f][1]
    polygon[j*2]=pos[f][2]
    size=size+2
   end
  end
  if drawPoly then
   polygon[size+1]=pos[faces2[i][1]][1]
   polygon[size+2]=pos[faces2[i][1]][2]
   if mode==4 then
    gc:setColorRGB(color[1],color[2],color[3])
    gc:fillPolygon(polygon)
   elseif mode==5 then
    chooseColor(gc,vertices,e,color)
    gc:fillPolygon(polygon)
   end
   if mode==2 or mode==3 or mode==4 then
    gc:setColorRGB(0,0,0)
    gc:setPen("thin","smooth")
    gc:drawPolyLine(polygon)
   end
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

function render(gc,vertices,faces,mode,color)
 local yDist,pos=0,{}
 for i,e in pairs(vertices) do
  if e[2]>-5 then
   yDist=5/(e[2]+5)
   pos[i]={e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25}
  else
   pos[i]=false
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if #faces>0 and (mode==2 or mode==3 or mode==4 or mode==5) then
  renderFaces(gc,vertices,faces,pos,mode,color)
 end
end
Title: Re: [Lua] Tiny3D
Post by: Levak on October 01, 2011, 12:54:53 pm
Strange, really strange.
Title: Re: [Lua] Tiny3D
Post by: NecroBumpist on October 01, 2011, 02:07:19 pm
If you're looking to micro-optimize at this point, you might as well begin changing constants to locals as well.

Code: (Example) [Select]
-- Use this
local _1 = 1;

if val == _1 then
-- stuff
end

aTable[_1];

I have no idea how much this will improve speed, but it will. Remember to localize both string and number constants.

Oh, and you need to localize the math library functions instead of getting them from the math table all the time.
Title: Re: [Lua] Tiny3D
Post by: Levak on October 01, 2011, 03:05:30 pm
Oh, and you need to localize the math library functions instead of getting them from the math table all the time.

Really.
This page helped me a lot : http://trac.caspring.org/wiki/LuaPerformance
Title: Re: [Lua] Tiny3D
Post by: DJ Omnimaga on October 23, 2011, 08:29:16 pm
This looks nice though. if it was speed up, I wonder if a Star Fox clone could be made on the Nspire? Maybe a clone of Space Dementia 68K too :D
Title: Re: [Lua] Tiny3D
Post by: flyingfisch on October 23, 2011, 08:52:02 pm
is it ok if i try to make a luaFX/AFX version of this?
Title: Re: [Lua] Tiny3D
Post by: DJ Omnimaga on October 23, 2011, 10:05:50 pm
I bet there is no problem. Just ask Chokosta some permission if you plan to use the same code.

How fast is LuaFX?
Title: Re: [Lua] Tiny3D
Post by: flyingfisch on October 23, 2011, 10:20:24 pm
It's supposed to be almost/as fast as C. :o
Title: Re: [Lua] Tiny3D
Post by: Chockosta on October 24, 2011, 07:20:59 am
You sure can use my code...

Have fun ! :)
Title: Re: [Lua] Tiny3D
Post by: flyingfisch on October 24, 2011, 12:32:21 pm
Thank you!
Title: Re: [Lua] Tiny3D
Post by: Chockosta on December 03, 2011, 09:12:05 am
Hello !

I wrote a little 3D viewer with this engine.
You can draw :
- Cube
- Tetrahedron
- Pyramid
- Cone
- Torus
- Sphere
- Cylinder
- Hypercube (tesseract)

You also can draw 3D functions. (even if the OS already provides this)
You can choose the color, the zoom...

I just realised that I spent days to write this useless tool... :(
I really should create a new game.


DOWNLOAD (http://www.omnimaga.org/index.php?action=dlattach;topic=10581.0;attach=10681)
Title: Re: [Lua] Tiny3D
Post by: Nick on December 03, 2011, 09:51:35 am
i really want to lear how to put this engine into a game, can you maybe give a tuorial/readme file, cause i don't really get it xs

but it is really amazing, nice work!
Title: Re: [Lua] Tiny3D
Post by: Chockosta on December 03, 2011, 09:58:01 am
Okay, I'm writing a tutorial.
I'll post it soon.

EDIT : Finished ! It is attached to my post. (English isn't my first language, so maybe there are mistakes)
And here is the latest vesion of the engine.
Code: [Select]
--Lua Tiny3D - By Loic Pujet

function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2,count={},1
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     faces2[count]=faces[j]
     count=count+1
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e+5,zsum/#e}
   dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3]
  distTbl[i]=dist
  facesTbl[i]=dist
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function chooseColor(gc,vertices,face,color)
 if #face<3 then
  gc:setColorRGB(color[1],color[2],color[3])
 else
  local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3]
  local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3]
  local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)}
  local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2])
  local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50
  R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B
  R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B
  gc:setColorRGB(R,G,B)
 end
end

function renderFaces(gc,vertices,faces,pos,mode,color)
 local polygon,size,faces2={},0,{}
 if mode==4 or mode==5 or mode==6 then
  faces2=sortFaces(vertices,faces)
 else
  faces2=faces
 end
 for i,e in pairs(faces2) do
  polygon,size={},0
  drawPoly=true
  for j,f in pairs(faces2[i]) do
   if not pos[f] then
    drawPoly=false
   else
    polygon[j*2-1]=pos[f][1]
    polygon[j*2]=pos[f][2]
    size=size+2
   end
  end
  if drawPoly then
   polygon[size+1]=pos[faces2[i][1]][1]
   polygon[size+2]=pos[faces2[i][1]][2]
   if mode==4 then
    gc:setColorRGB(color[1],color[2],color[3])
    gc:fillPolygon(polygon)
   elseif mode==5 or mode==6 then
    chooseColor(gc,vertices,e,color)
    gc:fillPolygon(polygon)
   end
   if mode==2 or mode==3 or mode==4 or mode==5 then
    gc:setColorRGB(0,0,0)
    gc:setPen("thin","smooth")
    gc:drawPolyLine(polygon)
   end
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

function render(gc,vertices,faces,mode,color,offset)
 local yDist,pos=0,{}
 for i,e in pairs(vertices) do
  if e[2]>-offset then
   yDist=offset/(e[2]+offset)
   pos[i]={e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25}
  else
   pos[i]=false
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if #faces>0 and (mode==2 or mode==3 or mode==4 or mode==5 or mode==6) then
  renderFaces(gc,vertices,faces,pos,mode,color)
 end
end
Title: Re: [Lua] Tiny3D
Post by: Nick on December 03, 2011, 01:46:56 pm
thanks, i'll certainly give it a try, as soon i finished my other projects :)
the tutorial looks great, simple, but straight forward! that's how tutorials have to be, good job!

so if i understand everything good, i just have to paste your engine-code below my code?
Title: Re: [Lua] Tiny3D
Post by: Chockosta on December 03, 2011, 04:49:55 pm
Yes :)

Nice to see that someone use it !
Title: Re: [Lua] Tiny3D
Post by: renatose on December 03, 2011, 07:21:36 pm
I just realised that I spent days to write this useless tool... :(

This is not useless, this can be made more powerful that the OS 3D graphing. Can you make it accept any functions? i.e. to insert x^2+y^2+z^2=2^2 which is an origin centered radius 2 sphere in the OS 3d graphing I've got to solve it in order to z before writing that which results in 2 equations: z(x,y)=sqrt(2^2-x^2-y^2) and z(x,y)=sqrt(2^2-x^2-y^2)
it would be nice if your Tiny3D accepted any function to draw.
Title: Re: [Lua] Tiny3D
Post by: DJ Omnimaga on December 03, 2011, 11:41:57 pm
This looks nice. You should post a tns demo so we can see how fast it is. :D I wonder if it could be fast enough for simple games like Star fox? I'm glad you're still working on this by the way. :D

EDIT: Nvm I didn't see the zip file above the screenshots. Gonna try it soon.
Title: Re: [Lua] Tiny3D
Post by: Chockosta on December 04, 2011, 08:09:57 am
I just realised that I spent days to write this useless tool... :(

This is not useless, this can be made more powerful that the OS 3D graphing. Can you make it accept any functions? i.e. to insert x^2+y^2+z^2=2^2 which is an origin centered radius 2 sphere in the OS 3d graphing I've got to solve it in order to z before writing that which results in 2 equations: z(x,y)=sqrt(2^2-x^2-y^2) and z(x,y)=sqrt(2^2-x^2-y^2)
it would be nice if your Tiny3D accepted any function to draw.

Actually my function drawer is really basic. It only draw one function, which has to be like z(x,y)=...
I could write another one to allow that.

This looks nice. You should post a tns demo so we can see how fast it is. :D I wonder if it could be fast enough for simple games like Star fox? I'm glad you're still working on this by the way. :D

EDIT: Nvm I didn't see the zip file above the screenshots. Gonna try it soon.
I'm not sure that it's possible, but I'll try. The main problem is the key input...
Title: Re: [Lua] Tiny3D
Post by: Nick on December 04, 2011, 08:14:48 am
i hate that key input with lua, soooo slow.. and it doesn't even support a keep-op-pressing function (only arrows) that's so stupid
Title: Re: [Lua] Tiny3D
Post by: Chockosta on December 04, 2011, 08:29:08 am
Actually, the space key and delete key also repeat, but I agree with you.



BTW, a very small update, with a little bugfix.
With very high values for the offset, the faces did not display right. It is now fixed.

Code: [Select]
--Lua Tiny3D - By Loic Pujet

function multiplyMatrix(matrix,vector)
 local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3]
 local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3]
 local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3]
 return x,y,z
end

function width() return platform.window:width() end
function height() return platform.window:height() end

function reverseTable(tbl)
 local tbl2={}
 for i,e in ipairs(tbl) do
  tbl2[#tbl-i+1]=e
 end
 return tbl2
end

function replaceFaces(tbl1,tbl2,faces)
 local faces2,count={},1
 for i,e in pairs(tbl1) do
  for j,e2 in pairs(tbl2) do
   if e2 then
    if e==e2 then
     faces2[count]=faces[j]
     count=count+1
     tbl2[j]=nil
    end
   end
  end
 end
 return reverseTable(faces2)
end

function sortFaces(vertices,faces,offset)
 local faces2,distTbl,facesTbl={},{},{}
 local middle={}
 local dist,xsum,ysum,zsum=0,0,0,0
 for i,e in pairs(faces) do
  xsum,ysum,zsum=0,0,0,0
  for j,e2 in pairs(e) do
   xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3]
  end
  middle={xsum/#e,ysum/#e+offset,zsum/#e}
   dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3]
  distTbl[i]=dist
  facesTbl[i]=dist
 end
 table.sort(distTbl)
 return replaceFaces(distTbl,facesTbl,faces)
end

function chooseColor(gc,vertices,face,color)
 if #face<3 then
  gc:setColorRGB(color[1],color[2],color[3])
 else
  local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3]
  local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3]
  local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)}
  local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2])
  local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50
  R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B
  R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B
  gc:setColorRGB(R,G,B)
 end
end

function renderFaces(gc,vertices,faces,pos,mode,color,offset)
 local polygon,size,faces2={},0,{}
 if mode==4 or mode==5 or mode==6 then
  faces2=sortFaces(vertices,faces,offset)
 else
  faces2=faces
 end
 for i,e in pairs(faces2) do
  polygon,size={},0
  drawPoly=true
  for j,f in pairs(faces2[i]) do
   if not pos[f] then
    drawPoly=false
   else
    polygon[j*2-1]=pos[f][1]
    polygon[j*2]=pos[f][2]
    size=size+2
   end
  end
  if drawPoly then
   polygon[size+1]=pos[faces2[i][1]][1]
   polygon[size+2]=pos[faces2[i][1]][2]
   if mode==4 then
    gc:setColorRGB(color[1],color[2],color[3])
    gc:fillPolygon(polygon)
   elseif mode==5 or mode==6 then
    chooseColor(gc,vertices,e,color)
    gc:fillPolygon(polygon)
   end
   if mode==2 or mode==3 or mode==4 or mode==5 then
    gc:setColorRGB(0,0,0)
    gc:setPen("thin","smooth")
    gc:drawPolyLine(polygon)
   end
  end
 end
end

function renderVertices(gc,pos)
 gc:setColorRGB(0,0,0)
 for i,e in pairs(pos) do
  if e then
   gc:fillRect(e[1]-1,e[2]-1,3,3)
  end
 end
end

----------------------------------------------------------------------------

function rotate(vertices,angle,x,y,z)
 local sum=x+y+z
 x,y,z=x/sum,y/sum,z/sum
 local c,s=math.cos(angle),math.sin(angle)
 local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}}
 for i,e in pairs(vertices) do
  vertices[i]={multiplyMatrix(matrix,e)}
 end
end

function translate(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]+x,e[2]+y,e[3]+z}
 end
end

function scale(vertices,x,y,z)
 for i,e in pairs(vertices) do
  vertices[i]={e[1]*x,e[2]*y,e[3]*z}
 end
end

function render(gc,vertices,faces,mode,color,offset)
 local yDist,pos=0,{}
 for i,e in pairs(vertices) do
  if e[2]>-offset then
   yDist=offset/(e[2]+offset)
   pos[i]={e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25}
  else
   pos[i]=false
  end
 end
 if mode==1 or mode==2 then
  renderVertices(gc,pos)
 end
 if #faces>0 and (mode==2 or mode==3 or mode==4 or mode==5 or mode==6) then
  renderFaces(gc,vertices,faces,pos,mode,color,offset)
 end
end

----------------------------------------------------------------------------
Title: Re: [Lua] Tiny3D
Post by: Jim Bauwens on December 04, 2011, 10:29:01 am
And the tab key repeats :)
Title: Re: [Lua] Tiny3D
Post by: DJ Omnimaga on December 25, 2011, 10:30:25 pm
Another issue is it seems multi-keypress is lacking, but I could be wrong. I just haven't seen any game using them in Lua.