Logo with title ".Blog"

Briefs

Low-effort content for certain microblogging platforms.

Good fit

Sometimes it takes way too much energy to decide that something you want to use isn’t going to be a good fit.

22

Not the 22nd month. Don’t care.

Sun rays Mk II

Sun rays with much better performance.

Lot to unpack here. Each ray is a triangle within a MeshPart. Each MeshPart groups together 85 triangles. Each vertex has a corresponding Bone, so the triangles can be positioned independently and arbitrarily. Rays are produced by allocating tris from the 85-tri meshes. A new MeshPart is created once all the tris from the previous MeshPart are used.

The ForceField material is utilized here. As previously mentioned, the orientation of vertex normals affects the appearance of the force field. Each vertex corresponds to a bone. For each tri, one of the bones is designated as a “roller”.

The roller bone is moved out of the MeshPart into a separate Part that is attached with a BallSocketConstraint at the original location. This part has another attachment with a randomized orientation. This randomized attachment is assigned to an AlignOrientation.

The other end of the AlignOrientation is assigned to a single attachment. The brick in the video contains this attachment. The rotation of this brick is directly controlling the “movement” of the rays.

The extra attachment with the randomized orientation is necessary so that the appearance of force fields are spread out and unaligned. Assemblies with BallSockets are necessary so that the bones are detected correctly while allowing free orientation.

Now that I think about, the whole thing is driven entirely by physics. The only script running continuously is to rotate the brick, but that’s only because the AngularVelocity constraint was being finicky.

Driving the control brick through physics doesn’t work well, because the rollers seem to fall asleep or otherwise get stuck. Updating it via script seems to keep them awake.

Sun rays

Sun rays.

Each ray is just a stretched cube mesh with an almost transparent ForceField material. The mesh is just for surface smoothing, so a simple Union could be used as well, though it’s less convenient to resize. Each part is rotated continuously.

Rays are cast from a defined plane using GetSunDirection, so some occlusion can be achieved.

In practice, it seems like using meshes and ForceFields is excessive. Regular transparent parts seem to produce more or less the same effect.

Retrying with a simple triangle mesh has much better performance. An interesting side-effect of using a mesh with bones is that the shape and appearance of the ForceField can be controlled by the vertex normals.

Rotating the vertex normals instead of the part produces a subtle rolling-fog-like effect. Not sure if it will show up in the video, but it’s really cool. Unfortunately, the performance is awful. Bone modification doesn’t seem to be as optimized as it could be.

According to the profiler, modifying a Bone’s CFrame once involves 27 instances of “Loader”, each involving a call to “IsA”. Definitely doesn’t seem right.

Apparently the ForceField material can be affected by vertex color alphas, but Blender doesn’t support them???

A further optimization is to have multiple triangles per MeshPart. A mesh can have up to 256 bones, which amounts to 85 triangles. This reduces the above scene of ~400 parts down to just 6.

It’s fine to put pressure on Roblox for the plugin marketplace, but you have no business being angry about it. Its financial viability was questioned from the moment it was introduced.

It has been around two years with no action from Roblox. A very short time to coordinate a multitude of features across a variety of systems and teams while also juggling other priorities. Especially considering the happenings during those two particular years. My impression is that they’re working on it. Give the feature the time it deserves.

Moving to http://itch.io is an excellent way to apply pressure and get Roblox to reevaluate their priorities. I just think that being upset about it comes off as entitled.

coroutine.close

The new coroutine.close doesn’t cause the thread to be removed from the scheduler, so it’s still sitting around in memory. Proper delay cancellation remains unsolved.

Just now I discovered that the devforum has a private category specifically for the plugin marketplace, created only a few months ago. Maybe something’s up.

Plugin running

Plugins run a lot earlier than you’d think. If you need to depend on the game running, you can do the following to block:

if not RunService:IsRunning() then
	RunService.Stepped:Wait()
end

Yaks

One of those days where a bunch of yaks just barge in.

Money

A player reaches out to you for support on your Roblox game (data loss). While gathering information you realize they ran exploits. Do you continue with their request?

