TylerH Posted December 20, 2009 Share Posted December 20, 2009 I have been trying to adapt the code Josh used in road_node.lua to create the roads aligned to terrains, in order to work on a per-entity individual basis for terrain-aligned decals. I stripped it down to how I think it should work, and made a few modifications, but nothing is visible. I was hoping someone (preferably Josh or anyone who knows how this may work), to take a look and see if they can either get it working, or tell me what in practice I am doing wrong. Here is the decal.lua script: dofile("Scripts/base.lua") dofile("Scripts/Math.lua") dofile("Scripts/Primitives/Patch.lua") dofile("Scripts/Math/Plane.lua") dofile("Scripts/linkedlist.lua") --Properties interface function InitDialog(grid) base_InitDialog(grid) end --Helper function to retrieve the scene terrain, if it exists function GetTerrain() for terrain in iterate(CurrentWorld().terrains) do return terrain end end function Spawn(model) local entity=base_Spawn(model) --Default settings entity.model:SetKey("width","5") entity.model:SetKey("border","0.25") entity.model:SetKey("tessellation","1.0") entity.model:SetKey("offset","0.05") entity.model:SetKey("material","road.mat") entity.model:SetKey("linkoncreate","1") entity.model:SetKey("reloadafterscript","0") entity.roadmesh=CreateMesh(nil) material=LoadMaterial("abstract::"..entity.model:GetKey("material")) entity.roadmesh:Paint(material,0) local surf=entity.roadmesh:AddSurface(material) entity.roadsurface=surf entity.roadsurface:Paint(material,0) entity.roadmesh:SetParent(entity.model,1) entity.roadmesh:SetShadowMode(0) function entity:BuildSegment() --Create a temporary mesh and add a surface local temp=CreateMesh() local x0,x1,z0,z1,cx,cz,w,d local terrain=GetTerrain() local meterspertile=2.0 if terrain~=nil then meterspertile=terrain.scale.x end cx=1.0 cz=1.0 w=2.0 d=2.0 --Now create a patch; this is a segmented plane that will match the terrain tiles patch=CreatePatch(w,d) local patchsurf=patch:GetSurface(1) patchsurf:Scale(Vec3(meterspertile*w,1.0,meterspertile*d)) patchsurf:Translate(Vec3(cx-w/meterspertile,0,cz-d/meterspertile)) --Make y coordinates of patch match terrain if terrain~=nil then for v=0,patchsurf:CountVertices()-1 do local t=patchsurf:GetVertexPosition(v) local px,pz px = t.x/meterspertile+terrain.resolution/meterspertile pz = t.z/meterspertile+terrain.resolution/meterspertile t.y = terrain:GetHeight(px,pz)*terrain.scale.y+0.005 patchsurf:SetVertexPosition(v,t) end end patch:SetParent(self.model,1) local a,b,c,p,d local src=patch:GetSurface(1) local dst=temp:AddSurface() --UV map the finished surface. This was hard!!! a=patchsurf:GetVertexPosition(0) b=patchsurf:GetVertexPosition(1) c=patchsurf:GetVertexPosition(2) d=patchsurf:GetVertexPosition(3) local texcoord = Vec2() local u = Vec3() local v = Vec3() local p0=Vec2() local p1=Vec2() local result0=0 local result1=0 local a00 local a01 local a10 local a11 local texcoord=Vec2(0) --Calculate the intersection of the top and bottom edges result0,p0.x,p0.y=linesintersect(a.x,a.z,b.x,b.z,c.x,c.z,d.x,d.z) if result0==1 then a00=math.atan2(a.z-p0.y,a.x-p0.x) a01=math.atan2(c.z-p0.y,c.x-p0.x) a00=WrapAngle(math.deg(a00)) a01=WrapAngle(math.deg(a01)) da0=angledifference(a00,a01) end --Calculate the intersection of the left and right edges result1,p1.x,p1.y=linesintersect(a.x,a.z,c.x,c.z,b.x,b.z,d.x,d.z) if result1==1 then a10=math.atan2(a.z-p1.y,a.x-p1.x) a11=math.atan2(b.z-p1.y,b.x-p1.x) a10=WrapAngle(math.deg(a10)) a11=WrapAngle(math.deg(a11)) da1=angledifference(a10,a11) end --Now calculate texcoords and add normals for n=0,dst:CountVertices()-1 do t=dst:GetVertexPosition(n) local yfactor=0 if result0==1 then angle=math.deg(math.atan2(t.z-p0.y,t.x-p0.x)) yfactor = angledifference(angle,a00)/da0 --yfactor = math.mod(angledifference(angle,a00)/da0,1.0) --yfactor=1.0+yfactor --texcoord.y = (i+yfactor) / self.countsegments*1.0 texcoord.y=yfactor else u=Vec3() u.x = c.x-a.x u.y = c.y-a.y u.z = c.z-a.z u=planefrompointnormal(a,Normalize(u)) dist=PointDistance(a,c) u.nx=u.nx/dist u.ny=u.ny/dist u.nz=u.nz/dist u.d=u.d/dist texcoord.y=((u.nx*t.x+u.ny*t.y+u.nz*t.z+u.d)) --texcoord.y=1.0+texcoord.y --texcoord.y = (i+texcoord.y) / self.countsegments*1.0 --if texcoord.y<0.0 then texcoord.y=1.0+texcoord.y end --texcoord.y = texcoord.y + i end if result1==1 then angle=math.deg(math.atan2(t.z-p1.y,t.x-p1.x)) texcoord.x = 1.0+angledifference(angle,a10)/da1 else u=Vec3() u.x = b.x-a.x u.y = b.y-a.y u.z = b.z-a.z u=planefrompointnormal(a,Normalize(u)) dist=PointDistance(a,B) u.nx=u.nx/dist u.ny=u.ny/dist u.nz=u.nz/dist u.d=u.d/dist texcoord.x=u.nx*t.x+u.ny*t.y+u.nz*t.z+u.d end dst:SetVertexTexCoords(n,texcoord,0) if terrain~=nil then dst:SetVertexNormal(n,terrain:CalcNormal(t.x,t.z)) else dst:SetVertexNormal(n,Vec3(0,1,0)) end end --Add the temporary surface to the real road surface dst:Add(entity.roadsurface) --Discard the temporary meshes patch:Free() temp:Free() end return entity end function SetKey(model,key,value) local entity=entitytable[model] if entity==nil then return 1 end if key=="material" then if entity.roadmesh then material=LoadMaterial("abstract::"..value) entity.roadmesh:Paint(material,0) end end return 1 end function GetKey(model,key,value) local entity=entitytable[model] if entity==nil then return value end if key=="material" then return value else return base_GetKey(model,key,value) end end function Kill(model) local entity=entitytable[model] base_Kill(model) end function UpdateMatrix(model) local entity=entitytable[model] if (entity ~= nil) then entity:BuildSegment() entity.roadsurface:UpdateTangentsAndBinormals() entity.roadmesh:UpdateLocalAABB() entity.roadmesh:UpdateAABB() end end Thanks, Tyler Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
macklebee Posted December 20, 2009 Share Posted December 20, 2009 might be difficult for anyone to test since this is the "old" way 2.3 script functions were named... if i get a chance i will unzip my "old" version and take a look... any chance you could answer this post? Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
Rick Posted December 20, 2009 Share Posted December 20, 2009 ??, I would first say you are using the old way with multiple lua states. Look at the template.lua in the Scripts dir to see how the new way is structured with the new single lua state. Quote Link to comment Share on other sites More sharing options...
TylerH Posted December 20, 2009 Author Share Posted December 20, 2009 I am not switching to the single-state 2.3 until I am comfortable with and fix all current bugs with the entities I have created in multi-state. I don't want to switch to single-state with pre-existing bugs in my code at present, because then any bugs from single-state will be hard to differentiate from the existing ones. Over the next 2-3 days I will upgrade, but in the mean time can you just bear with me here? Don't act like you are incapable of making it compatible if you need it that way. Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
macklebee Posted December 20, 2009 Share Posted December 20, 2009 ??, I would first say you are using the old way with multiple lua states. Look at the template.lua in the Scripts dir to see how the new way is structured with the new single lua state. thats just it... he is still using multi-state. Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
TylerH Posted December 20, 2009 Author Share Posted December 20, 2009 Ninja'd B) Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
macklebee Posted December 20, 2009 Share Posted December 20, 2009 Ninja'd B) Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
Rick Posted December 20, 2009 Share Posted December 20, 2009 Don't act like you are incapable of making it compatible if you need it that way. I don't know if you mean it this way or not but sometimes your posts come off as you being very rude. I was not aware you didn't upgrade to the new system. I see now from a different post you made that you haven't. If I find time away from my 3rd person entity I'll see if I can't see what's wrong. Quote Link to comment Share on other sites More sharing options...
TylerH Posted December 20, 2009 Author Share Posted December 20, 2009 Sorry, it was meant to be taken lightly. Really hard to commit emotion and tone via the Internet and Text, so I should have added a B) or smiley. I'm not aware how different the new system is, so I was assuming the change-over was either minuscule or 1:1, if it is difficult I will see if I can do it myself so others can test. Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
TylerH Posted December 20, 2009 Author Share Posted December 20, 2009 might be difficult for anyone to test since this is the "old" way 2.3 script functions were named... if i get a chance i will unzip my "old" version and take a look... any chance you could answer this post? Replied to the post in that other thread and posted my decal material file. Cheers, Tyler Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
macklebee Posted December 20, 2009 Share Posted December 20, 2009 tyler, I think you edited too much... you do not appear to be creating a mesh/surface anywhere for you to be able to paint a material. I haven't looked at the code too much yet, but just looking at how the road nodes work in the editor with the grid off, skybox set to a solid color, and wireframe on, i can see the mesh plane? being created between two points... your code shows a link but no mesh/surface being created... Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
TylerH Posted December 21, 2009 Author Share Posted December 21, 2009 It is all good. I created a new entity from scratch in the single-state 2.3 Editor, and got everything working great. I just need to setup UV coordinates, grab a material for a cool terrain decal, place some, and grab some screenshots. Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
TylerH Posted December 21, 2009 Author Share Posted December 21, 2009 Here is the working code. I need to figure out how to calculate the UV Coords properly, and scale the entire system down so the patch can be much smaller (for small decals, ofcourse B)) require("Scripts/class") require("Scripts/Math/math") require("Scripts/Primitives/Patch") require("Scripts/Math/Plane") require("Scripts/linkedlist") require("Scripts/hooks") require("Scripts/loop") local class=CreateClass(...) function class:GetTerrain(world) local terrain for terrain in iterate(world.terrains) do return terrain end end function class:InitDialog(grid) self.super:InitDialog(grid) end function class:CreateObject(model) local object=self.super:CreateObject(model) function object:CreateTerrainAlignedPatch() if (object.patch ~= nil) then object.patch:Free() end local terrain = self.class:GetTerrain(self.model.world) local meterspertile=2.0 if terrain~=nil then self.terrain = terrain meterspertile=terrain.scale.x end local pos = self.model.position if meterspertile==1 then --[[x0=math.floor(self.model.aabb.x0) x1=math.ceil(self.model.aabb.x1) z0=math.floor(self.model.aabb.z0) z1=math.ceil(self.model.aabb.z1)]] x0=math.floor(pos.x)-1 x1=math.ceil(pos.x)+1 z0=math.floor(pos.z)-1 z1=math.ceil(pos.z)+1 cx=x0 cz=z0 w=x1-x0 d=z1-z0 patch=CreatePatch(w,d) patchsurf=patch:GetSurface(1) patchsurf:Scale(Vec3(w,1.0,d)) patchsurf:Translate(Vec3(x0,0,z0)) else --[[x0=math.floor(self.model.aabb.x0/meterspertile)*meterspertile x1=math.ceil(self.model.aabb.x1/meterspertile)*meterspertile z0=math.floor(self.model.aabb.z0/meterspertile)*meterspertile z1=math.ceil(self.model.aabb.z1/meterspertile)*meterspertile]] x0=math.floor((pos.x-1)/meterspertile)*meterspertile x1=math.ceil((pos.x+1)/meterspertile)*meterspertile z0=math.floor((pos.z-1)/meterspertile)*meterspertile z1=math.ceil((pos.z+1)/meterspertile)*meterspertile cx=x0 cz=z0 w=x1-x0 d=z1-z0 patch=CreatePatch(w,d) patchsurf=patch:GetSurface(1) patchsurf:Scale(Vec3(meterspertile*w,1.0,meterspertile*d)) patchsurf:Translate(Vec3((cx-Round(w/meterspertile/meterspertile)*meterspertile),0,(cz-Round(d/meterspertile/meterspertile)*meterspertile))) end if terrain~=nil then for v=0,patchsurf:CountVertices()-1 do local t=patchsurf:GetVertexPosition(v) local px,pz px = t.x/meterspertile+terrain.resolution/2.0 pz = t.z/meterspertile+terrain.resolution/2.0 t.y = terrain:GetHeight(px,pz)*terrain.scale.y+0.01 patchsurf:SetVertexPosition(v,t) end end patch:UpdateLocalAABB() patch:UpdateAABB() --calculate texcoords/normals for n=0,patchsurf:CountVertices()-1 do t=patchsurf:GetVertexPosition(n) if terrain~=nil then patchsurf:SetVertexNormal(n,terrain:CalcNormal(t.x,t.z)) else patchsurf:SetVertexNormal(n,Vec3(0,1,0)) end end patchsurf:UpdateTangentsAndBinormals() if (self.material ~= nil) then patch:Paint(self.material,0) end patch:SetParent(self.model,1) self.patch = patch end function object:UnlockKeys() self.super:UnlockKeys() end function object:SetKey(key,value) if key=="material" then self.materialname = value self.material = LoadMaterial("abstract::"..value) if (self.patch ~= nil) then self.patch:Paint(self.material,0) end else return self.super:SetKey(key,value) end end function object:GetKey(key,value) if key=="material" then return self.materialname else return self.super:GetKey(key,value) end end function object:SetTarget(target,index) end function object:UpdateMatrix() self:CreateTerrainAlignedPatch() end function object:ReceiveMessage(message,extra) self.super:ReceiveMessage(message,extra) end function object:Free(model) self.super:Free() end object:CreateTerrainAlignedPatch() end function class:Free() self.super:Free() end Images are in the gallery. Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
Michael Betke Posted December 21, 2009 Share Posted December 21, 2009 Nice, I'll try it out at home. Quote Pure3d Visualizations Germany - digital essences AAA 3D Model Shop specialized on nature and environments Link to comment Share on other sites More sharing options...
TylerH Posted December 21, 2009 Author Share Posted December 21, 2009 Here is the newest version. This supports just about everything I want, except the vertices are not UV Mapped, so materials do not appear properly. It supports customizable aperture (like radius, but in geometry terms for square), tessellation (if you have a larger sized decal, you may need to increase tessellation, otherwise you will experience issues with the decal aligning to the terrain). The terrain alignment code now also uses TerrainElevation as opposed to TerrainHeight, so the decal can be smaller than a terrain tile and still be aligned relatively accurately. Ofcourse someone may come along and find an even better approahc to align the decal to the terrain, so I applaud everyone who wishes to improve this. Things that need done before this is usable: 1) UV Coordinates Code: require("Scripts/class") require("Scripts/Math/math") require("Scripts/Primitives/Patch") require("Scripts/Math/Plane") require("Scripts/linkedlist") local class=CreateClass(...) function class:GetTerrain(world) local terrain for terrain in iterate(world.terrains) do return terrain end end function class:InitDialog(grid) self.super:InitDialog(grid) group=grid:AddGroup("Terrain Decal") group:AddProperty("aperture",PROPERTY_FLOAT,"0.5,10,1","Aperture") group:AddProperty("tessellation",PROPERTY_FLOAT,"1,10,0","Tessellation") group:Expand(1) end function class:CreateObject(model) local object=self.super:CreateObject(model) function object:CreateTerrainAlignedPatch() if (object.patch ~= nil) then object.patch:Free() end local terrain = self.class:GetTerrain(self.model.world) local meterspertile=2.0 if terrain~=nil then self.terrain = terrain meterspertile=terrain.scale.x end local pos = self.model.position cx = pos.x - (self.aperture/2) cz = pos.z - (self.aperture/2) w = 1.0 d = 1.0 patch=CreatePatch(w*self.tessellation,d*self.tessellation) patchsurf=patch:GetSurface(1) patchsurf:Scale(Vec3(meterspertile*w*self.aperture,1.0,meterspertile*d*self.aperture)) patchsurf:Translate(Vec3((cx-Round(w/meterspertile/meterspertile)*meterspertile),0,(cz-Round(d/meterspertile/meterspertile)*meterspertile))) --end if terrain~=nil then for v=0,patchsurf:CountVertices()-1 do local t=patchsurf:GetVertexPosition(v) t.y = TerrainElevation(terrain,t.x,t.z)+0.025--*terrain.scale.y+0.01 patchsurf:SetVertexPosition(v,t) end end patch:UpdateLocalAABB() patch:UpdateAABB() --calculate texcoords/normals for n=0,patchsurf:CountVertices()-1 do t=patchsurf:GetVertexPosition(n) if terrain~=nil then patchsurf:SetVertexNormal(n,terrain:CalcNormal(t.x,t.z)) else patchsurf:SetVertexNormal(n,Vec3(0,1,0)) end end patchsurf:UpdateTangentsAndBinormals() if (self.material ~= nil) then patch:Paint(self.material,0) end patch:SetParent(self.model,1) self.patch = patch end function object:UnlockKeys() self.super:UnlockKeys() end function object:SetKey(key,value) if key=="material" then self.materialname = value self.material = LoadMaterial("abstract::"..value) if (self.patch ~= nil) then self.patch:Paint(self.material,0) end elseif key=="aperture" then self.aperture = tonumber(value) self:CreateTerrainAlignedPatch() elseif key=="tessellation" then self.tessellation = tonumber(value) self:CreateTerrainAlignedPatch() else return self.super:SetKey(key,value) end end function object:GetKey(key,value) if key=="material" then return self.materialname elseif key=="aperture" then return self.aperture elseif key=="tessellation" then return self.tessellation else return self.super:GetKey(key,value) end end function object:SetTarget(target,index) end function object:UpdateMatrix() self:CreateTerrainAlignedPatch() end function object:ReceiveMessage(message,extra) self.super:ReceiveMessage(message,extra) end function object:Free(model) self.super:Free() end object.aperture = 0.5 object.tessellation = 1.0 object:CreateTerrainAlignedPatch() end function class:Free() self.super:Free() end Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
macklebee Posted December 21, 2009 Share Posted December 21, 2009 pretty slick so far i see you caved in and moved to single state welcome to the headache! Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
TylerH Posted December 21, 2009 Author Share Posted December 21, 2009 xD. No headaches so far, other than the one from my cold + sinus congestion. I actually found it easier, since I can bypass the entity key system and just set values directly to the Lua object (see SetKey and GetKey for material, aperture, and tessellation ) Quote nVidia 530M Intel Core i7 - 2.3Ghz 8GB DDR3 RAM Windows 7 Ultimate (64x)----- Visual Studio 2010 Ultimate Google Chrome Creative Suite 5 FL Studio 10 Office 15 ----- Expert Professional Expert BMX Programmer ----- Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.