Использование существующей текстуры opengl с набором сценариев

Согласно документации Apple, вы можете использовать NSColor, NSImage и CALayer для предоставления текстуры SCNMaterialProperty. SCNMaterialProperty

Однако мне интересно, есть ли способ предоставить существующую текстуру OpenGL, которая была создана с помощью glGenTextures и отрисована отдельно.

Я, конечно, могу прочитать буфер текстуры, настроить NSImage и передать его в SCNMaterialProperty; но по соображениям производительности это явно не оптимально.

Было бы разумно реализовать вышеизложенное, переопределив программу (программы) шейдера материала, я думаю, но документации для этого, похоже, не существует.


person simonfi    schedule 05.09.2013    source источник


Ответы (2)


Вы можете переопределить программы шейдеров, назначив материалу SCNProgram. Затем в одном из методов делегата для SCNProgramDelegate вы можете привязать свои собственные значения для текстуры (и других униформ). Однако вам придется написать свои собственные шейдеры.

Есть небольшая настройка, если вы привыкли к Objective-C, но на самом деле это не так уж много, если подумать о соответствующем коде OpenGL.

Ниже приведен пример шейдерной программы, которая привязывает текстуру к поверхности геометрического объекта. Для простоты он не затеняет нормали и источники света.

Обратите внимание, что я не знаю, как вы хотите связать свою конкретную текстуру, поэтому в приведенном ниже коде я читаю png с помощью GLKit и использую эту текстуру.

// Create a material
SCNMaterial *material = [SCNMaterial material];

// Create a program
SCNProgram *program = [SCNProgram program];

// Read the shader files from your bundle
NSURL *vertexShaderURL   = [[NSBundle mainBundle] URLForResource:@"yourShader" withExtension:@"vert"];
NSURL *fragmentShaderURL = [[NSBundle mainBundle] URLForResource:@"yourShader" withExtension:@"frag"];
NSString *vertexShader = [[NSString alloc] initWithContentsOfURL:vertexShaderURL
                                                        encoding:NSUTF8StringEncoding
                                                           error:NULL];
NSString *fragmentShader = [[NSString alloc] initWithContentsOfURL:fragmentShaderURL
                                                          encoding:NSUTF8StringEncoding
                                                             error:NULL];
// Assign the shades 
program.vertexShader   = vertexShader;
program.fragmentShader = fragmentShader;

// Bind the position of the geometry and the model view projection
// you would do the same for other geometry properties like normals
// and other geometry properties/transforms.
// 
// The attributes and uniforms in the shaders are defined as:
// attribute vec4 position;
// attribute vec2 textureCoordinate;
// uniform mat4 modelViewProjection;    
[program setSemantic:SCNGeometrySourceSemanticVertex
           forSymbol:@"position"
             options:nil];
[program setSemantic:SCNGeometrySourceSemanticTexcoord
           forSymbol:@"textureCoordinate"
             options:nil];
[program setSemantic:SCNModelViewProjectionTransform
           forSymbol:@"modelViewProjection"
             options:nil];


// Become the program delegate so that you get the binding callback
program.delegate = self;

// Set program on geometry
material.program = program; 
yourGeometry.materials = @[material];

В этом примере шейдеры записываются как

// yourShader.vert
attribute vec4 position;
attribute vec2 textureCoordinate;
uniform mat4 modelViewProjection;

varying vec2 texCoord;

void main(void) {
    // Pass along to the fragment shader
    texCoord = textureCoordinate;

    // output the projected position
    gl_Position = modelViewProjection * position;
}

А также

// yourShader.frag
uniform sampler2D yourTexture;
varying vec2 texCoord;

void main(void) {
    gl_FragColor = texture2D(yourTexture, texCoord);
}

Наконец, реализация метода ...bindValueForSymbol:... для привязки текстуры к униформе "yourTexture".

- (BOOL)    program:(SCNProgram *)program
 bindValueForSymbol:(NSString *)symbol
         atLocation:(unsigned int)location
          programID:(unsigned int)programID
           renderer:(SCNRenderer *)renderer
{
    if ([symbol isEqualToString:@"yourTexture"]) {
        // I'm loading a png with GLKit but you can do your very own thing
        // here to bind your own texture.
        NSError *error = nil;
        NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"sampleImage" ofType:@"png"];
        GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:imagePath options:nil error:&error];
        if(!texture) {
            NSLog(@"Error loading file: %@", [error localizedDescription]);
        }

        glBindTexture(GL_TEXTURE_2D, texture.name);

        return YES; // indicate that the symbol was bound successfully.
    }

    return NO; // no symbol was bound.
} 

Кроме того, в целях отладки очень полезно реализовать program:handleError: для вывода любых ошибок компиляции шейдера.

- (void)program:(SCNProgram*)program handleError:(NSError*)error {
    // Log the shader compilation error
    NSLog(@"%@", error);
}
person David Rönnqvist    schedule 06.09.2013
comment
Наконец-то появилось время поиграть с этим, и я просто хотел еще раз сказать спасибо! За исключением небольшой опечатки (a_textureCoordinate в вершинном шейдере), это работало отлично и намного быстрее, чем моя предыдущая реализация, которая постоянно заменяла текстуру, используя новый NSImage. Просто небольшой вопрос; как ты это понял? Документация для SceneKit пока кажется крайне ограниченной. - person simonfi; 05.10.2013

если вам нужно напрямую работать с OpenGL и привязывать свои пользовательские текстуры, то SCNProgram или делегат SCNNode - это то, что вам нужно (MountainLion или выше). Если у вас есть учетная запись разработчика Apple, образец кода можно найти здесь: http://developer.apple.com/downloads/ в разделе "Образец кода WWDC 2013". Найдите «OS_X_SceneKit_Slides_WWDC2013».

person Toyos    schedule 05.09.2013
comment
К сожалению, вам придется предоставить свои собственные шейдеры. Кроме того, SceneKit сам по себе — это Mountain Lion и выше ;) - person David Rönnqvist; 06.09.2013
comment
@Toyos какой у тебя адрес электронной почты? Хотел бы написать вам по электронной почте о проекте, если вы не возражаете. - person Crashalot; 24.06.2016