need help with using multi-texture in pfx

I’m using a POD file with shaders in a PFX file. I’ve got a model of a car, which I have a base texture applied. I am trying to apply some decals to the car, by blending another texture onto the base. I’m seriously having problems though as I can’t figure out how exactly to do this. I know it’s possible as the Alpha Blend example uses transparency in the 1st quad. The problem is, I can’t figure out how to accomplish the same technique using shaders that are defined in the pfx.



Here’s how my render mesh and draw mesh are defined:




  • (void) renderMeshes:(SPODNode )pNode withIndex:(int)index andEffect:(GLuint)uiFXID

    {





    // Gets the node model matrix

    PVRTMat4 mWorld;

    PVRTMat4 mWorldView;



    mWorld = _broncoScene.GetWorldMatrix(pNode);



    mWorld = [self sizeTiresAndWheels:index axis:mWorld node:pNode withIndex:index];



    mWorld = [self applySuspensionLift:index axis:mWorld];



    SPODMaterial
    pMaterial = &_broncoScene.pMaterial[pNode->nIdxMaterial];



    mWorldView = _viewMatrix * _rotationX * mWorld;





    // Set the blend mode

    // Based in the info stored in the material by PVRShaman.

    // We check whether the blend mode is ‘opaque’ (ONE,ZERO).

    // Otherwise we enable blending and set the corresponding operations.

    if (_broncoScene.pMaterial[pNode->nIdxMaterial].eBlendSrcRGB == ePODBlendFunc_ONE && _broncoScene.pMaterial[pNode->nIdxMaterial].eBlendDstRGB == ePODBlendFunc_ZERO)

    {

    glDisable(GL_BLEND);

    }

    else

    {

    glEnable(GL_BLEND);

    // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glBlendFunc(_broncoScene.pMaterial[pNode->nIdxMaterial].eBlendSrcRGB, _broncoScene.pMaterial[pNode->nIdxMaterial].eBlendDstRGB);

    }







    // Now process PVRShaman semantics and set-up the associated uniforms.

    const CPVRTArray& aUniforms = _pFX[uiFXID]->GetUniformArray();

    for(unsigned int j = 0; j < aUniforms.GetSize(); ++j)

    {

    switch(aUniforms[j].nSemantic)

    {

    case ePVRTPFX_UsWORLDVIEWPROJECTION:

    {

    PVRTMat4 mWVP;



    // Passes the world-view-projection matrix (WVP) to the shader to transform the vertices

    mWVP = _projectionMatrix * mWorldView;

    glUniformMatrix4fv(aUniforms[j].nLocation, 1, GL_FALSE, mWVP.f);

    }

    break;

    case ePVRTPFX_UsWORLDVIEWIT:

    {

    PVRTMat4 mWorldViewI, mWorldViewIT;



    // Passes the inverse transpose of the world-view matrix to the shader to transform the normals

    mWorldViewI = mWorldView.inverse();

    mWorldViewIT = mWorldViewI.transpose();



    PVRTMat3 WorldViewIT = PVRTMat3(mWorldViewIT);



    glUniformMatrix3fv(aUniforms[j].nLocation, 1, GL_FALSE, WorldViewIT.f);

    }

    break;

    case ePVRTPFX_UsWORLDVIEW:

    {

    glUniformMatrix4fv(aUniforms[j].nLocation, 1, GL_FALSE, _viewMatrix.f);

    }

    break;

    case ePVRTPFX_UsVIEWIT:

    {

    PVRTMat4 mViewI, mViewIT;



    /
    Passes the inverse transpose of the model-view matrix to the shader to transform the normals */

    mViewI = _viewMatrix.inverse();

    mViewIT= mViewI.transpose();



    PVRTMat3 ViewIT = PVRTMat3(mViewIT);



    glUniformMatrix3fv(aUniforms[j].nLocation, 1, GL_FALSE, ViewIT.f);

    }

    break;

    case ePVRTPFX_UsLIGHTDIREYE:

    {





    //

test...


//


// Reads the light direction from the scene.
PVRTVec4 vLightDirection;
PVRTVec3 vPos;
// vLightDirection = _broncoScene.GetLightDirection(0);
vLightDirection = PVRTVec4(0, 0, 0, 0);

vLightDirection.x = -vLightDirection.x;
vLightDirection.y = -vLightDirection.y;
vLightDirection.z = -vLightDirection.z;



/*
Sets the w component to 0, so when passing it to glLight(), it is
considered as a directional light (as opposed to a spot light).
*/
vLightDirection.w = 0;

// Passes the light direction in eye space to the shader
PVRTVec4 vLightDirectionEyeSpace;
vLightDirectionEyeSpace = _viewMatrix * vLightDirection;

glUniform3f(aUniforms[j].nLocation, vLightDirectionEyeSpace.x, vLightDirectionEyeSpace.y, vLightDirectionEyeSpace.z);
}
break;
case eCUSTOMSEMANTIC_DIFFUSECOLOUR:
{
glUniform4f(aUniforms[j].nLocation, pMaterial->pfMatDiffuse[0], pMaterial->pfMatDiffuse[1], pMaterial->pfMatDiffuse[2], 1.0f);
}
break;

}
}

//set animation

const CGFloat* components = CGColorGetComponents([self bodyColor].CGColor);

glUniform4f(glGetUniformLocation(_pFX[uiFXID]->GetProgramHandle(), "diffuseColor"),components[0], components[1], components[2], 1);

/*
Now that the model-view matrix is set and the materials ready,
call another function to actually draw the mesh.
*/
[self drawMesh:index withEffect: _pFX[uiFXID]];
glBindBuffer(GL_ARRAY_BUFFER, 0);



}


