有人可以帮助我或让我朝着正确的方向前进,从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的机制。对于着色器代码,我只是要求给出正确的流。据我所知,未点亮和点亮的版本依赖于传递矩阵,我完全理解这个概念。我很难找到显示这些概念的着色器示例。
答案 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
,但是inPosition
和inTexcoord
(也许inVertexCol
,如果您需要顶点有颜色),所有代码都与不需要的{相关{1}}Šattribute
可以是inPosition
希望它有所帮助。
答案 1 :(得分:1)
<强>简介强>
您没有指定要定位的OpenGL / GLSL版本,因此我假设它至少是OpenGL 3.
可编程流水线的一个主要优点是与固定功能流水线相比,是完全可定制的顶点输入。我不太确定,如果引入固定顶点格式等约束是个好主意。为了什么?...(你会发现我的帖子“另一种方式”段落中的现代方法)
但是,如果你真的想模仿固定功能...
我认为你需要为每个顶点格式设置一个顶点着色器 你有,或以某种方式生成顶点着色器。甚至是 所有着色器阶段。
例如,对于x, y, color, tu, tv
输入,您将拥有顶点
着色器如:
attribute vec2 inPosition;
attribute vec4 inCol;
attribute vec2 inTexcoord;
void main()
{
...
}
由于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;
};
或许,您可以通过分支将所有着色器与不同格式,制服等组合在一个大的 ubershader 中。
另一种方式
你可以坚持使用现代方法,只允许用户声明他想要的顶点格式(格式,他在着色器中使用的格式)。只需实现类似于IDirect3DDevice9::CreateVertexDeclaration或ID3D11Device::CreateInputLayout的概念:您将使用glVertexAttribPointer(),可能还会使用VAO。这样,您也可以以独立于API的方式抽象出顶点布局。
主要观点是:
P.S。如果您需要有关如何正确实现GLSL中的光线,材质(我的意思是算法)的想法,您最好选择一些书籍或在线教程,而不是在这里询问。或者只是谷歌“GLSL照明”。 你可以找到有趣的链接:
快乐的编码!