
Ma-Shell
Members-
Posts
371 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Downloads
Everything posted by Ma-Shell
-
You mean, because unlike the previous version the user does not directly call Render() anymore, since it is run on a different thread and thus the user can not correctly orchestrate the rendering? This should not be a problem, since in CreateCamera you can specify the world. auto realCamera = CreateCamera(realWorld); auto HUDCamera = CreateCamera(HUDWorld); realCamera->setOrder(1); HUDCamera->setOrder(2); realCamera->SetClearMode(CLEAR_DEPTH | CLEAR_COLOR); HUDCamera->SetClearMode(CLEAR_DEPTH);
-
Would it be possible to use two different worlds for this? One "real" world and one for your HUD and then first rendering only the first world and after that rendering the HUD-world.
-
The model probably does not have a surface. You should get the number of surfaces first and then iterate over the surfaces. Something like the following (I don't know much about lua, so probably this code won't work without modification): for k,v in pairs (self.modelTable) do for i = 0, v:CountSurfaces(), 1 do surface = v:GetSurface(i) mat = surface:GetMaterial() mat:SetShader(shader) shader:SetVec4("ex_color",self.color) mat:SetColor(self.color) self.modelTable[k] = nil end end
-
As I said, you should take a look at the objects on your map and the scripts they have attached!
-
I am pretty sure, the problem is coming from a LUA script of an object in your map, not from C++. That script has probably a world render or update hook, where it tries to access that variable.
-
No, the comment "//lua" only means that this function is available in lua, as well, but that does not mean, that it is only executed in lua. As for your other problem, it seems like you might not be setting the variable "world" before calling the Update-function or you are probably setting a function-local variable in the Start-function and then accessing a global variable in the update function or something like that. It's hard to say without seeing your code.
-
Also, looking at https://www.gamedev.net/forums/topic/673534-instancing-and-the-various-ways-to-supply-per-instance-data/?do=findComment&comment=5264179, you can create the buffer much larger first, then copy all data and later repeatedly use glBindBufferRange instead of glBufferSubData, copying all data in one go and being much faster
-
ah, I see, so you're refering to GL_MAX_UNIFORM_BLOCK_SIZE (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml)? I think, it would make sense, to query that number in the beginning and use that instead of the fixed 256. Otherwise every system would suffer, only so that it can run on lower end systems. EDIT: Of course I mean use that number divided by 64
-
Doing a performance-test with LW 4.7, I wanted to draw an element ins tanced multiple thousands of times. Using RenderDoc I found out, that Leadwerks batches these into groups of 256 elements each, so instead of having one call to glDrawElementsInstanced, instead I have quite many (which in my eyes are not needed). Also looking at the shaders, I found that they usually have a line like #define MAX_INSTANCES 256 I believe that there is a lot of wasted potential because of this for rendering large groups of the same entity. Is there a reason for this limit? Can we increase it somehow? Will the same limitation be there in Turbo? I have attached the source code for my test. App.h App.cpp main.cpp
-
How long until you get the Top Secret Tesselated Toad Tech? ?
-
Performance Tanks after Instancing an enemy just 6 times.
Ma-Shell replied to TheConceptBoy's topic in General Discussion
One should also note that there are basically two different Debugging modes: The option you changed affects only the Code Generation process. This means that the Debug version will set some compiler flags, which might enable some runtime checks in the libraries that were included and it also might disable binary optimizations. However, independent of whether you compiled a Release or a Debug version, you can start your executable with a debugger attached or without one. The debugger running on the release version will usually not give you as useful results as on the Debug version, as the Release version might optimize your code by removing some variables or unnecessary code. However, it is still possible to debug the release version and set breakpoints etc. So for maximum performance you should switch to Release version and then choose "start without debugging" (in the debug-menu) -
Leadwerks Multiplayer Controller Theory
Ma-Shell replied to gamecreator's topic in General Discussion
You can not 100% protect the game files. You can only make it hard enough for an attacker to eventually give up and lose interest in deobfuscating what you did. The reason, why it is not possible to protect the files is that the pc must be able to execute and therefore decrypt your files and an attacker can simply e.g. attach a debugger to your program and read the contents from memory or reverse engineer the decryption-process. For this reason, one option for an attacker to cheat is by simply modifying the game files. For multiplayer games, an attacker can actually simply send data to the players / the server, without even touching your game files, if they figure out the protocol you are using. They can learn about your protocol e.g. by simply analyzing networking-dumps. The other party does not have any possibility to check that the data was sent from your program and not from any other program capable of sending networking-packets. -
Leadwerks Multiplayer Controller Theory
Ma-Shell replied to gamecreator's topic in General Discussion
Why would the server do that? It should instead just tell the client the correct current state, the client takes this state as the new truth (it might use some smoothing operations, so the objects don't flip around) and starts simulating from that new state again... No need to simulate the past, if the actual current state is known. This network-model you are describing is called "client side prediction" and by googling that term, you should be able to find lots of articles to help you further with this. -
You can see in the file "Leadwerks\Include\Classes\Drivers\Physics\NewtonDynamics\NewtonDynamicsPhysicsDriver.h", that the PhysicsDriver has a reference to the collisionWorld, which is a NewtonWorld pointer. You can get the current physics-driver from "_currentPhysicsDriver" but you need to cast it to a NewtonDynamicsPhysicsDriver, thus: ((NewtonDynamicsPhysicsDriver*)(_currentPhysicsDriver))->collisionWorld should be the droid you're looking for. (I haven't tested this but I am fairly certain, this will work)
-
(https://www.leadwerks.com/community/blogs/entry/2387-getting-started-with-vulkan/?tab=comments#comment-10207) So, do you wish to take back that statement or did you now find other ways to optimize that were not possible in the OpenGL implementation? Anyway, I'm happy, you decided to go with Vulkan
-
Don't know about shadmar's one but you can try that one:
-
That way makes total sense to me. With Load() you are creating the first instance and with Copy() you are copying that instance... Copying (as opposed to instancing) makes only sense if you already have an object using that model, so you can just use that one. Have you tried the suggestion using the "Asset::CreateNew"-parameter?
-
For me this behaviour you described makes perfectly sense. The call to "Load" creates your first instance and the call to "Copy" creates your second instance by copying the first one. So if you could get a hand on your other model instance which comes from the same asset, you could go ahead and call other_instance->Copy(true) and you would get what you wanted. Furthermore, the documentation of Load (https://www.leadwerks.com/learn?page=API-Reference_Object_Entity_Model_Load) mentions that there is a second parameter called "flags" but it does not say, which ones are available. The description is simply "asset load parameters". That is something, you might want to add to the documentation @Josh. From the header file Asset.h, I find the following four constants defined, which I believe are those mentioned asset load parameters: Unmanaged, CreateNew, LoadQuiet and SkipTextures. You might want to give the following a shot (I haven't tried it myself): Model::Load("Models/level/ground.mdl", Asset::CreateNew);
-
The problem you are trying to solve is called "Principal Component Analysis (PCA)". The process involves quite a lot of math, computing Eigenvalues, etc. I'm not entirely familiar with how it works either but just throwing this term at you, so you can use the name for further research
-
Josh seems to have a way to extract the files if you can prove ownership to him: https://www.leadwerks.com/community/topic/16895-do-you-need-your-encrypted-game-files-extracted/?do=getNewComment
-
Using Multiple Entity Scripts in Turbo Game Engine
Ma-Shell commented on Josh's blog entry in Development Blog
Nice, I like the concept you are proposing here. Just adding my 2 ct: When you said, there was no remove-function for a script, that makes perfect sense for scripts that are only setting variables, as you mentioned. However, you might want to have the option to remove these functions. Let's consider your tank-example: If you somehow lose your main cannon, you might want to remove the script associated with it, such that future calls to GetTarget() do not call the function of the main cannon anymore. There is another issue with your tank-example: If you have two functions called GetTarget(), you would likely also name the corresponding setter-function SetTarget(), each. However, this would mean that you can only set the target of both at the same time, if you did not name them AISetTarget() and CanonSetTarget(). For this reason, I think, you should draw a line here so you have to make explicit whether you want to call functions from a different script or only those of the same script. I would suggest, you do the following: SetTarget() will only execute the function from the current script. If there is no function named SetTarget in the current script, an error should be thrown All::SetTarget() (or something similar) will execute functions from all attached scripts (as well, as the current script) with the current name (i.e. the way you proposed) FILENAME::SetTarget() will only execute the function from the script called FILENAME. If this script does not exist or it does not have this function, an error should be thrown So for each function you define in your script, you would need to internally create three different mappings. Doing this would give everyone maximal flexibility while at the same time preventing some unforeseen errors. So, everyone could still use their isolated scripts the way they used them before without even needing to change anything. If you want to call functions from other scripts, you have the choice to select either only one specific other script or all others -
In order to move the rotation center, you need to translate the point, such that the new rotation center lays at (0, 0), then apply the rotation matrix and then translate it back. This means, you need to change the last line to something similar to vTexCoords0 = (texcoords[gl_VertexID] - vec2(0.5, 0.5)) * rot + vec2(0.5, 0.5); I haven't tried it out, so you might need to switch the minus and the plus or play around a little bit but something like this should do the trick
-
Brushes get collapsed to form a single object (except if they have a mass or a script attached). This means, if you have 100 CSG cubes, there is still only one transformation matrix for them and basically everything that runs per object only runs once. For that reason, they should perform better than using multiple objects of box models... If you, however, compose all the boxes in your 3d modeller and export them as a single object, they should perform the same. I suppose, collapsing could have a negative impact as well: since they are only one object, the individual boxes can not be culled. I.e. if one of them is within the viewing frustrum, all of them need to go through the rendering stages until the individual fragments are finally culled when rasterizing, while if everyone is an individual object, they can be culled early. This means that both, a negative and a positive impact on performance might be possible.
-
You also need to take into consideration that you need to read less data from the harddrive and IO is usually quite a large factor in loading times, so on a slow harddrive you might even see better loading times with a compressed package.
-
In the following I will use the following terminology: A -> blue point, B -> red point, C -> yellow point, D -> black point (point to find); I will further use o to specify the dot-product of two vectors and use v1, v2, v3 to specify the individual components of v. Overview: You need to mirror B on the line AC. This will yield a point B' which is on the line AD. From there you can calculate D by going |u| from A in the direction of AB'. Step by step: The line going through A and C can be written as X=A+p*a with p being a scalar variable. We need to find a vector Z such that B+Z is on that line (i.e. there exists a value for p such that B+Z = A+p*a -> Z = A+p*a-B -> Z = p*a-w) and that is perpendicular to a (i.e. Z o a = 0). Together that is: 0 = (p*a-w) o v 0 = (p*a1-w1)*a1 + (p*a2-w2)*a2 + (p*a3-w3)*a3 -> p = (a1*w1+a2*w2+a3*w3)/(a1*a1+a2*a2+a3*a3) -> p = (a o w) / |a| With this we can calculate Z as Z = p*a-w Now we can mirror B as B' = B+2*Z -> B' = B+2*(p*a-w) Now we can calculate D as D = A + |u| * (B' - A) / |(B' - A)| Implementation: Simply hack in the formulas I marked as fat and you should be good (p is a float and B' and D are both vectors). Let me know if you need any further help with that!