Ozzypig, 10:37 PM · Feb 6, 2022

Assuming my game has already isolated them from non-exploiters, the answer depends on whether they’re making me money.

Web slides

Why are presentation programs still a thing? Why hasn’t the entire concept been completely devoured by HTML/CSS/JS? You’re basically making a bunch of web pages. You could do it all on one page. Hell, you probably don’t even need JS.

CFrames

Attributes are not allowed to be CFrames. Why.

Moreover, since Roblox’s inception they haven’t displayed CFrames in the properties panel. Instead we’ve been getting things like Position/Orientation pseudo-representations for select properties.

Roblox could have done this years ago:

Production logo sequencer.

First logo is actually 3D to avoid loading assets. On the other hand, the next logo loads over 500 assets; the previous logo will wait until the next logo is finished loading. The second run of the sequence demonstrates skipping via user input.

Maid pattern

Maids are a pattern.

local maid = {}

local function finish(maid)
	for _, task in pairs(maid) do
		task()
	end
	table.clear(maid)
end

local conn = button.Activated:Connect(listener)
maid.activated = function() conn:Disconnect() end

instance.Parent = parent
maid.instance = function() instance:Destroy() end

local otherMaid = {}
otherMaid.maid = function() finish(maid) end

finish(otherMaid)

Quotes

Including “without the quotes” will be necessary until humans are extinct.

Passphrase

When you’re typing your passphrase and you feel a sneeze coming on so you start scrambling to finish.

Cloth physics

Here’s cloth physics via RodConstraints. Cloth is a MeshPart deformed by bones. Bone positions are matched to node positions by a script. An AngularVelocity dampens each node, since their rotations like to go crazy for some reason.

Bones have to be parented to a MeshPart to work, so a script is necessary. It would be neat if they could refer to a mesh instead, so that they could be placed inside different parts.

Seems to run surprisingly well. Like capes-for-everyone might be viable, at least for a low player count.

The MeshPart is anchored, but its appearance is deformed using bones. A script updates the positions of the bones every frame to match the positions of the red balls, which are simulated with Roblox’s physics.

Here’s cloth with SpringConstraints instead of rods. LinearVelocity dampens movement. VectorForce negates gravity to reduce weight. Spring Stiffness makes the cloth more or less stretchy.

RodConstraints are much better for less stretchy material, but the LinearVelocity force has to be increased to compensate for the increased rigidity:

Apparently the orientation of bones affects the vertex normals of meshes, so I can’t really get away with just ignoring it. No good way using constraints, so I’ll have to calculate it in Luau.


What am I doing with my life.

So, yes, it is possible to control bones with other parts, but it requires certain constraint types to work. BallAndSocket is the most versatile, so I’ll see if I can construct cloth out of that. Until then, it’s floppy rigatoni.

“hey tony, rig me a pasta noodle”

I’ll have to rig-a-toni. Hahaha HAHAHAHAA AAAAAAAAAAAAAAAAAAAAAAAAA

— Me (utterly deranged)


Think I have a general theory of how skinned meshes work. Two bones are merged if and only if they:

  • have the same Name.
  • are under the same Model.
  • are a part of the same assembly via compatible joints (JointInstance, BallSocketConstraint, HingeConstraint).

If more than two bones meet these criteria, only one pair is merged. It’s not clear which pair is selected, but it’s probably undefined.

Bones usually exist internally in a mesh. The Bone instance can be thought of as creating a virtual internal bone that is then merged as usual.

Some examples of valid skinned mesh configurations (I forgot to update the compatible joint list; any JointInstance is allowed, not just Motor6Ds and Welds):

We variously called them “skinning islands” or “skeletons” instead of assemblies (can span multiple assemblies or just a subset of one), but that’s pretty much it. Bones don’t have to be child of mesh at all.

This is how skinned avatars work. Parts link up, internal bones linked to the respective parts. Using Parts instead of Bones but it’s all using the same logic.

@ContextLostRBX, 8:26 AM · Jan 17, 2022


Here’s cloth driven entirely by physics. No scripts. Vertex normals are still a problem because the BallSockets are allowed to twist. But if twist limits are enabled, they start vibrating for some reason. Maybe the attachments are oriented wrong.

