Search code examples
iosswiftmetal

Setting UV Coordinates Of Texture In Metal Programmatically Deforms Texture


In my project I am creating Vertexes programmatically which means I am filling following struct with data I am creating in application.

struct Vertex{
var position: SIMD3<Float>
var color: SIMD4<Float>
var textCoors: SIMD2<Float>
}

My objects are simple they are planes consist of two triangles.

I am creating texture coordinates with following code;

pI is the plane index. My object consists of certain number of planes.

l is the index of corner positions of planes.

It works fine if my planes are square or rectangle it places texture seamlessly.

enter image description here

But if my quadrilateral corner coordinates are not symmetrical.

enter image description here

(Square and rectangle is special case of quadrilateral) Texture is deforming.

I could not find fine solution I have some ideas like making may plane with many small squares but it feels crappy There should be better solution.

func textureRip(pI: Int, l: Int, vertex: [[SIMD3<Float>]]) -> SIMD2<Float> {
        
        var textCoor0 = SIMD2<Float>()
        
        // We have this ratio because metalview coordinate system 2x2 unit size
        // from -1 to 1 for both x and y. Texture coordinate sistem is 1 unit wide and
        // unit height. (0 to 1). So metal view twice as much bigger.
        let ratio:Float = 2
        
        // We are adding 1 to metal view values because its values begins
        // from -1 so we are shifting its coordinate system to texture coordinate
        // system along wiht ratio.
        let x0  =  (vertex[pI][0].x + 1) / ratio
        let x   =  (vertex[pI][1].x + 1) / ratio
        
        // We are using "1 -" because texture coordinate sistem origin is
        // at the top left corner and metal view coordinate system at center.
        // in that case texture look upside down so we are turning it using "1-".
        let y0  = 1 - (vertex[pI][0].y + 1) / ratio
        let y   = 1 - (vertex[pI][2].y + 1) / ratio
        
        
        if l == 0 {
            
            textCoor0 = SIMD2<Float>(x0, y0)
            
        } else if l == 1 {
            
            textCoor0 = SIMD2<Float>(x, y0)
            
        } else if l == 2 {
            
            textCoor0 = SIMD2<Float>(x, y)
            
        } else {
            
            textCoor0 = SIMD2<Float>(x0, y)
            
        }
        
        
        return textCoor0
    }

Solution

  • Well, my mistake as generally it is.

    Instead of using four corner of quadrilateral I has been using two corner data of it, as if it is going to be always square or rectangle.

    I revised func and it is not optimized as you can see I am just experimenting with Metal to see what I can do with it.

    func textureRip(pI: Int, l: Int, vertex: [[SIMD3<Float>]]) -> SIMD2<Float> {
            
            var textCoor = SIMD2<Float>()
            
            // We have this ratio because metalview coordinate system 2x2 unit size
            // from -1 to 1 for both x and y. Texture coordinate sistem is 1 unit wide and
            // unit height. (0 to 1). So metal view twice as much bigger.
            let ratio:Float = 2
            
            // We are adding 1 to metal view values because its values begins
            // from -1 so we are shifting its coordinate system to texture coordinate
            // system along wiht ratio.
            let x1  =  (vertex[pI][0].x + 1) / ratio
            let x2  =  (vertex[pI][1].x + 1) / ratio
            
            let x3  =  (vertex[pI][2].x + 1) / ratio
            let x4  =  (vertex[pI][3].x + 1) / ratio
            
             
            
            // We are using "1 -" because texture coordinate sistem origin is
            // at the top left corner and metal view coordinate system at center.
            // in that case texture look upside down so we are turning it using "1-".
            let y1  = 1 - (vertex[pI][0].y + 1) / ratio
            let y2  = 1 - (vertex[pI][1].y + 1) / ratio
            
            let y3  = 1 - (vertex[pI][2].y + 1) / ratio
            let y4  = 1 - (vertex[pI][3].y + 1) / ratio
            
            
            
            if l == 0 {
                
                textCoor = SIMD2<Float>(x1, y1)
                
            } else if l == 1 {
                
                textCoor = SIMD2<Float>(x2, y2)
                
            } else if l == 2 {
                
                textCoor = SIMD2<Float>(x3 , y3)
                
            } else {
                
                textCoor = SIMD2<Float>(x4, y4)
                
            }
            
            
            return textCoor
        }
    

    And as it can be seen, my test image looks good as texture. Every quadrilateral is separate object actually and can be moved around independently.

    enter image description here