- (void)drawMesh:(int)i32NodeIndex withEffect:(CPVRTPFXEffect *)pCurrentFX
{
// Get the mesh data from the POD file
int i32MeshIndex = _broncoScene.pNode[i32NodeIndex].nIdx;
SPODMesh* pMesh = &_broncoScene.pMesh[i32MeshIndex];

// bind the VBO for the mesh
glBindBuffer(GL_ARRAY_BUFFER, _puiVbo[i32MeshIndex]);

// bind the index buffer, won't hurt if the handle is 0
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _puiIndexVbo[i32MeshIndex]);

const CPVRTArray& Uniforms = pCurrentFX->GetUniformArray();

// Set attributes and texture stages
// The vertex data is already loaded into an VBO as 'interleaved data' (e.g. x,y,z,nx,ny,nz,u0,v0,...).
// When using 'interleaved data' the last parameter in glVertexAttribPointer is just a numerical offset (in bytes) into the stream (e.g. 0, 12, 24).
// Our tools use pMesh->sVertex.pData, etc. to store this offset only when using interleaved data.
// If you do not want to use interleaved data you will need to create separated VBO from pMesh->sVertex.pData, pMesh->sNormals.pData, etc.
// and set the offset (last parameter) to 0
for(unsigned int j = 0; j < Uniforms.GetSize(); ++j)
{
switch(Uniforms[j].nSemantic)
{
case ePVRTPFX_UsPOSITION:
{
glVertexAttribPointer(Uniforms[j].nLocation, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
glEnableVertexAttribArray(Uniforms[j].nLocation);
}
break;
case ePVRTPFX_UsNORMAL:
{
glVertexAttribPointer(Uniforms[j].nLocation, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
glEnableVertexAttribArray(Uniforms[j].nLocation);
}
break;
case ePVRTPFX_UsUV:
{
glVertexAttribPointer(Uniforms[j].nLocation, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
glEnableVertexAttribArray(Uniforms[j].nLocation);
}
break;

case ePVRTPFX_UsTEXTURE:
{
// Set the sampler variable to the texture unit/stage 0,1,2,etc.
glUniform1i(Uniforms[j].nLocation, Uniforms[j].nIdx);
}
break;
case eCUSTOMSEMANTIC_TANGENT:
{
glVertexAttribPointer(Uniforms[j].nLocation, 3, GL_FLOAT, GL_FALSE, pMesh->sTangents.nStride, pMesh->sTangents.pData);

}
break;

}
}

// Indexed Triangle list
// Note: if you export you model and want to use this code, please export it as 'interleaved' triangle list.
glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);

// Safely disable the vertex attribute arrays
for(unsigned int j = 0; j < Uniforms.GetSize(); ++j)
{
switch(Uniforms[j].nSemantic)
{
case ePVRTPFX_UsPOSITION:
{
glDisableVertexAttribArray(Uniforms[j].nLocation);
}
break;
case ePVRTPFX_UsNORMAL:
{
glDisableVertexAttribArray(Uniforms[j].nLocation);
}
break;
case ePVRTPFX_UsUV:
{
glDisableVertexAttribArray(Uniforms[j].nLocation);
}
break;
}
}

// Un-bind our vertex and index buffers.
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

}


Hi,



Could you post the fragment shader code you are currently using to attempt this effect?



Thanks,

Paul.

Thanks PaulL, that’s the thing though, I don’t have the shaders. I’m trying to get help with creating them.

You can use the PVRShaderEditor tool in the PowerVR SDK to view the .pfx file.



https://www.imgcommunity.local/developers/powervr/tools/pvrshadereditor/

You achieve the effect by creating a POD for the car model, which should have a base texture, and a decal texture. You can then use a fragment shader defined in the PFX which takes two texture uniforms. The first texture handle would reference the car base texture, and the second handle should reference the decal you wish to use. The shader can then blend between the two textures on to the model.



By changing the texture referenced by the shader handle, you can then apply different decals to several cars in a scene.

Thanks Pauil,



Here’s how the effect looks applied.



Not sure how to modify this further, but here’s my effect code:





[TEXTURE]

NAME cubemap

PATH bronco_cubemap_rotated2.pvr

MINIFICATION LINEAR

MAGNIFICATION LINEAR

MIPMAP LINEAR

WRAP_S CLAMP

WRAP_T CLAMP

[/TEXTURE]



[TEXTURE]

NAME bodyBase

PATH broncoBody0017_texture.pvr

MINIFICATION LINEAR

MAGNIFICATION LINEAR

MIPMAP LINEAR

WRAP_S REPEAT

WRAP_T REPEAT



[/TEXTURE]

// ENVIRONMENT CUBEMAP /////////////////////////////////////////////////////////////////////

//

// Effect 3 from skybox2 example. Displays a textured bronco with diffuse lighting and a

// second texture cube map of a garage, which is applied using a reflection vector as texture coordinates.

// This makes it look like the bronco is reflecting the garage.

//



[VERTEXSHADER]

NAME envMapVertShader



[GLSL_CODE]

attribute vec3 myVertex;

attribute vec3 myNormal;

attribute vec2 myUV;



uniform mat4 myMVPMatrix;

uniform mat3 myModelViewIT;

uniform mat4 myModelView;

uniform mediump vec3 EyePosModel;



uniform mediump vec3 myLightDirection;

varying highp float fDiffuse;

varying lowp vec2 fTexCoord;



uniform mediump float myFrame;

uniform mediump float fAnim;

varying lowp vec3 fReflectVec;



uniform vec4 diffuseColor;

varying vec4 baseColor;



void main(void)

{

mediump vec4 myVertex4 = vec4(myVertex, 1);



gl_Position = myMVPMatrix * myVertex4;

mediump vec3 fTransNormal = myModelViewIT * myNormal;



fDiffuse = (0.05 * dot(fTransNormal, myLightDirection) + 0.95) * 0.5;



mediump vec3 EyeDir = vec3(0.0,-1.0,0.0) - vec3(myModelView * myVertex4);

fReflectVec = myModelViewIT * reflect(EyeDir, normalize(fTransNormal) );



baseColor = diffuseColor;



fTexCoord = myUV.st;

}

[/GLSL_CODE]

[/VERTEXSHADER]



[FRAGMENTSHADER]

NAME envMapFragShader



[GLSL_CODE]

const mediump float MixRatio = 0.15;



varying lowp vec4 baseColor;

varying lowp vec2 fTexCoord;

varying lowp vec3 fReflectVec;



uniform sampler2D sampler2d;

uniform samplerCube myCubeMap;



void main (void)

{





// Draw the static base

mediump vec3 envColor = vec3 (texture2D(sampler2d, fTexCoord) * baseColor);



// Do a lookup into the environment map.

mediump vec3 envColor2 = vec3 (textureCube(myCubeMap, fReflectVec));



// Mix them

envColor = mix(envColor, envColor2, MixRatio);



gl_FragColor = vec4 (envColor, 1.0);



}







[/GLSL_CODE]

[/FRAGMENTSHADER]



[EFFECT]

NAME environmentMapEffect



// GLOBALS UNIFORMS

UNIFORM myModelViewIT WORLDVIEWIT

UNIFORM myMVPMatrix WORLDVIEWPROJECTION

UNIFORM myModelView WORLDVIEW

UNIFORM myLightDirection LIGHTDIREYE

UNIFORM sampler2d TEXTURE0

UNIFORM myCubeMap TEXTURE1



// ATTRIBUTES

ATTRIBUTE myVertex POSITION

ATTRIBUTE myNormal NORMAL

ATTRIBUTE myUV UV



VERTEXSHADER envMapVertShader

FRAGMENTSHADER envMapFragShader

TEXTURE 0 bodyBase

TEXTURE 1 cubemap

[/EFFECT]