What are you working on currently? (2022)

another build I’ll never touch again

12 Likes

not sure if I ever posted this, but here’s a spay can I made ages ago lol

9 Likes

Love the clean look on this. :slight_smile:

Cel Shading v2.0 demonstration

Join the discussion (tutorial here):
https://devforum.roblox.com/t/how-would-you-approach-cel-shading-in-roblox/1790336

20 Likes

since nobody reads on the original topic i posted, here’s some nurse spittin

3 Likes

i just finished this church.

Blender



Roblox



9 Likes

Mercedes-Benz S 500 4Matic: Front Finished

14 Likes

Thank you so much! Very much appreciated. I personally just used shadowmap, lowered ambience, and messed with the Lighting Effects. I also made sure to use light fixtures with surfacelights only, and used these as a primary source of lighting.

2 Likes

Gives me Genshin Impact energy, very nice! You’re clearly very talented when it comes to texturing.

1 Like

looks spectacular! i’m an international school student myself (different country)

Making more random stuff to stall on what I’m actually “supposed” to be doing. This is a really simple script that changes the OutdoorAmbient and ColorShift_Top to a random color at a given interval.

This is the code behind it. Anyone who has any knowledge of scripting whatsoever should be able to determine how it works… just input the BPM of whatever song you’re listening to and go.

while true do
	local bpm = 160 -- Change this value to whatever you want!
	local bpmformula = (1/(bpm/60))
	
	local lighting = game:GetService("Lighting")
	local color = Color3.fromRGB((math.random(1,255)),(math.random(1,255)),(math.random(1,255)))
	
	lighting.OutdoorAmbient = color
	lighting.ColorShift_Top = color
	wait(bpmformula)
	
end

I think what I want to do next is implement multiple modes, with this being the “classic” mode and another mode having less frequent color changes, but the colors lerp(??? tween??? I’m not familiar with this terminology) between each other making for a smoother effect.

I also want to make this GUI-based so I don’t have to dig around in the Properties window to check on it.

4 Likes

I modeled two vehicles last night
image







33 Likes

Jungle dungeon

16 Likes

Update on my previous post.

This is the code so far. Feel free to tell me how to improve it.

local BPM = 120
local waitTime = 0.5
local textBox = script.Parent.TextBox

textBox.FocusLost:Connect(function(enterPressed)
	local newBPM = textBox.Text

	if enterPressed then
		if newBPM == nil then
			BPM = 120
			waitTime = 0.5
		else
			BPM = math.clamp(newBPM,1,400)
			waitTime = 1/(BPM/60)
		end
	end

	textBox.Text = ""
	print(BPM)
	
end)

	while true do
		local lighting = game:GetService("Lighting")
		local color = Color3.fromRGB(math.random(1,255),math.random(1,255),math.random(1,255))
		
		local label = script.Parent.TextLabel
		
		label.BackgroundColor3 = color
		label.Text = tostring(math.floor(color.R*255))..", "..tostring(math.floor(color.G*255))..", "..tostring(math.floor(color.B*255))

		lighting.OutdoorAmbient = color
		lighting.ColorShift_Top = color

		wait(waitTime)

	end
4 Likes

You should use task.wait(n) as it is more efficient and performant than wait(n), and you should reference services and other variables outside of loops for performance reasons:

--//Services
local Lighting = game:GetService("Lighting")

--//Variables
local textBox = script.Parent.TextBox
local label = script.Parent.TextLabel

--//Controls
local BPM = 120
local waitTime = 0.5

--//Intialization
local newRandom = Random.new()

--//Functions
textBox.FocusLost:Connect(function(enterPressed)
	local newBPM = textBox.Text

	if enterPressed then
		if newBPM then
			BPM = math.clamp(newBPM, 1, 400)
			waitTime = 1/(BPM/60)
		else
			BPM = 120
			waitTime = 0.5
		end
	end

	textBox.Text = ""
	print(BPM)
end)

