-- How many textures of different types are available, with sizes and offsets in the atlas local CloudTextures = { Blurry = { group = 'b', count = 16, start = vec2(0, 0/8), size = vec2(2/16, 1/8) }, Hovering = { group = 'h', count = 16, start = vec2(0, 2/8), size = vec2(2/16, 1/8) }, Spread = { group = 's', count = 6, start = vec2(0, 4/8), size = vec2(2/16, 1/8) }, Flat = { group = 'f', count = 5, start = vec2(0, 6/8), size = vec2(2/16, 1/8) }, Bottoms = { group = 'd', count = 5, start = vec2(0, 7/8), size = vec2(1/16, 1/8) }, } -- Various helper functions for clouds local cloudutils = {} function cloudutils.setPos(cloud, params) params = params or {} local height = params.height or (100 + math.random() * 200) local sizeMult = params.size or 1 local aspectRatio = params.aspectRatio or 0.5 local distanceMult = params.distance or 10 local pos = params.pos and params.pos:clone():normalize() or math.randomVec2():normalize() cloud.size = vec2(100, 100 * aspectRatio) * sizeMult * (1 + 0.5 * math.random()) * distanceMult cloud.position = vec3(400 * pos.x, height, 400 * pos.y) * distanceMult cloud.horizontal = params.horizontal or false cloud.customOrientation = params.customOrientation or false cloud.noTilt = params.noTilt or false cloud.procScale = vec2(1.0, (params.horizontal and 1 or 1.2) * aspectRatio) * (params.procScale or 1) * sizeMult end function cloudutils.setTexture(cloud, type) local index = math.floor(math.random() * type.count) if CloudUseAtlas then local start = type.start:clone() for i = 1, index do start.x = start.x + type.size.x if start.x >= 1 then start.x = start.x - 1 start.y = start.y + type.size.y end end cloud.texStart:set(start) cloud.texSize:set(type.size) cloud:setTexture('clouds/atlas.dds') else cloud:setTexture('clouds/' .. type.group .. index .. '.png') end cloud.flipHorizontal = math.random() > 0.5 return index end function cloudutils.setProcNormalShare(cloud, globalShare, totalIntensity) globalShare = globalShare or 0.5 totalIntensity = totalIntensity or 1 cloud.procNormalScale = vec2((1 - globalShare) * totalIntensity, globalShare * totalIntensity) end -- Different types of clouds CloudTypes = {} function CloudTypes.Basic(cloud, pos) cloudutils.setTexture(cloud, CloudTextures.Blurry) cloud.procMap = vec2(0.6, 0.85) + math.random() * 0.15 cloud.procSharpnessMult = math.random() cloudutils.setProcNormalShare(cloud, 0.6) cloudutils.setPos(cloud, { pos = pos, size = (1 + math.random()) * 2, procScale = 0.45 }) end function CloudTypes.Dynamic(cloud, pos) local typeRandom = math.random() local fidelityRandom = math.random() local sizeRandom = math.random() if typeRandom > 0.95 then -- Let’s increase variety some more cloudutils.setTexture(cloud, CloudTextures.Hovering) elseif typeRandom > 0.9 then cloudutils.setTexture(cloud, CloudTextures.Spread) else cloudutils.setTexture(cloud, CloudTextures.Blurry) end cloud.occludeGodrays = true cloud.procMap = vec2(0.6, 0.9) cloud.procSharpnessMult = math.lerp(0, 0.5, fidelityRandom) cloud.extraFidelity = math.lerp(0.7, 0.3, fidelityRandom) cloud.receiveShadowsOpacityMult = 1 cloudutils.setProcNormalShare(cloud, math.lerp(1, 0.7, fidelityRandom), 1.5) local cloudSize = math.lerp(2, 5, sizeRandom) * CloudSpawnScale cloudutils.setPos(cloud, { pos = pos, size = cloudSize, procScale = math.lerp(1.6, 1.2, fidelityRandom) / cloudSize }) cloud.extras.procMap = cloud.procMap:clone() cloud.extras.procScale = cloud.procScale:clone() cloud.extras.nearbyCutoffOffset = math.lerp(-0.3, 0.3, math.random()) cloud.extras.extraFidelity = cloud.extraFidelity cloud.extras.lowerK = math.lerpInvSat(pos.y, DynCloudsMaxHeight, DynCloudsMinHeight) end function CloudTypes.Bottom(cloud, mainCloud) cloudutils.setTexture(cloud, CloudTextures.Bottoms) cloud.occludeGodrays = true cloud.horizontal = true cloud.horizontalHeading = math.random() * 360 cloud.procScale:set(0.8, 0.8) cloud.procMap = mainCloud.procMap * vec2(0.8, 1) cloud.procSharpnessMult = mainCloud.procSharpnessMult cloud.extraFidelity = mainCloud.extraFidelity local size = (mainCloud.size.x + mainCloud.size.y) / 2 cloud.size:set(size, size) cloudutils.setProcNormalShare(cloud, 0.2, 1.8) cloud.material = CloudMaterials.Bottom cloud.receiveShadowsOpacityMult = mainCloud.receiveShadowsOpacityMult end function CloudTypes.Hovering(cloud, pos) cloudutils.setTexture(cloud, CloudTextures.Hovering) cloud.procMap = vec2(0.5, 0.9) + math.random() * 0.15 cloud.procSharpnessMult = 0 cloud.extraFidelity = 0.6 cloudutils.setProcNormalShare(cloud, 0.2, 2) cloudutils.setPos(cloud, { pos = pos, horizontal = true, size = math.lerp(8, 12, math.random()) * CloudSpawnScale, procScale = 0.2 / CloudSpawnScale }) cloud.horizontalHeading = -1 cloud.material = CloudMaterials.Hovering cloud.extras.extraFidelity = cloud.extraFidelity cloud.opacity = cloud.opacity * 0.5 end function CloudTypes.Spread(cloud, pos) cloudutils.setTexture(cloud, CloudTextures.Spread) cloud.procMap = vec2(0.4, 1) cloud.procSharpnessMult = 0 cloud.extraFidelity = 1 cloudutils.setProcNormalShare(cloud, 0.2) local isSpread = math.random() > 0.5 cloudutils.setPos(cloud, { pos = pos, horizontal = true, size = math.lerp(4, 6, math.random()) * CloudSpawnScale, procScale = 0.1 / CloudSpawnScale, aspectRatio = 0.33 }) cloud.horizontalHeading = -1 cloud.material = CloudMaterials.Spread cloud.procScale:mul(vec2(1, 4)) cloud.opacity = math.lerp(0.15, 0.35, math.random()) cloud.extras.extraFidelity = cloud.extraFidelity end function CloudTypes.Low(cloud, pos, distance) local index = cloudutils.setTexture(cloud, CloudTextures.Flat) local heightFixes = { 0, 4, -10 } cloud.occludeGodrays = true cloud.procMap = vec2(0.65, 0.95) cloud.procSharpnessMult = math.random() * 0.5 cloud.extraFidelity = 1.2 cloud.color = rgb(1, 1, 1) cloud.opacity = 0.8 -- cloud.fogMultiplier = 5 cloud.orderBy = 1e12 + distance * 1e10 cloud.extras.opacity = cloud.opacity cloud.extras.extraFidelity = cloud.extraFidelity cloud.extras.randomOffset = math.atan2(pos.x, pos.y) cloud.extras.procMap = cloud.procMap:clone() cloudutils.setProcNormalShare(cloud, 0.2, 2) cloudutils.setPos(cloud, { pos = pos, height = CalculateHorizonCloudYCoordinate(pos:clone():normalize()) - 5 * distance + (heightFixes[index + 1] or 0), distance = 50 + distance, size = 1.3, aspectRatio = 0.3 }) cloud.receiveShadowsOpacityMult = 0 end function CloudTypes.Test(cloud, pos, distance) local index = cloudutils.setTexture(cloud, CloudTextures.Bottoms) cloud.occludeGodrays = true cloud.procMap = vec2(0.65, 0.85) cloud.procSharpnessMult = 0 cloud.extraFidelity = 0 cloud.color = rgb(1, 1, 1) cloud.opacity = 1 cloud.orderBy = 0 cloud.cutoff = 0 cloudutils.setProcNormalShare(cloud, 0, 2) cloudutils.setPos(cloud, { pos = pos, size = 7, procScale = 1 }) cloud.receiveShadowsOpacityMult = 0 end