I’ve been struggling to get a 256x256 image textured onto a custom geometry I have.
There are many questions that have great answers like artificially creating the UV map for the custom geometry. However these answers are all pre 2017 and I am too stoopid to implement the solution with the new way of storing geometry information as attributes (uv, position, normal).
I have a nice texture but it only displays as what seems to be the mean colour of the image…
//First loading the points centered around the origin
//coorAroundOrigin has 13 points
let vertices = []
for(let k = 0;k < coorAroundOrigin.length;k++){
vertices.push(new THREE.Vector2( coorAroundOrigin[k].x , coorAroundOrigin[k].y ))
}
vertices.push(new THREE.Vector2( coorAroundOrigin[0].x , coorAroundOrigin[0].y ))
let geo = new THREE.ShapeBufferGeometry(new THREE.Shape(vertices))
//Now the material
//SLIME_TEXTURE is a material that has a map of a 256x256 image that is definitely loaded -only displays as a solid colour though
let final_mesh = new THREE.Mesh(geo , SLIME_TEXTURE)
scene.add(final_mesh )
Thanks @hofk looking at the circle geometry set me on the right path - almost got my slime texture contorting how it should be based on the changing vertices:
Here’s the algorithm - it’s very similar to circle geometry except you start with points and the radius is calculated differently:
//Function for generating geometries from points
function getGeometryFromSetOfPoints(points){//[vertx1, vertex2, vertex3, ...] *** Centered around (0, 0, 0)
const newGeometry = new THREE.BufferGeometry();
//Get the min / max of x and y from the points (used in place of radius that's usually given to circle geometry constructor)
let minX=0,minY=0,maxX=0,maxY=0;
for(let i = 0; points.length && points[i];i++){
minX=Math.min(minX, points[i].x)
minY=Math.min(minY, points[i].y)
maxX=Math.max(maxX, points[i].x)
maxY=Math.max(maxY, points[i].y)
}
let rangeX = maxX - minX
rangeX /= 2
let rangeY = maxY - minY
rangeY /= 2
//Buffers that the geometries attributes will be set to
const indices = [];
const vertices = [];
const normals = [];
const uvs = [];
// helper variables
const uv = new THREE.Vector2();
// =*Circular design*=
//Add center point
vertices.push( 0, 0, 0 );
normals.push( 0, 0, 1 );
uvs.push( 0.5, 0.5 );
//Each iteration of the loop will be a "segment" from the circle example
for(let i = 0;i <= points.length;i++){
//Add corresponding vertex
vertices.push(points[i%points.length].x, points[i%points.length].y, 0)
//Add correspoding normal
normals.push( 0, 0, 1 );
//Add correspoding uvs
let indexOfVertexToUse = vertices.length - 3
uv.x = ( vertices[ indexOfVertexToUse ] / rangeX + 1 ) / 2;
uv.y = ( vertices[ indexOfVertexToUse + 1 ] / rangeY + 1 ) / 2;
uvs.push( uv.x, uv.y )
}
//Indices
for(let i = 1; i <= points.length;i++){
indices.push( i, i + 1, 0 );
}
//Finally build geometry
newGeometry.setIndex(indices)
newGeometry.setAttribute("position", new THREE.Float32BufferAttribute( vertices, 3 ) );
newGeometry.setAttribute("normal", new THREE.Float32BufferAttribute( normals, 3 ) );
newGeometry.setAttribute("uv", new THREE.Float32BufferAttribute( uvs, 2 ) );
return newGeometry
}
Last problem is one slice per slime now
^^^*Edit : fixed the code now