@UberGoober @dave1707 - here is an approach for textured spheres/icosahedron which uses a shader. Written by @Muffincoder which allows reduction of sides and panels. It may help translate vertices to texture maps as the top and bottom of the sphere are well defined
function setup()
--
--[[ Sphere generator v1
This is an app made in Codea written by Muffincoder on Codeas' forum
You may use this code for whatever you like, I would be glad to see
whatever you come up with using this or use this for.
Also note that the algorithm I came up with is not optimal, it works, that's it.
If you improve the algorithm then please tell me what and how you did it.
This was purely a fun project that I created on my pastime. Enjoy!
]]
-- Definitions of the amount of fragments vertically and horizontally
segmentsH = 100
segmentsV = 30
size = 100 -- The radius of the sphere
-- This is the texture for the sphere, use a rectangular texture for example an image of earth.
texture = "Documents:earth"
-- Also note that the sphere can be either colored with random colors or textured
-- This is made possible with the use of 2 shaders, one for pure color and one basic texture shader
colorOnlyShader = shader([[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
varying lowp vec4 vColor;
void main()
{
vColor = color;
gl_Position = modelViewProjection * position;
}
]],[[
precision highp float;
varying lowp vec4 vColor;
void main()
{
gl_FragColor = vColor;
}
]])
textureShader = shader([[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
vColor = color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],[[
precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying lowp vec2 vTexCoord;
void main()
{
lowp vec4 col = texture2D(texture, vTexCoord) * vColor;
gl_FragColor = col;
}
]])
-- Variable init
meshS = mesh()
verts = {}
vertices = {}
colors = {}
texels = {}
texCoords = {}
parameter.integer("segmentsH",5,150,segmentsH)
parameter.integer("segmentsV",3,150,segmentsV)
parameter.action("generateSphere",generateSphere)
parameter.boolean("randomColors",true)
parameter.integer("dist",-1000,0,-350)
parameter.integer("rotX",0,360,0)
parameter.integer("rotY",0,360,0)
parameter.integer("rotZ",0,360,0)
generateSphere()
end
function generateSphere()
--
-- Calculate how big of an angle each fragment of the sphere has
local segmentHangle = (2*math.pi)/segmentsH
local segmentVangle = (math.pi/(segmentsV+1))
-- Reset arrays if set already, or initialize them if this is the first run
meshS = mesh()
verts = {}
vertices = {}
colors = {}
texels = {}
texCoords = {}
--First part is to generate each unique vertex for the sphere
--Starting with the topmost vertex
table.insert(verts,vec3(0,size,0))
table.insert(texels,vec2(0.5,1.0))
for i=1,segmentsV do
local texelY = 1-(i / segmentsV)*((segmentsV-1)/segmentsV)
for j=1,segmentsH do
--Radius parameter exposed for easier manipulation of the surface
-- you can for example add some noise here to make the surface 'grainy'
local length = size
local posX = math.cos(j*segmentHangle)*length*math.cos(math.pi/2 + (i*segmentVangle))
local posZ = math.sin(j*segmentHangle)*length*math.cos(math.pi/2 + (i*segmentVangle))
local posY = math.sin(math.pi/2 + (i*segmentVangle))*length
local texelX = 1-(j / segmentsH)
table.insert(verts,vec3(posX,posY,posZ))
table.insert(texels,vec2(texelX,texelY))
end
end
-- And ending with the bottom vertex
table.insert(verts,vec3(0,-size,0))
table.insert(texels,vec2(0.5,0.0))
print("Nr of unique vertices: "..#verts)
print("Nr of unique texels: "..#texels)
-- Then generate the mesh out of the unique vertices
for i=1,#verts do
--[[I split the sphere into 3 parts;
A Top part, a middle part and a bottom part.
-The top and bottom ones are pretty much the same but the latter turned upside down.
-The top vertex and the first ring of vertices assemble a circle using
triangles that all share the top vertex. The same for the bottom part.
-The middle part is just a mesh of the remaining vertices
]]
-- Top part
if i == 1 then
for j=1,segmentsH-1 do
local curIndex = i + j
table.insert(vertices,verts[i])
table.insert(vertices,verts[curIndex+1])
table.insert(vertices,verts[curIndex])
table.insert(texCoords,texels[i])
table.insert(texCoords,texels[curIndex+1])
table.insert(texCoords,texels[curIndex])
end
table.insert(vertices,verts[i])
table.insert(vertices,verts[i+1])
table.insert(vertices,verts[i+segmentsH])
table.insert(texCoords,texels[i])
table.insert(texCoords,texels[i+1])
table.insert(texCoords,vec2(1.0,texels[i+segmentsH].y))
i = i + segmentsH
-- Middle part
elseif i > segmentsH and i < #verts then
local lastRow = i - segmentsH
local thisRow = ((i-1) % segmentsH)+1
if lastRow > 1 then
table.insert(vertices,verts[i])
table.insert(vertices,verts[lastRow+1])
table.insert(vertices,verts[lastRow])
if thisRow == 1 then
table.insert(texCoords,vec2(1.0,texels[i].y))
table.insert(texCoords,texels[lastRow+1])
table.insert(texCoords,vec2(1.0,texels[lastRow].y))
else
table.insert(texCoords,texels[i])
table.insert(texCoords,texels[lastRow+1])
table.insert(texCoords,texels[lastRow])
end
end
if i+1 < #verts then
table.insert(vertices,verts[i])
table.insert(vertices,verts[i+1])
table.insert(vertices,verts[lastRow+1])
if thisRow == 1 then
--table.insert(texCoords,vec2(1.0,texels[lastRow].y))
table.insert(texCoords,vec2(1.0,texels[i].y))
table.insert(texCoords,texels[i+1])
table.insert(texCoords,texels[lastRow+1])
else
table.insert(texCoords,texels[i])
table.insert(texCoords,texels[i+1])
table.insert(texCoords,texels[lastRow+1])
end
end
-- Bottom part
if i == (#verts-segmentsH) then
for j=1,segmentsH-1 do
local curIndex2 = i + j
table.insert(vertices,verts[#verts])
table.insert(vertices,verts[curIndex2])
table.insert(vertices,verts[curIndex2-1])
table.insert(texCoords,texels[#verts])
table.insert(texCoords,texels[curIndex2])
table.insert(texCoords,texels[curIndex2-1])
end
table.insert(vertices,verts[#verts])
table.insert(vertices,verts[#verts-1])
table.insert(vertices,verts[#verts-segmentsH])
table.insert(texCoords,texels[#verts])
table.insert(texCoords,vec2(1.0,texels[#verts-1].y))
table.insert(texCoords,texels[#verts-segmentsH])
i = i + segmentsH
end
end
end
meshS.vertices = vertices
meshS.texCoords = texCoords
if randomColors then
for i=1,#vertices,3 do-- Color each triangle with a different color
randomCol(3)
end
meshS.colors = colors
meshS.shader = colorOnlyShader
meshS.texture = ""
else
meshS:setColors(255,255,255,255)
meshS.texture = texture
meshS.shader = textureShader
end
print("Final mesh vertex count: "..#vertices)
print("Color array length: "..#colors)
print("Tex-coord array length: "..#texCoords)
print("---------")
end
function draw()
--
background(0, 0, 0, 255)
fill(255, 255, 255, 255)
camera(0,0,5, 0,0,0, 0,1,0) -- Camera setup
perspective(45,WIDTH/HEIGHT,0.1,10000)
translate(0,0,dist) -- Translate the sphere a bit into the screen
rotate(rotX,1,0,0) -- And rotate the object
rotate(rotY+ElapsedTime*10,0,1,0)
rotate(rotZ,0,0,1)
meshS:draw() -- Draw sphere
end
function randomCol(n)
local col = vec4(math.random(),math.random(),math.random(),1.0)
for q=1,n do
table.insert(colors,col)
end
end