while true do
	local color = Color3.fromRGB(newRandom:NextInteger(1, 255), newRandom:NextInteger(1, 255), newRandom:NextInteger(1, 255))
	label.BackgroundColor3 = color
	label.Text = tostring(tostring(math.floor(color.R*255))..", "..tostring(math.floor(color.G*255))..", "..tostring(math.floor(color.B*255)))

	Lighting.OutdoorAmbient = color
	Lighting.ColorShift_Top = color

	task.wait(waitTime)
end

(looks pretty cool though)

1 Like

Yep, like it’s still in the 80’s… something to remember





27 Likes

Thank you for the advice! By the way, what’s the difference between calling Random.new and using math.random? Just curious

I personally just use Random.new() as it has more functions and more customizability. Also because most of the backend of math.random was taken from Random.new() as far as I know.

1 Like

That’s actually the exact video I watched to make this, I just had no idea how to recreate the global illumination.

Yes I do. it’s actually the only property for the objects in the world (aside from colour of course). I use the roughness value to spread the rays out and to merge colours together for reflections.

local OffsetAngle = math.pi * Roughness

MirroredColour = MirroredColour:Lerp(OriginalColor, Roughness)

I don’t have a metallicness property for the materials.

The light source doesn’t really have a brightness property. The light colour is a single color3 value that just get’s multiplied depending on hit objects and light angle, as explained in the video for the shadows.


If you want to know more, you can have a look at my process reflection function:

function ProcessReflection(Roughness, Normal, IntersectPos, Direction, OriginalColor, CurrentBounces, InitialReflection) -- Per pixel function
	if not ReflectionsEnabled or CurrentBounces > MaxReflectionBounces then
		return OriginalColor
	end

	CurrentBounces += 1

	local ReflectedDirection = Direction - (2 * Direction:Dot(Normal) * Normal) -- Relfect the direction.
	ReflectedDirection = ReflectedDirection * RenderDistance -- New reflected direction

	local ReflectedDirectionCFrame = CFrame.new(ReflectedDirection)

	local OffsetAngle = MaxReflectionAngle * Roughness

	local HitColours = {}

	local MirroredColour
	
	for i = 1, RaySamplesPerPixel do
		local OffsetReflectedDirection = CFrame.Angles(RanAxis(OffsetAngle), RanAxis(OffsetAngle), RanAxis(OffsetAngle)) * ReflectedDirectionCFrame.Position

		local ReflectionRay = workspace:Raycast(IntersectPos, OffsetReflectedDirection)

		local ReflectedColour

		if ReflectionRay then
			local HitPart = ReflectionRay.Instance
			if HitPart ~= LightSource then
				local HitNormal = ReflectionRay.Normal
				local IntersectionPos = ReflectionRay.Position + (HitNormal / 1000)

				ReflectedColour = HitPart.Color

				ReflectedColour = ProcessShadows(ReflectedColour, OffsetReflectedDirection, IntersectionPos, HitNormal)
                -- Recursive reflections
				ReflectedColour = ProcessReflection(GetPartRoughness(HitPart), HitNormal, IntersectionPos, OffsetReflectedDirection, ReflectedColour, CurrentBounces)
			else
				ReflectedColour = LightColour -- Light source colour
			end
		else
			ReflectedColour = Black -- No light
		end

		--HitColours[i] = ReflectedColour
		table.insert(HitColours, ReflectedColour)
		
		if not InitialReflection then
			break
		end
	end
	
	MirroredColour = GetAverageColour(HitColours)
	
	--if not InitialReflection then
	MirroredColour = MirroredColour:Lerp(OriginalColor, Roughness)
	--MirroredColour = MultiplyColourByColour(MirroredColour, OriginalColor)
	--end

	return MirroredColour 
end

My places «Abandoned Factory» started in 2020, and «Forbidden Zone» started in 2022.



19 Likes