-
Posts
24,626 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Downloads
Everything posted by Josh
-
Why? Transfer buffers are a very common technique.
-
The imposter generation step was missing a conversion from linear space back to srgb, resulting in dark images. This has been fixed.
-
The issue in the first post is fixed. In order to investigate the other issue, I will need to download your project so I can try it.
-
0.9.6 Fixed bug that was preventing painting mesh layer instances in some situations.
-
I think selecting an object should use a polygon pick, but once it is selected, I could see a good argument for using the bounds of the selection as the area to click and drag to move things.
-
When I click to download the page says: This attachment is not available. It may have been removed or the person who shared it may not have permission to share it to this location.
-
I think I am going to make the interface in C++, built into the program, and then use Lua for the various integrations with different websites. Here is the final version of the pure Lua approach. It doesn't download assets but it's a nice example of asynchronous behavior with Lua. AssetLibrary.lua
-
0.9.6 HDRI to cubemap tool no longer using OpenCL so it will work on all machines now.
-
This algorithm creates an intermediate buffer that gets passed to the rendering thread. It's working as I would expect.
-
3dassetsone API: https://3dassets.one/about-site
-
Here is a basic skeleton for a downloader. The idea is to have one system with multiple content providers that can be plugged in to download assets from other sources. local extension = {} extension.providers = {} function extension:Initialize() local sidepanelwidth = 280 local x = 4 local y = 4 extension.window = CreateWindow("Asset Library", 0, 0, 1024, 768, program.window, WINDOW_HIDDEN | WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_RESIZABLE) extension.ui = CreateInterface(extension.window) extension.treeview = CreateTreeView(x, y, sidepanelwidth, extension.ui.background.size.y - y * 2, extension.ui.background) extension.treeview:SetLayout(1,0,1,1) extension.panel = CreatePanel(x + sidepanelwidth + 4, y, extension.ui.background.size.x - sidepanelwidth - 4 - 2 * x, extension.ui.background.size.y - 2 * y, extension.ui.background, PANEL_BORDER) extension.panel:SetLayout(1,1,1,1) --extension.panel:SetColor(extension.panel:GetColor(WIDGETCOLOR_SUNKEN)) extension.panel:SetColor(0,0,0,1) --Set DPI scale if needed if program.window.display.scale ~= 1 then local scale = program.window.display.scale local pos = extension.window.position local size = extension.window.size extension.window:SetShape(pos.x, pos.y, size.x * scale, size.y * scale) extension.ui:SetScale(scale) end ListenEvent(EVENT_WINDOWCLOSE, extension.window, extension.ProcessEvent, extension) ListenEvent(EVENT_WINDOWSIZE, extension.window, extension.ProcessEvent, extension) local s = FetchUrl("https://ambientcg.com/api/v2/categories_json") local t = LoadTable(s) local n local groups = {} for n = 1, #t do local name = t[n].categoryName local group = t[n].defaultDataTypeId if groups[group] == nil then groups[group] = {} end groups[group][name] = t --extension.treeview.root:AddNode(name) end local k,v local base = extension.treeview.root:AddNode("AmbientCG") for k,v in pairs(groups) do local node = base:AddNode(k) local k2, v2 for k2, v2 in pairs(v) do node:AddNode(k2) end end base:Expand() end function extension.ProcessEvent(event, extension) if event.id == EVENT_WIDGETACTION then if event.source == extension.menuitem then if extension.window == nil then extension:Initialize() end extension.window:SetHidden(false) extension.window:Activate() return false end elseif event.id == EVENT_WINDOWCLOSE then if event.source == extension.window then program.window:Activate() extension.window:SetHidden(true) return false end end end local submenu = program.menu:FindChild("Scripting") if submenu == nil then Print("Error: Could not find script menu") return end extension.menuitem = CreateMenu("Asset Library", submenu) ListenEvent(EVENT_WIDGETACTION, extension.menuitem, extension.ProcessEvent, extension) --Add a content provider local t = {} function t:GetCategories() end table.insert(extension.providers, t)
-
Well, that's the maximum I thought would be necessary. The GPU will have to allocate a buffer equal to the number of LODs times the number of instances of the model that exist in the world, times four, which I guess is not that much memory. I could probably support more but four seems like a nice number. The culling routine might also have to iterate through the number of LODs for each instance in order to be dynamically uniform.
-
Get download links and preview images for a single item: https://ambientcg.com/api/v2/full_json?type=Material&sort=Popular&limit=10&include=downloadData%2CpreviewData&offset=0&id=Bricks092
-
Get all files in a category, with downloads and preview images: https://ambientcg.com/api/v2/full_json?type=Material&sort=Popular&limit=10&include=downloadData%2CpreviewData&offset=0&category=Bricks
-
This gets the categories: https://ambientcg.com/api/v2/categories_json
-
The engine supports up to four LODs. It will be important to enforce this when we move culling over the a compute shader, because the data layouts have to be very strict.
-
Recently I came across a problem where HDRI images I loaded and converted into cube maps looked simultaneously too bright and too dark. I found that a simple linear to sRGB conversion made the images look as I would expect. I have read about sRGB and linear color spaces before, but for some reason this time it just clicked and I understood. Maybe since I am not longer dealing with low-level Vulkan nonsense, I have extra mental capacity to spend on more high-level concepts like this. In any case, I find this stuff is usually not explained very well and I want to show you how it works, in simple terms everyone can understand. The basic idea of sRGB color space is that the way we perceive lightness in an image is wrong. Look at the gradient below. The change in the left-most 25% of the image looks much greater than the change in the right-most 25%, but it's not: A long time ago, photography folks all agreed that these types of gradients look wrong. You will often see this referred to as crushed blacks, the opposite of overexposed bright colors, and it's usually considered to be a bad thing: In 1996 HP and Microsoft came up with an equation that makes a gradient that looks "right". This is called sRGB color space, and it just shifts the darker tones to the right with a simple equation. The resulting gradient below looks more "balanced", even though it's really unbalanced: The only problem is that since these colors are stretched, all our nice neat color math is no longer valid. Multiplying two colors together like we do for lighting won't produce the right result because the colors have all been shifted to the right by varying amounts. The solution is to unstretch all colors by converting from sRGB to linear, perform your color math like lighting, and then shift the result back from linear to sRGB. Fortunately you don't have to modify your textures and colors, because sRGB is considered the "correct" value that we want to see, and linear color space is a temporary intermediary used for math. We can convert between these color spaces in a shader with the code below. const float GAMMA = 2.2; const float INV_GAMMA = 1.0 / GAMMA; vec3 linearTosRGB(vec3 color) { return pow(color, vec3(INV_GAMMA)); } vec3 sRGBToLinear(vec3 srgbIn) { return vec3(pow(srgbIn.xyz, vec3(GAMMA))); } Let's take a look at some math to see how light and color interact with this approach: float albedo = 0.5; float light = 0.75; float color = albedo * light; Print("Simple lighting: " + String(color)); albedo = sRGBToLinear(albedo); light = sRGBToLinear(light); color = LinearTosRGB(color); Print("sRGB lighting: " + String(color)); The output of this program shows that converting from sRGB to linear and back results in lighting that doesn't get smashed by the albedo color: Simple lighting: 0.375 sRGB lighting: 0.640292 What this technique basically does is it reallocates precision away from the bright colors, which we do not have as accurate perception of, and gives it to the dark colors, which we can see between more easily. With standard linear color a simple scene looks both dull and heavily contrasted: The same scene comes to life when colors are converted from sRGB to linear before lighting, and then transformed back for the final color. We can clearly see a blue tint from the PBR environment map mixed with the orange color, and the dark gray colors have much more definition now. I don't even understand how something can be blue and orange at the same time, but I can clearly see a blue reflection from the sky in the image below. This operation doesn't change the colors, it just changes the way that colors combine. Overall this makes it easier for lights to illuminate dark areas without requiring extremely bright lights with strong contrast, and the PBR lighting is more strongly visible in colored objects. This update is available now on the beta branch, in the standalone and Steam versions of Ultra Engine. I used the Lua code below to create the gradient images. You can paste this into a Lua file and run it by selecting the Script > Run Script item in the main menu, or you can just paste this into the console and press enter, and it will run: local pixmap = CreatePixmap(256, 16) --Write linear gradient for x = 0, pixmap.size.x - 1 do for y = 0, pixmap.size.y - 1 do pixmap:WritePixel(x, y, Rgba(x, x, x, 255)) end end pixmap:Save(GetPath(PATH_DESKTOP).."/lineargradient.png") --Convert to sRGB pixmap = pixmap:LinearTosRgb() pixmap:Save(GetPath(PATH_DESKTOP).."/srgbgradient.png") I hope this explanation helps you to understand what sRGB and linear color spaces actually do and how this feature makes your games look better. It's actually a very straightforward concept that for some reason is poorly explained in most articles I have seen. Just remember, linear is the "squished" color for math, and sRGB is the "stretched" color that's easier to see (sRGB = standard stretched RGB).
-
And here is how to retrieve the contents of a Github repository: https://api.github.com/repos/ultraengine/documentation/contents/CPP
-
Okay, so I found that the LOD models contain extra hierarchy. This is bad because the editor can't correlate which limb matches which. Maybe I can improve this, but the easiest solution is to collapse the models first. Once I did this, the LODs loaded and saved with no problems. I generated a convex decomposition collider and that seemed to work fine. veoneio.zip (This model contains one additional LOD.) When importing large numbers (about 100) of complex models, I had the best results writing a script that automated the process. You can call Collapse() and AddLod() in a script and use the Scripts > Run Script menu item to execute it.
-
When and how is this done? In code or in the editor?
-
Prefabricated does not load on the map, the editor closes.
Josh replied to Yue's topic in Bug Reports
I found this: "prefab": { "path": "Models/Prefabs/ModuleA.pfb" }, The prefab tries to load itself. The solution is I need to break the prefabs when a prefab is saved, although I have no idea how you created this one. Unity needs nested prefabs because they treat FBX files as a collection of meshes to assemble prefabs from. Our model format supports a lot of information, and I think nested prefabs might not be needed in Ultra. -
I will need to download the model in order to test it.
-
Oh, okay. The newer build solves a problem some models had, but it was a long time ago and I don't remember what the issue was.