Constructed in a zigzag because I had trouble getting the mesh to merge to the assembly any other way. Either it only merges into one branch of an assembly, or it’s something to do with the attachments. Doesn’t seem to care about the direction of the connections, though.

BallSockets have a sort of stiffness property that can be used to dampen the motion, but this only works well for stiffer cloths. LinearVelocity will be better for lighter cloth because it simulates air resistance.

The horizontal red lines are Rods. It would actually be better to make these parts with BallSockets on each end, so that all joints can have stiffness applied to them. I’m not sure how that would affect the “branchiness” of the assembly, though.

Tried a new skeleton consisting of rows of chains of bones, which correspond to chains of BallSockets. Each joint is then connected by a Rod. The problem now is that character movement is way too aggressive. Maybe increasing the cloth weight will help?

What happens when I enable collisions:

Nuking appears to be caused by cloth joints getting under the Humanoid. So, instead of colliding with the Default group, a separate “ClothExclusion” group is used (in red). Lowering the UpperAngle of the BallSockets reduces flailing and tangling. Limb clipping still a problem.

The problem with limbs is that the Humanoid forces them to have no collisions. Could be resolved by attaching ClothExclusion parts to each limb. Not sure how badly that will affect flailing, though, if they even collide correctly.

Something to try is to attach an AlignPosition with a weak force to the end of each chain, aligning to the expected resting position of the end relative to the character. It may also be possible to alter them dynamically to improve air resistance simulation.

Another problem is that something is interfering with jumping, leading to the character being pushed horizontally. Also, landing wrong can cause the cloth to detonate.

The jumping problem is caused by the cloth joints affecting the inertia of the character. Simply moving the cloth outside of the character model solved the problem.

Tried this, but it works rather poorly. The cloth doesn’t respond to limb movement very well, so it still clips right through. A combination of reducing limb animation and increasing the number of chains might help.

Light mode

The reason you dislike light mode is because your room doesn’t get enough sunlight.

Export

One pattern I’ve been using lately is naming the table returned by modules “export” instead of the module name. This creates a similarity to exporting types, and also frees up the module name to be used for something else (usually a metatable).

Reactive graphs

Thinking about APIs.

One idea was using add/sub to compose sets of symbol types, such as Prop "Name"-Set for a read-only property node, or Receiver+Signal "Activated" for a signal with a receiver. The Get/Set symbols would then be usable with Nodes to control direction. I’m not sure how I feel about it, because it would enable weird things like Prop "Foo" + Attr "Bar".


Prototyping. Nothing actually graphy yet. “Prop” does get repetitive, so it definitely needs a “Properties” tag that receives a dictionary.

Inst isn’t built in the to core (“Graf”). Instead, the core defines interfaces, and Inst is just an implementation that operates on instances. Bind does the heavy lifting of making data flow.

Bind returns the instance, along with a list of tasks to be finalized somewhere. Schedule just sets these tasks to be finalized when the instance is destroyed. Context returns a resolver that converts things like Prop"Name" into actual state.

Implementing recursion. A context can resolve a sink (stuff on the left) into another context, which must receive a map as a source (stuff on the right). In this example, Properties becomes a context that converts string sinks into property setters in addition to the usual stuff.

NFTs

An NFT is a string of bytes. Some authority invented out of thin air then makes the unenforceable claim that these bytes are associated with something else in a vain attempt to give them value. After that it’s just the usual trading of fake items in a fake market with fake money.

Given that the value of these items hinge completely on this authority anyway, the blockchain part (and all the dumb shit that goes with it) can be skipped entirely. This is how Roblox works.

The real point of interest is whether the fake money can be exchanged for real money. In Roblox’s case, the fake money earned from the sales of fake items cannot be exchanged for real money. However, it can be used indirectly towards earning “clean” money that can be exchanged.

Search engines

The current state of search engines: I do a search for “firefox import profile” and the top result is a health website titled “Import Browser Settings Firefox Cancer”. Next result is a cooking website titled “Import Firefox Settings Best Recipes”.