DirectX FVF类似GLSL着色器

时间:2013-10-04 22:44:56

标签: opengl directx glsl

有人可以帮助我或让我朝着正确的方向前进,从GLSL代码中实现DirectX的基本FVF吗?我完全理解如何创建程序,应用VBO以及所有这些,但我在实际创建着色器时遇到了很大困难。即:

transformed+lit (x,y,color,specular,tu,tv)
lit (x,y,z,color,specular,tu,tv)
unlit (x,y,z,nx,ny,nz,tu,tv) [material/lights]

有了这个,我将获得足够的实施更多有趣的着色器。

所以,我不是要求一种处理FVF的机制。对于着色器代码,我只是要求给出正确的流。据我所知,未点亮和点亮的版本依赖于传递矩阵,我完全理解这个概念。我很难找到显示这些概念的着色器示例。

2 个答案:

答案 0 :(得分:2)

好。如果您在查找工作着色器时遇到麻烦,可以使用示例(老实说,您可以在任何OpenGL书籍中找到它)。

此着色器程序将使用对象的世界矩阵和相机的矩阵来变换顶点,然后将一个纹理映射到像素并使用一个方向光照亮它们(根据材料属性和光线方向)。

顶点着色器:

#version 330

// Vertex input layout
attribute vec3 inPosition;
attribute vec3 inNormal;
attribute vec4 inVertexCol;
attribute vec2 inTexcoord;
attribute vec3 inTangent;
attribute vec3 inBitangent;

// Output
struct PSIn
{
    vec3 normal;
    vec4 vertexColor;
    vec2 texcoord;
    vec3 tangent;
    vec3 bitangent;
};

out PSIn psin;

// Uniform buffers
layout(std140)
uniform CameraBuffer
{
    mat4 mtxView;
    mat4 mtxProj;
    vec3 cameraPosition;
};

layout(std140)
uniform ObjectBuffer
{
    mat4 mtxWorld;
};

void main()
{
    // transform position
    vec4 pos = vec4(inPosition, 1.0f);
    pos = mtxWorld * pos;
    pos = mtxView * pos;
    pos = mtxProj * pos;
    gl_Position = pos;

    // just pass-through other stuff
    psin.normal = inNormal;
    psin.tangent = inTangent;
    psin.bitangent = inBitangent;
    psin.texcoord = inTexcoord;
    psin.vertexColor = inVertexCol;
}

片段着色器:

#version 330

// Input
in vec3 position;
in vec3 normal;
in vec4 vertexColor;
in vec2 texcoord;
in vec3 tangent;
in vec3 bitangent;

// Output
out vec4 fragColor;

// Uniforms
uniform sampler2D sampler0;

layout(std140)
uniform CameraBuffer
{
    mat4 mtxView;
    mat4 mtxProj;
    vec3 cameraPosition;
};

layout(std140) 
uniform ObjectBuffer
{
    mat4 mtxWorld;
};

layout(std140) 
uniform LightBuffer
{
    vec3 lightDirection;
};

struct Material
{
    float Ka;  // ambient quotient
    float Kd;  // diffuse quotient
    float Ks;  // specular quotient
    float A;   // shininess
};

layout(std140) 
uniform MaterialBuffer
{
    Material material;
};

    // function to calculate pixel lighting
float Lit( Material material, vec3 pos, vec3 nor, vec3 lit, vec3 eye )
{
    vec3 V = normalize( eye - pos );
    vec3 R = reflect( lit, nor);

    float Ia = material.Ka;
    float Id = material.Kd * clamp( dot(nor, -lit), 0.0f, 1.0f );
    float Is = material.Ks * pow( clamp(dot(R,V), 0.0f, 1.0f), material.A );
    return Ia + Id + Is;
}

void main() 
{   
    vec3 nnormal = normalize(normal);
    vec3 ntangent = normalize(tangent);
    vec3 nbitangent = normalize(bitangent);

    vec4 outColor = texture(sampler0, texcoord); // texture mapping

    outColor *=  Lit( material, position, nnormal, lightDirection, cameraPosition ); // lighting

    outColor.w = 1.0f;

    fragColor = outColor;
}

如果您不想进行纹理处理,请不要对纹理进行采样,而是将outColor等同于vertexColor

如果您不需要照明,只需注释掉Lit()功能。

修改 对于2D对象,您仍然可以使用相同的程序,但许多功能将是多余的。你可以剥离:

  • 相机
  • 材料
  • 所有顶点attribute,但是inPositioninTexcoord(也许inVertexCol,如果您需要顶点有颜色),所有代码都与不需要的{相关{1}}Š
  • attribute可以是inPosition
  • 您需要传递正交投影矩阵而不是透视矩阵
  • 你甚至可以去掉矩阵,并以像素为单位传递顶点缓冲区。请参阅我的回答here,了解如何将这些像​​素位置转换为屏幕空间位置。您可以使用C / C ++代码或GLSL / HLSL。

希望它有所帮助。

答案 1 :(得分:1)

<强>简介

您没有指定要定位的OpenGL / GLSL版本,因此我假设它至少是OpenGL 3.

可编程流水线的一个主要优点是与固定功能流水线相比,是完全可定制的顶点输入。我不太确定,如果引入固定顶点格式等约束是个好主意。为了什么?...(你会发现我的帖子“另一种方式”段落中的现代方法)

但是,如果你真的想模仿固定功能...

  1. 我认为你需要为每个顶点格式设置一个顶点着色器 你有,或以某种方式生成顶点着色器。甚至是 所有着色器阶段。

    例如,对于x, y, color, tu, tv输入,您将拥有顶点 着色器如:

    attribute vec2 inPosition;
    attribute vec4 inCol;
    attribute vec2 inTexcoord;
    
    void main()
    {
    ...
    }
    
  2. 由于OpenGL 3中没有变换,灯光和材质固定功能,您必须自己实现:

    • 您必须传递矩阵才能进行转换
    • 对于亮起的着色器,您必须传递其他变量,例如光线方向
    • 对于材质着色器,您必须在输入中包含材料

    通常,在着色器中,您可以使用制服或制服块:

    layout(std140)
    uniform CameraBuffer
    {
        mat4 mtxView;
        mat4 mtxProj;
        vec3 cameraPosition;
    };
    
    layout(std140) 
    uniform ObjectBuffer
    {
        mat4 mtxWorld;
    };
    
    layout(std140) 
    uniform LightBuffer
    {
        vec3 lightDirection;
    };
    
    struct Material
    {
        float Ka; 
        float Kd; 
        float Ks;
        float A;
    };
    
    layout(std140) 
    uniform MaterialBuffer
    {
        Material material;
    };
    
  3. 或许,您可以通过分支将所有着色器与不同格式,制服等组合在一个大的 ubershader 中。

  4. 另一种方式

    你可以坚持使用现代方法,只允许用户声明他想要的顶点格式(格式,他在着色器中使用的格式)。只需实现类似于IDirect3DDevice9::CreateVertexDeclarationID3D11Device::CreateInputLayout的概念:您将使用glVertexAttribPointer(),可能还会使用VAO。这样,您也可以以独立于API的方式抽象出顶点布局。

    主要观点是:

    P.S。如果您需要有关如何正确实现GLSL中的光线,材质(我的意思是算法)的想法,您最好选择一些书籍或在线教程,而不是在这里询问。或者只是谷歌“GLSL照明”。 你可以找到有趣的链接:

    快乐的编码!