es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Metal / Scenekit – Textura repetitiva en muestra

No estoy seguro de por qué no puedo repetir la textura al usar el shader de fragmento personalizado del cliente.

Aquí está mi fragmento:

fragment float4 bFragment( VertexOut vertexOut [[stage_in]],
                           texture2d<float, access::sample=""> textureInput [[texture(0)]],)
    {
constexpr sampler sampler2d(coord::normalized, address::repeat, filter::linear, address::repeat);

float4 outputColor;
outputColor = textureInput.sample(sampler2d, vertexOut.texCoord);

return float4(outputColor.x , outputColor.y , outputColor.z , 1.0);

}

Así es como paso la textura:

let imageProperty = SCNMaterialProperty(contents: texture)
imageProperty.wrapS  = .repeat
imageProperty.wrapT  = .repeat
imageProperty.contentsTransform = SCNMatrix4MakeScale(screenRatio * numberOfRepetitionsOnX, numberOfRepetitionsOnX , 1)
node.geometry!.firstMaterial!.setValue(imageProperty, forKey: "textureInput")

La imagen no se repite, solo se sujeta al objeto, sin importar el tamaño de la textura.

Si uso la misma configuración SIN un shader personalizado:

let myMaterial = SCNMaterial()
myMaterial.lightingModel = .constant
myMaterial.diffuse.contents = texture 
myMaterial.diffuse.wrapS = .repeat
myMaterial.diffuse.wrapT = .repeat
myMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(screenRatio * numberOfRepetitionsOnX, numberOfRepetitionsOnX , 1)
node.geometry!.firstMaterial! = myMaterial

La textura se repite correctamente.

Preguntas:

  1. ¿Qué tengo que cambiar para que sea efectivo el valor de contentsTransform también al usar el sampler en el shader de fragmento personalizado?
  2. Si eso no es posible, ¿cuál es la manera más fácil de lograrlo? (Escalar, repetir, volver a dibujar la textura no es una opción).

Gracias.</float,>

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Basado en el código proporcionado, parece que el problema podría ser con el valor de contentsTransform. En el fragment shader personalizado, la textura se pasa como texture2d y el muestreador se define con address::repeat tanto para las direcciones S como para las T. Sin embargo, el valor de contentsTransform solo se aplica al usar SCNMaterialProperty en el enfoque de shader no personalizado.

    Para lograr el mismo efecto en el enfoque de shader personalizado, puede pasar el valor de contentsTransform como un uniforme y aplicarlo en el fragment shader. Aquí hay un código actualizado del fragment shader que incluye el uniforme contentsTransform:

    fragment float4 bFragment( VertexOut vertexOut [[stage_in]],
                               texture2d<float, access::sample=""> textureInput [[texture(0)]],
                               constant SCNMatrix4& contentsTransform [[buffer(1)]])
    {
        constexpr sampler sampler2d(coord::normalized, address::repeat, filter::linear, address::repeat);
    
        float2 transformedTexCoord = float2(vertexOut.texCoord.x, vertexOut.texCoord.y)*contentsTransform.m00z + contentsTransform.m30zxy;
    
        float4 outputColor;
        outputColor = textureInput.sample(sampler2d, transformedTexCoord);
    
        return float4(outputColor.x , outputColor.y , outputColor.z , 1.0);
    }
    

    En este código, el uniforme contentsTransform se pasa como un buffer con índice 1 y se aplica a la coordenada de textura antes de muestrear la textura. Los valores de escala y desplazamiento se extraen de la matriz de contentsTransform y se aplican al valor de texCoord.

    Para pasar el valor de contentsTransform desde el código Swift, puede agregar el siguiente código:

    let transform = SCNMatrix4MakeScale(screenRatio * numberOfRepetitionsOnX, numberOfRepetitionsOnX , 1)
    let contentsTransform = SCNMatrix4ToMat4(transform)
    let contentsTransformBuffer = device.makeBuffer(bytes: &contentsTransform, length: MemoryLayout<scnmatrix4>.stride, options: [])
    

    Este código crea un SCNMatrix4 con los valores de escala y desplazamiento deseados, lo convierte en un SCNMatrix4, y crea un búfer con ese valor. Luego, puede establecer este búfer como el uniformBuffer del material que está utilizando el shader personalizado:

    let material = SCNMaterial()
    material.shaderModifiers = [
        .fragment: "tu código de shader personalizado",
    ]
    material.setValue(contentsTransformBuffer, forKey: "contentsTransform")
    

    Esto debería pasar el valor de contentsTransform al shader personalizado y aplicarlo a las coordenadas de textura, dando como resultado una textura repetida.</float,>

Comments are closed.