Jump to content

reepblue

Developers
  • Posts

    2,503
  • Joined

  • Last visited

Everything posted by reepblue

  1. I noticed that the SlidingDoor.lua script from the Leadwerks 3.0 demo was a tad different from the current stock one. After fixing the Joint:Slider call, I've noticed that doors reset to the exact position it was when it is closed. You can try it for yourself, I've modified the script to have the loop sound, and release everything properly. There might be a good reason why it was changed with 3.1, but I've found it to be more reliable. The door will also not collapse if a lot of heavy objects are on top of it if you're using it as a lift. import "Scripts/Functions/ReleaseTableObjects.lua" Script.enabled=true--bool "Enabled" Script.openstate=false--bool "Start Open" Script.offset=Vec3(0)--Vec3 "Offset" Script.movespeed=1--float "Move speed" 0,100,3 Script.opensoundfile=""--path "Open Sound" "Wav File (*wav):wav|Sound" Script.closesoundfile=""--path "Close Sound" "Wav File (*wav):wav|Sound" Script.loopsoundfile=""--path "Loop Sound" "Wav File (*wav):wav|Sound" Script.manualactivation=false--bool "Manual activate" Script.closedelay=2000--int "Close delay" function Script:Start() self.entity:SetGravityMode(false) if self.entity:GetMass()==0 then Debug:Error("Entity mass must be greater than 0.") end self.sound={} if self.opensoundfile~="" then self.sound.open = Sound:Load(self.opensoundfile) end if self.loopsoundfile~="" then self.sound.loop = Sound:Load(self.loopsoundfile) end if self.closesoundfile~="" then self.sound.close = Sound:Load(self.closesoundfile) end if self.sound.loop~=nil then self.loopsource = Source:Create() self.loopsource:SetSound(self.sound.loop) self.loopsource:SetLoopMode(true) self.loopsource:SetRange(50) end if self.manualactivation==false then self.Use=nil end self.opentime=0 if self.openstate then self.openposition=self.entity:GetPosition(true) self.closedposition=self.openposition+self.offset self.desiredposition=Vec3(self.openposition.x,self.openposition.y,self.openposition.z) else self.closedposition=self.entity:GetPosition(true) self.openposition=self.closedposition+self.offset self.desiredposition=Vec3(self.closedposition.x,self.closedposition.y,self.closedposition.z) end if self.openstate then self.openangle=0 self.closedangle=self.offset:Length() else self.openangle=self.offset:Length() self.closedangle=0 end local pin=self.offset:Normalize() self.base=Pivot:Create() self.base:SetPosition(self.closedposition) self.joint = Joint:Slider(self.closedposition.x,self.closedposition.y,self.closedposition.z,pin.x,pin.y,pin.z, self.entity,self.base) self.joint:EnableLimits() self.joint:SetLimits(0,self.offset:Length()) end function Script:Use() self:Toggle() end function Script:Toggle()--in if self.enabled then if self.openstate then self:Close() else self:Open() end end end function Script:Open()--in if self.enabled then self.opentime = Time:GetCurrent() if self.openstate==false then self.openstate=true if self.opensound then self.entity:EmitSound(self.opensound) end self.component:CallOutputs("Open") if self.loopsource~=nil then self.loopsource:SetPosition(self.entity:GetPosition(true)) if self.loopsource:GetState()==Source.Stopped then self.loopsource:Play() end end end end end function Script:Close()--in if self.enabled then if self.openstate then if self.closesound then self.entity:EmitSound(self.closesound) end self.openstate=false self.component:CallOutputs("Close") if self.loopsource~=nil then self.loopsource:SetPosition(self.entity:GetPosition(true)) if self.loopsource:GetState()==Source.Stopped then self.loopsource:Play() end end end end end function Script:Disable()--in self.enabled=false end function Script:Enable()--in self.enabled=true end function Script:UpdatePhysics() --Disable loop sound if self.sound.loop~=nil then local angle if self.openstate then angle = self.openangle else angle = self.closedangle end if math.abs(self.joint:GetAngle()-angle)<0.1 then if self.loopsource:GetState()~=Source.Stopped then self.loopsource:Stop() end else if self.loopsource:GetState()==Source.Stopped then self.loopsource:Resume() end end if self.loopsource:GetState()==Source.Playing then self.loopsource:SetPosition(self.entity:GetPosition(true)) end end if self.openstate then if self.closedelay>0 then local time = Time:GetCurrent() if time-self.opentime>self.closedelay then self:Close() end end end --Figure out where the door should be local diff if self.openstate then diff = self.openposition - self.desiredposition else diff = self.closedposition - self.desiredposition end local l = diff:Length() if l>self.movespeed/60 then diff = diff:Normalize() * self.movespeed/60 end self.desiredposition = self.desiredposition + diff --Find the difference between where we want the door to be, and where it is diff = self.desiredposition - self.entity:GetPosition() --If the difference is more than a tiny bit, use physics to add forces to make it go where we want if diff:Length()>0.01 then self.entity:PhysicsSetPosition(self.desiredposition.x,self.desiredposition.y,self.desiredposition.z) return end end function Script:Release() ReleaseTableObjects(self.sound) if self.loopsource then self.loopsource:Release() self.loopsource=nil end self.sound=nil self.base:Release() self.base=nil end
  2. Works like: void MapHook(Entity* entity, Object* extra) { LoadingScreen(); } void Changemap(std::string map) { Map::Load(map, &MapHook) } Sill works, this is what I use. Not as dynamic as Lua I've found.
  3. Great work! I really like how it makes a material pop out more.
  4. But we're making video games, not real life! As in, yes, the default settings is correct, but there may be cases where we'd need to cheat realism to get a desired look or effect. It's really case by case of what looks best for what you're going after. But glad to see a new blend mode will be coming soon. (If I've read right.)
  5. Blend::Lighten confirmed? I mean I get that this is for the probes, but that screen shot of the spots looks way better how spotlights are handled now. Really great!
  6. I personally have a feeling that this will sell better as DLC.
  7. Bout time! I've went to the post to see what they've said, but I figure it was a PM/E-mail as nothing else was posted. I still like the idea of turning multi-sampling completely off personally, but I understand that this is getting real messy, real fast. However, you're already knee deep in this process...
  8. Hey all, I decided for fun to sync up the Vectronic Demo with the latest version. I also wanted to see how the game looked with multi sampling off. when I booted up the game however, it lacked fog. No big deal I thought, I'll just use the #if SAMPLES==0 statements like the light shaders do, and make ms textures 2d textures. I did just that, and it works.... Only if SAMPLES==0 and MSAA is set to 0 as well. I'm curious why there isn't an automatic system in the shader system to detect if MSAA is 0. (I thought #if SAMPLES==0 was it.) I've looked at the decals and they use an int that's most likely toggled under the hood. How would I do this with any Post Process effects that are loaded? In the PBR code, there was a way to toggle an int value, but could I just load the shader and toggle it, or do I need to fetch the active camera, get the shaders of the post processing effects, and do it that way? Perhaps a global sampling value would be nice here so other users don't collide with this issue while making/updating shaders. Maybe actually Set SAMPLES to 0 when Multisampling is 0? This might be more of a request more than anything. Thanks. Oh, for those who want the semi-fix, here: _passthrough.shader (Frag) #version 400 #ifndef SAMPLES #define SAMPLES 1 #endif uniform bool isbackbuffer; uniform vec2 buffersize; uniform vec2 camerarange; uniform float currenttime; out vec4 fragData0; uniform sampler2D texture1; #if SAMPLES==0 uniform sampler2DMS texture2; uniform sampler2DMS texture3; #else uniform sampler2D texture2; uniform sampler2D texture3; #endif void main() { vec2 icoord = vec2(gl_FragCoord.xy/buffersize); if (isbackbuffer) icoord.y = 1.0 - icoord.y; vec4 color = texture(texture1,icoord); fragData0=color; } _klepto_fog.shader (Frag) #version 400 #ifndef SAMPLES #define SAMPLES 1 #endif uniform sampler2D texture1; uniform samplerCube texture2; #if SAMPLES==0 uniform sampler2D texture3; #else uniform sampler2DMS texture3; #endif uniform bool isbackbuffer; uniform vec2 buffersize; out vec4 fragData0; uniform samplerCube uTexture; smooth in vec3 eyeDirection; uniform vec2 camerarange; uniform float camerazoom; uniform vec3 cameraposition; uniform mat4 camerainversematrix; uniform mat4 projectionmatrix; uniform mat4 cameramatrix; uniform vec2 fogrange = vec2(0.0,15.0); uniform vec4 fogcolor = vec4(0.72,0.73,0.67,1.0); uniform vec2 fogangle = vec2(5.0,15.0); uniform bool fogislocal = false; uniform float clipheight= 0.0; float DepthToZPosition(in float depth) { return camerarange.x / (camerarange.y - depth * (camerarange.y - camerarange.x)) * camerarange.y; } void main() { //integer screen coordinates //needed for depth lookup ivec2 icoord = ivec2(gl_FragCoord.xy); if (isbackbuffer) icoord.y = int(buffersize.y) - icoord.y; //floating screencoords normalised to range 0-1 vec2 coord = vec2(gl_FragCoord.xy/buffersize); if (isbackbuffer) coord.y = 1.0 - coord.y; //fetch depth value float depth; #if SAMPLES==0 depth = texelFetch(texture3,icoord,0).x; #else depth = texelFetch(texture3,icoord,0).x; #endif //calculating worldposition from cameramatrix,screenposition and depth //normalize it to get the cubecoords vec3 screencoord; screencoord = vec3(((coord.x)-0.5) * 2.0,((coord.y)-0.5) * 2.0 / (buffersize.x/buffersize.y),DepthToZPosition( depth )); screencoord.x *= screencoord.z; screencoord.y *= -screencoord.z; vec4 worldpostemp= vec4(screencoord,1.0) * camerainversematrix; vec3 worldpos = worldpostemp.xyz;// / 1.0-worldpostemp.w; worldpos+=cameraposition; vec3 cubecoord = normalize(worldpos.xyz); fragData0 = texture(texture1,coord); if(depth == 1.0) //no geometry rendered --> background { vec3 normal=normalize(cubecoord); normal.y=max(normal.y,0.0); float angle=asin(normal.y)*57.2957795-fogangle.x; float fogeffect=1.0-clamp(angle/(fogangle.y-fogangle.x),0.0,1.0); fogeffect *= fogcolor.w; fragData0=fragData0*(1.0-fogeffect)+fogeffect*fogcolor; } else // no background - render input + fog to output { float lineardepth = DepthToZPosition(depth); float fogeffect = clamp( 1.0 - (fogrange.y - lineardepth) / (fogrange.y - fogrange.x) , 0.0, 1.0 ); if (fogislocal && lineardepth > fogrange.y) fogeffect=0.0; fragData0 = fragData0 * (1.0 - fogeffect) + fogcolor * fogeffect; } //if (cameramatrix[3][1] <= -0.99) fragData0=texture(texture1, icoord); }
  9. Cause I pushed the new build to the beta branch..... opps.
  10. Well later I found that link, but again, my first instinct was the Steam client/store.
  11. Is there a chance that other DLC's will be added to the workshop but updated to have the source files? I understand that it's been a while, but if you could include them, that'd be great! I opted out of the beta a week ago since the update broke my reflection system (most likely from your early env probe stuff), but I was looking at the Merc, and my first instinct to buy it was to use the Steam client, and not Leadwerks itself. In-fact, it was actually hard! There is a bug with the workshop window (not sure if it's fixed now) that the top taskbar was out of my screen space, and I couldn't close the workshop window. I'll try this update and post if it's still a problem.
  12. Did you try: System::Print(box->GetQuaternion(true)); ??
  13. A quick bump, today I found out about Awesome Bump, a free alternative to CrazyBump. Not only that it's free, but open source, and Linux version is a thing. Supports both bump mapping and PBR shading, so no matter if you're making a material for Shadmar's substance shader, or the standard ones. I've yet to really play with it, but it seems promising.
  14. I really hope official env probes get in the next full release. These recent beta updates broke my cubemap system.
  15. With the recent beta update(s), this doesn't work anymore! D: Hopefully official probe support comes soon.
  16. I understand that the MSAA 0 support is in beta (and released today), but I thought I might aswell post this report as soon as possible while it's still recent. I was testing my Darkness Awaits template for the Github transfer, and I decided to test multisampling set to 0 to see what would happen, and this was the results. As you can see, the particles aren't drawing correctly when multisampling is set to 0. You can see for yourself by installing this template, Set "multisample" to "0" in the player script, and playing the start map. Walk around and watch the flames toggle on and off depending on distance.
  17. Ahh ok, then it's the whole "My GPU hates Vsync" reasoning when I noticed why my frames were dipping. Mind sharing what you did? Because Leadwerks isn't the only engine I notice Vsync issues.
  18. I've been having issues with Vsync as of lately. Strangely when I load a map, it'll run at 60fps with vsync. Then when I reload it, the framerate tanks to 20, until you change the vsync setting to off, then on again, and it'll run at 60 again. Maybe I should upload the project so Josh can take a look at it as I would really like vsync to work as expected, and not turn the game into a slide show.
  19. reepblue

    Environment Probes

    I really hope you go forward with this. Although I've created my own system, I'd be nice to have it an official feature. I also didn't do a real world test (Full playable map with gameplay, etc), so I expect something to pop up with it. (I always do!) Anyway, glad to see you're looking into this and I can't wait to hear more on this.
  20. Visual Studio 2013/2015 Notepad Notepad++ Google Chrome Paint.Net Adobe Photoshop Adobe Illustrator Blender Goldwave Audacity Windows Media Player And I use an outdated version of MediaMonkey so I can listen to music while I work.
  21. With the recent popular substance shader by Shadmar, more talk and focus has been about cubemap reflections surfaced in the community. Reflections in Leadwerks were done in the past with the SSLR post process shader which made all surfaces reflect the world in real time. However, it had the following problems: It was applied to ALL materials in the scene. If you had a material that wouldn't normally reflect such as concrete or wood, the shader would still effect those materials. Basically, the texture artist had little control. The post process shader needed to be first on the list, and some people didn't understand that. You could adjust the reflections by the model's alpha color. But if you had any shader that relied on the alpha mask for map blending or something else, you're out of luck! The reflections distorted based on camera angle, and not really great for in-game action. Like everything OpenGL, there is/was a chance it wouldn't work well with AMD gpus. This was all we had until in February, Mattline1 posted a blog on his PBR system, which included a block of code that built a world cubemap and swapped the cubemap texture with it. Thankfully, he uploaded is source code so anyone who has the professional edition could download his code and have a look. While his implementation is very nice, it has the following design flaws for a typical Leadwerks user. You needed to use only the PBR shader. Normal Leadwerks shaders didn't render well. Needed a Post process effect to adjust the gamma of the scene. Weeks later, Shadmar uploaded his version of a Substance/PBR shader which allowed users to still use their existing shaders, and gave artists more to work. Since it's a shader, and not a full implementation like Matt's, it didn't have the world reflection system. I've been busy with a lot of Source engine work, but seeing how much interest this is getting lately, I decided to take a few days off and see if I can make my own cubemap system. The Implementation A disclaimer, this is not a full "How-To" as you'll need to add it to how your application, and it'll most likely do things differently than how I have my application set up. First, we need to figure out how we are gonna get a world cubemap to a texture. While it's not the most "next-gen" way of doing this, I decided to base my system off of the Source engine because, well I know how it works, and it's pretty simple. It goes like this: Mapper places a env_cubemap entity near a shinny surface. (Any material set to use cubemaps.) Mapper compiles and runs the engine. Mapper than types "buildcubemaps" into the console. For each env_cubemap entity, 6 "pictures" are taken (up, down, left, right, forward, and back). than those textures are saved within the bsp. The map restarts, and the surface will use the near by cubemap texture. Great, that seems very straight forward, and we can remove steps 2 and 3 as there is no compling in Leadwerks, and everything should just work. The first thing we need is a 3D point in the world that'll act as our env_cubemap. class Cubemap : public Pivot { public: Cubemap(Vec3 pos = NULL); //lua virtual ~Cubemap() {} ... ... ... }; We build off of the pivot class because we want this to actually exist in our world, not be a "puppeteer" for a pivot entity. We also have the position being set in the constructor as the only way to get our custom entity into the world is by a lua script. Using ToLua++ we can make a script that we can attach to a pivot/sprite. function Script:Start() local n = Cubemap:new(self.entity:GetPosition(true)) self.entity:Hide() end This script will spawn our cubemap entity at our editor placed pivot, then hide the editor placed pivot. Basically, we swap the entities during level load. This cubemap entity job is to search for near by entites, (Which I currently have set to it's aabb radius + a range float) then change it's surface material with a copy of what it had, only with a different cubemap texture. Early in development, I just have the entity fix the cubemap texture to the current world's skybox to make sure that this would work. void Cubemap::SetReflectionTextureToSkybox(Leadwerks::Surface* surf) { if (WORLD == NULL) { return; } if (WORLD->skyboxpath == "") { return; } if (!surf) { return; } Material* mat = surf->GetMaterial(); if (!mat) { return; } // Make this faster, if there is any indication of a surface not using the substance shader, abort the cubemap application! // If there is no cubemap assigned, then we can skip this object. if (mat->GetTexture(6) == nullptr) return; // if the metal value is 0, we can skip. int matspecmetalness = mat->GetColor(COLOR_SPECULAR).w; if (matspecmetalness == 0 ) return; Material* copy = (Material*)mat->Copy(); if (copy != NULL) { Texture* cubeTexture = Texture::Load(WORLD->skyboxpath); copy->SetTexture(cubeTexture, 6); surf->SetMaterial(copy); cubeTexture->Release(); copy->Release(); } } Before we go into building the world cubemaps, we need to add this to the entity's header. This will make it so we can pass a texture to the entity: Texture* SavedMap; Texture* GetCubemap() { return SavedMap; } Now to the cubemap factory, which on map load will find all of our cubemap entites, do the texture building or each entity, Set SavedMap to the new cubemap texture, then tell the cubemap entity to look for near by entities so it can do it's replacement job. Thankfully, all the yucky stuff has been done by Matt, so I just needed to cut the stuff I didn't need, and make it handle multiple level loads and disconnects to work with my worldmanager class. Here's a few snip of this process. bool CubemapFactory::initialize() { Release(); ... ... ... int i = 0; do { if (WORLD->GetEntity(i)->GetKeyValue("cubemap", "0") == "1") { Cubemap* pCubemap = dynamic_cast<Cubemap*>(WORLD->GetEntity(i)); if (pCubemap != NULL) { // Build the cubemap cubeTexture = Leadwerks::Texture::CubeMap( reflectionResolution, reflectionResolution, Leadwerks::Texture::RGBA, Leadwerks::Texture::Mipmaps ); cubeTexture->BuildMipmaps(); Leadwerks::OpenGL2Texture* gl2cubeTexture = dynamic_cast<Leadwerks::OpenGL2Texture*>(cubeTexture); glActiveTexture(gl2cubeTexture->GetGLTarget()); glBindTexture(GL_TEXTURE_CUBE_MAP, gl2cubeTexture->gltexturehandle); glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glGenerateMipmap(GL_TEXTURE_CUBE_MAP); // Apply it! GenerateReflection(pCubemap->GetPosition()); //<-- generate first reflection texture GenerateReflection(pCubemap->GetPosition()); //<-- use initial texture to generate correct texture if (cubeTexture != nullptr) { pCubemap->SavedMap = cubeTexture; } // Tell the cubemap to look for near by entities, and replace it's cubemap texture with cubeTexture pCubemap->SearchForEntites(); cubeTexture->Release(); } } i++; } while (i < WORLD->CountEntities()); ... ... ... CubemapFactory::init = true; } GenerateReflection() is pretty much the same as Matt's PBR project. That function actually does the "camera work", and saves the result in a Texture. This is done on the fly during level transition. Skipping Dynamic Objects There is just one problem however. Everything is being rendered when the cubemaps are being built. So any enemies, or move-able objects will be baked into a reflection. To fix this, we need to have all objects that can move (Mostly have mass) be hidden, and then re-shown after we've finished the building of cubemaps. Pretty much. #define S_NULL "" #define ON "1" void ShowMoveables(Entity* entity) { if (entity != NULL) { if (entity->Hidden() == true && entity->GetKeyValue("hide_for_cubemap", S_NULL) == ON) { entity->Show(); entity->AddForce(Vec3(0, 0, 0)); // <-Wake me! entity->SetKeyValue("hide_for_cubemap", S_NULL); } } } void HideMoveables(Entity* entity) { if (entity != NULL) { // Things to look for ar entites with the mass > 0, or have their shadow mode non static! if (entity->GetMass() == 0 || entity->GetShadowMode() == Light::Static) return; // Only hide the non-hidden! if (entity->Hidden() == false) { entity->SetKeyValue("hide_for_cubemap", ON); entity->Hide(); } } } void MapHook(Entity* entity, Object* extra) { // For cubemap generation, we don't want anything that's set to move to be built in with our cubemaps. HideMoveables(entity); } bool WorldManager::Connect(std::string pMapname) { ... if (Map::Load(pMapname, &MapHook) == false) return false; ... return true; } //-------------------------------------- // For cubemap building! //-------------------------------------- void WorldManager::MakeMoveablesVisible() { vector<Entity*>::iterator iter = entities.begin(); for (iter; iter != entities.end(); iter++) { Entity* entity = *iter; ShowMoveables(entity); } } Then back in the initialize function of our cubemap factory before we return true. // Lastly, redraw moveables! worldmanager.MakeMoveablesVisible(); And now anything that has mass, or has it's ShadowMode set to Dynamic will not be baked into the reflection! Cleaning up To make it so that this can work with multiple level loads and when the game "disconnects" (Not in a map), we need to reset everything. Cubemap factory: void CubemapFactory::Render() { if (WORLD != NULL || worldmanager.IsConnected() == true) { if (!CubemapFactory::init) { CubemapFactory::initialize(); } WORLD->Render(); } } void CubemapFactory::Release() { System::Print("Clearing Cubemaps!"); CubemapFactory::init = false; if (cubeTexture != NULL) { cubeTexture->Release(); } CubemapFactory::currentContext = nullptr; CubemapFactory::reflectionCamera = nullptr; CubemapFactory::cubeBuffer = nullptr; CubemapFactory::cubeTexture = nullptr; } And instead of calling world->Clear in my world manager, I instead call this function: void WorldManager::ClearWorld() { CubemapFactory::Release(); world->Clear(); } Calling CubemapFactory::Release() may not be necessary as it's called everytime the factory is initialized, but it doesn't hurt to be safe! Conclusion It was a ride getting this to work correctly. I'm still not happy about how the cubemaps look for near by entities, but it's better than what we have now, which is nothing, Apperently, Josh is concidering this as a engine feature so all of this work might just be temp until he adds it in, which hopefully will be smoother and less error prone! But what we have a system that works like this: Engine loads a map, world created, etc. A map hook hides any entities that has mass or a dynamic shadow mode. Cubemap Factory takes it's "pictures" much like Source does when buildcubemaps is executed. Each cubemap texture is given to the right Cubemap entity, then released. The cubemap looks for near by entites and swaps the model surface's default cubemap with the one it got from the factory. Cubemap factory tells the world manager to re-show the entities it hid. Things continue as normal. So that's it! Thanks for reading!
  22. What you have is great, but this video came to me when I saw the map reflection in the floor. If you are gonna do this, maybe make it it's own shader file perhaps.
  23. Source engine like cubemap generation!
×
×
  • Create New...