Merge branch 'hardware_skinning'

This commit is contained in:
Benau 2016-12-22 10:38:06 +08:00
commit ffa4ad84cb
66 changed files with 2184 additions and 708 deletions

View File

@ -63,5 +63,11 @@ layout (std140) uniform LightingData
float rL21;
float rL22;
};
layout (std140) uniform SkinningData
{
mat4 joint_matrices[MAX_BONES];
};
#endif
#endif // HEADER_TXT

View File

@ -0,0 +1,77 @@
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;
layout(location = 3) in vec4 Data1;
layout(location = 4) in vec4 Data2;
layout(location = 5) in ivec4 Joint;
layout(location = 6) in vec4 Weight;
layout(location = 7) in vec3 Origin;
layout(location = 8) in vec3 Orientation;
layout(location = 9) in vec3 Scale;
layout(location = 10) in vec4 misc_data;
#ifdef Use_Bindless_Texture
layout(location = 11) in sampler2D Handle;
layout(location = 12) in sampler2D SecondHandle;
layout(location = 13) in sampler2D ThirdHandle;
layout(location = 14) in sampler2D FourthHandle;
#endif
layout(location = 15) in int skinning_offset;
out vec3 nor;
out vec3 tangent;
out vec3 bitangent;
out vec2 uv;
out vec4 color;
out vec2 color_change;
#ifdef Use_Bindless_Texture
flat out sampler2D handle;
flat out sampler2D secondhandle;
flat out sampler2D thirdhandle;
flat out sampler2D fourthhandle;
#endif
#stk_include "utils/getworldmatrix.vert"
void main(void)
{
mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale);
mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin, Orientation, Scale) * InverseViewMatrix);
vec4 idle_position = vec4(Position, 1.);
vec4 idle_normal = vec4(Normal, 0.);
vec4 idle_tangent = vec4(Data1.z, Data1.w, Data2.x, 0.);
vec4 idle_bitangent = vec4(Data2.y, Data2.z, Data2.w, 0.);
vec4 skinned_position = vec4(0.);
vec4 skinned_normal = vec4(0.);
vec4 skinned_tangent = vec4(0.);
vec4 skinned_bitangent = vec4(0.);
// Note : For normal we assume no scale factor in bone (otherwise we'll have to compute inversematrix for each bones...)
for (int i = 0; i < 4; i++)
{
vec4 single_bone_influenced_position = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
vec4 single_bone_influenced_normal = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_normal;
vec4 single_bone_influenced_tangent = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_tangent;
vec4 single_bone_influenced_bitangent = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_bitangent;
skinned_position += Weight[i] * single_bone_influenced_position;
skinned_normal += Weight[i] * single_bone_influenced_normal;
skinned_tangent += Weight[i] * single_bone_influenced_tangent;
skinned_bitangent += Weight[i] * single_bone_influenced_bitangent;
}
gl_Position = ProjectionViewMatrix * ModelMatrix * skinned_position;
// Keep orthogonality
nor = (TransposeInverseModelView * skinned_normal).xyz;
// Keep direction
tangent = (ViewMatrix * ModelMatrix * skinned_tangent).xyz;
bitangent = (ViewMatrix * ModelMatrix * skinned_bitangent).xyz;
uv = vec2(Data1.x + misc_data.x, Data1.y + misc_data.y);
color = Color.zyxw;
color_change = misc_data.zw;
#ifdef Use_Bindless_Texture
handle = Handle;
secondhandle = SecondHandle;
thirdhandle = ThirdHandle;
fourthhandle = FourthHandle;
#endif
}

View File

@ -0,0 +1,57 @@
uniform int layer;
layout(location = 0) in vec3 Position;
layout(location = 3) in vec4 Data1;
layout(location = 5) in ivec4 Joint;
layout(location = 6) in vec4 Weight;
layout(location = 7) in vec3 Origin;
layout(location = 8) in vec3 Orientation;
layout(location = 9) in vec3 Scale;
#ifdef Use_Bindless_Texture
layout(location = 11) in uvec2 Handle;
#endif
layout(location = 15) in int skinning_offset;
#ifdef VSLayer
out vec2 uv;
#ifdef Use_Bindless_Texture
flat out uvec2 handle;
#endif
#else
out vec2 tc;
out int layerId;
#ifdef Use_Bindless_Texture
flat out uvec2 hdle;
#endif
#endif
#stk_include "utils/getworldmatrix.vert"
void main(void)
{
mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale);
vec4 idle_position = vec4(Position, 1.);
vec4 skinned_position = vec4(0.);
for (int i = 0; i < 4; i++)
{
vec4 single_bone_influenced_position = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
skinned_position += Weight[i] * single_bone_influenced_position;
}
#ifdef VSLayer
gl_Layer = layer;
gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * skinned_position;
uv = Data1.xy;
#ifdef Use_Bindless_Texture
handle = Handle;
#endif
#else
layerId = layer;
gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * skinned_position;
tc = Data1.xy;
#ifdef Use_Bindless_Texture
hdle = Handle;
#endif
#endif
}

View File

@ -1,9 +1,9 @@
#ifdef Use_Bindless_Texture
layout(bindless_sampler) uniform sampler2D normalMap;
layout(bindless_sampler) uniform sampler2D DiffuseForAlpha;
layout(bindless_sampler) uniform sampler2D glossMap;
#else
uniform sampler2D normalMap;
uniform sampler2D DiffuseForAlpha;
uniform sampler2D glossMap;
#endif
in vec3 tangent;
@ -17,7 +17,7 @@ void main()
{
// normal in Tangent Space
vec3 TS_normal = 2.0 * texture(normalMap, uv).rgb - 1.0;
float alpha = texture(DiffuseForAlpha, uv).a;
float gloss = texture(glossMap, uv).x;
// Because of interpolation, we need to renormalize
vec3 Frag_tangent = normalize(tangent);
vec3 Frag_normal = normalize(cross(Frag_tangent, bitangent));
@ -25,5 +25,5 @@ void main()
vec3 FragmentNormal = TS_normal.x * Frag_tangent + TS_normal.y * Frag_bitangent - TS_normal.z * Frag_normal;
EncodedNormal.xy = 0.5 * EncodeNormal(normalize(FragmentNormal)) + 0.5;
EncodedNormal.z = 1. - alpha;
EncodedNormal.z = gloss;
}

View File

@ -1,81 +1,70 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 the SuperTuxKart team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef GL_ES
uniform mat4 ModelMatrix;
uniform mat4 InverseModelMatrix;
uniform vec2 texture_trans;
#else
uniform mat4 ModelMatrix =
mat4(1., 0., 0., 0.,
0., 1., 0., 0.,
0., 0., 1., 0.,
0., 0., 0., 1.);
uniform mat4 InverseModelMatrix =
mat4(1., 0., 0., 0.,
0., 1., 0., 0.,
0., 0., 1., 0.,
0., 0., 0., 1.);
// skinning.vert
#version 330 compatibility
#define MAX_JOINT_NUM 36
#define MAX_LIGHT_NUM 8
uniform vec2 texture_trans = vec2(0., 0.);
#endif
uniform int skinning_offset;
uniform mat4 JointTransform[MAX_JOINT_NUM];
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;
layout(location = 3) in vec4 Data1;
layout(location = 4) in vec4 Data2;
layout(location = 5) in ivec4 Joint;
layout(location = 6) in vec4 Weight;
void main()
out vec3 nor;
out vec3 tangent;
out vec3 bitangent;
out vec2 uv;
out vec4 color;
#stk_include "utils/getworldmatrix.vert"
void main(void)
{
int index;
vec4 ecPos;
vec3 normal;
vec3 light_dir;
float n_dot_l;
float dist;
mat4 TransposeInverseModelView = transpose(InverseModelMatrix * InverseViewMatrix);
vec4 idle_position = vec4(Position, 1.);
vec4 idle_normal = vec4(Normal, 0.);
vec4 idle_tangent = vec4(Data1.z, Data1.w, Data2.x, 0.);
vec4 idle_bitangent = vec4(Data2.y, Data2.z, Data2.w, 0.);
vec4 skinned_position = vec4(0.);
vec4 skinned_normal = vec4(0.);
vec4 skinned_tangent = vec4(0.);
vec4 skinned_bitangent = vec4(0.);
// Note : For normal we assume no scale factor in bone (otherwise we'll have to compute inversematrix for each bones...)
for (int i = 0; i < 4; i++)
{
vec4 single_bone_influenced_position = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
vec4 single_bone_influenced_normal = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_normal;
vec4 single_bone_influenced_tangent = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_tangent;
vec4 single_bone_influenced_bitangent = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_bitangent;
skinned_position += Weight[i] * single_bone_influenced_position;
skinned_normal += Weight[i] * single_bone_influenced_normal;
skinned_tangent += Weight[i] * single_bone_influenced_tangent;
skinned_bitangent += Weight[i] * single_bone_influenced_bitangent;
}
mat4 ModelTransform = gl_ModelViewProjectionMatrix;
index = int(gl_Color.r * 255.99);
mat4 vertTran = JointTransform[index - 1];
index = int(gl_Color.g * 255.99);
if(index > 0)
vertTran += JointTransform[index - 1];
index = int(gl_Color.b * 255.99);
if(index > 0)
vertTran += JointTransform[index - 1];
index = int(gl_Color.a * 255.99);
if(index > 0)
vertTran += JointTransform[index - 1];
ecPos = gl_ModelViewMatrix * vertTran * gl_Vertex;
normal = (vertTran * vec4(gl_Normal, 0.0)).xyz;
normal = normalize(gl_NormalMatrix * normal);
gl_FrontColor = vec4(0,0,0,0);
for(int i = 0;i < MAX_LIGHT_NUM;i++)
{
light_dir = vec3(gl_LightSource[i].position-ecPos);
n_dot_l = max(dot(normal, normalize(light_dir)), 0.0);
dist = length(light_dir);
n_dot_l *= 1.0 / (gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist);
gl_FrontColor += gl_LightSource[i].diffuse * n_dot_l;
}
gl_FrontColor = clamp(gl_FrontColor,0.3,1.0);
ModelTransform *= vertTran;
gl_Position = ModelTransform * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;
/*
// Reflections.
vec3 r = reflect( ecPos.xyz , normal );
float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) );
gl_TexCoord[1].s = r.x/m + 0.5;
gl_TexCoord[1].t = r.y/m + 0.5;
*/
gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * skinned_position;
// Keep orthogonality
nor = (TransposeInverseModelView * skinned_normal).xyz;
// Keep direction
tangent = (ViewMatrix * ModelMatrix * skinned_tangent).xyz;
bitangent = (ViewMatrix * ModelMatrix * skinned_bitangent).xyz;
uv = vec2(Data1.x + texture_trans.x, Data1.y + texture_trans.y);
color = Color.zyxw;
}

View File

@ -0,0 +1,37 @@
uniform mat4 ModelMatrix;
uniform int skinning_offset;
uniform int layer;
layout(location = 0) in vec3 Position;
layout(location = 3) in vec4 Data1;
layout(location = 5) in ivec4 Joint;
layout(location = 6) in vec4 Weight;
#ifdef VSLayer
out vec2 uv;
#else
out vec2 tc;
out int layerId;
#endif
void main(void)
{
vec4 idle_position = vec4(Position, 1.);
vec4 skinned_position = vec4(0.);
for (int i = 0; i < 4; i++)
{
vec4 single_bone_influenced_position = joint_matrices[clamp(Joint[i] + skinning_offset, 0, MAX_BONES)] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
skinned_position += Weight[i] * single_bone_influenced_position;
}
#ifdef VSLayer
gl_Layer = layer;
uv = Data1.xy;
gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * skinned_position;
#else
layerId = layer;
tc = Data1.xy;
gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * skinned_position;
#endif
}

View File

@ -30,6 +30,11 @@ if(APPLE)
endif()
add_definitions(-DNDEBUG=1 -DIRRLICHT_EXPORTS=1 -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES)
if(UNIX OR MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
endif()
if(MSVC)
add_definitions(/D_IRR_STATIC_LIB_)
add_definitions(/D_CRT_SECURE_NO_WARNINGS) # Shut up about unsafe stuff

View File

@ -116,6 +116,8 @@ namespace scene
NewVertices=new CSpecificVertexList<video::S3DVertexTangents>;
break;
}
default:
break;
}
if (Vertices)
{

View File

@ -8,6 +8,8 @@
#include "aabbox3d.h"
#include "IMesh.h"
typedef void (*SkinningCallback)(const irr::core::matrix4& m, int joint, int offset);
namespace irr
{
namespace scene

View File

@ -371,6 +371,8 @@ protected:
func(verts[i]);
}
break;
default:
break;
}
if (boundingBoxUpdate)
{

View File

@ -69,11 +69,11 @@ namespace scene
virtual void animateMesh(f32 frame, f32 blend)=0;
//! Preforms a software skin on this mesh based of joint positions
virtual void skinMesh(f32 strength=1.f) = 0;
virtual void skinMesh(f32 strength=1.f, SkinningCallback sc = NULL, int offset = -1) = 0;
//! converts the vertex type of all meshbuffers to tangents.
/** E.g. used for bump mapping. */
virtual void convertMeshToTangents() = 0;
virtual void convertMeshToTangents(bool(*predicate)(IMeshBuffer*)) = 0;
//! Allows to enable hardware skinning.
/* This feature is not implementated in Irrlicht yet */

View File

@ -26,7 +26,9 @@ enum E_VERTEX_TYPE
//! Vertex with a tangent and binormal vector, video::S3DVertexTangents.
/** Usually used for tangent space normal mapping. */
EVT_TANGENTS
EVT_TANGENTS,
EVT_SKINNED_MESH
};
//! Array holding the built in vertex type names
@ -251,6 +253,22 @@ struct S3DVertexTangents : public S3DVertex
}
};
struct S3DVertexSkinnedMesh : public S3DVertexTangents
{
s32 m_joint_idx1;
s32 m_joint_idx2;
s32 m_joint_idx3;
s32 m_joint_idx4;
f32 m_weight1;
f32 m_weight2;
f32 m_weight3;
f32 m_weight4;
E_VERTEX_TYPE getType() const
{
return EVT_SKINNED_MESH;
}
};
inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType)
@ -261,6 +279,8 @@ inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType)
return sizeof(video::S3DVertex2TCoords);
case video::EVT_TANGENTS:
return sizeof(video::S3DVertexTangents);
case video::EVT_SKINNED_MESH:
return sizeof(video::S3DVertexSkinnedMesh);
default:
return sizeof(video::S3DVertex);
}

View File

@ -50,6 +50,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return (video::S3DVertex*)&Vertices_2TCoords[index];
case video::EVT_TANGENTS:
return (video::S3DVertex*)&Vertices_Tangents[index];
case video::EVT_SKINNED_MESH:
return (video::S3DVertex*)&Vertices_SkinnedMesh[index];
default:
return &Vertices_Standard[index];
}
@ -64,6 +66,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords.const_pointer();
case video::EVT_TANGENTS:
return Vertices_Tangents.const_pointer();
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh.const_pointer();
default:
return Vertices_Standard.const_pointer();
}
@ -78,6 +82,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords.pointer();
case video::EVT_TANGENTS:
return Vertices_Tangents.pointer();
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh.pointer();
default:
return Vertices_Standard.pointer();
}
@ -92,6 +98,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords.size();
case video::EVT_TANGENTS:
return Vertices_Tangents.size();
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh.size();
default:
return Vertices_Standard.size();
}
@ -180,6 +188,20 @@ struct SSkinMeshBuffer : public IMeshBuffer
}
break;
}
case video::EVT_SKINNED_MESH:
{
if (Vertices_SkinnedMesh.empty())
BoundingBox.reset(0,0,0);
else
{
BoundingBox.reset(Vertices_SkinnedMesh[0].Pos);
for (u32 i=1; i<Vertices_SkinnedMesh.size(); ++i)
BoundingBox.addInternalPoint(Vertices_SkinnedMesh[i].Pos);
}
break;
}
default:
break;
}
}
@ -208,6 +230,54 @@ struct SSkinMeshBuffer : public IMeshBuffer
}
}
void convertForSkinning()
{
if (VertexType==video::EVT_STANDARD)
{
for(u32 n=0;n<Vertices_Standard.size();++n)
{
video::S3DVertexSkinnedMesh Vertex;
Vertex.Color=Vertices_Standard[n].Color;
Vertex.Pos=Vertices_Standard[n].Pos;
Vertex.Normal=Vertices_Standard[n].Normal;
Vertex.TCoords=Vertices_Standard[n].TCoords;
Vertex.Tangent=core::vector3df(0.0f, 0.0f, 0.0f);
Vertex.Binormal=core::vector3df(0.0f, 0.0f, 0.0f);
Vertex.m_joint_idx1 = 0;
Vertex.m_joint_idx2 = 0;
Vertex.m_joint_idx3 = 0;
Vertex.m_joint_idx4 = 0;
Vertex.m_weight1 = 0;
Vertex.m_weight2 = 0;
Vertex.m_weight3 = 0;
Vertex.m_weight4 = 0;
Vertices_SkinnedMesh.push_back(Vertex);
}
}
if (VertexType==video::EVT_TANGENTS)
{
for(u32 n=0;n<Vertices_Tangents.size();++n)
{
video::S3DVertexSkinnedMesh Vertex;
Vertex.Color=Vertices_Tangents[n].Color;
Vertex.Pos=Vertices_Tangents[n].Pos;
Vertex.Normal=Vertices_Tangents[n].Normal;
Vertex.TCoords=Vertices_Tangents[n].TCoords;
Vertex.Tangent=Vertices_Tangents[n].Tangent;
Vertex.Binormal=Vertices_Tangents[n].Binormal;
Vertex.m_joint_idx1 = 0;
Vertex.m_joint_idx2 = 0;
Vertex.m_joint_idx3 = 0;
Vertex.m_joint_idx4 = 0;
Vertex.m_weight1 = 0;
Vertex.m_weight2 = 0;
Vertex.m_weight3 = 0;
Vertex.m_weight4 = 0;
Vertices_SkinnedMesh.push_back(Vertex);
}
}
}
//! Convert to tangents vertex type
virtual void convertToTangents()
{
@ -250,6 +320,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Pos;
case video::EVT_TANGENTS:
return Vertices_Tangents[i].Pos;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Pos;
default:
return Vertices_Standard[i].Pos;
}
@ -264,6 +336,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Pos;
case video::EVT_TANGENTS:
return Vertices_Tangents[i].Pos;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Pos;
default:
return Vertices_Standard[i].Pos;
}
@ -278,6 +352,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Normal;
case video::EVT_TANGENTS:
return Vertices_Tangents[i].Normal;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Normal;
default:
return Vertices_Standard[i].Normal;
}
@ -292,6 +368,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Normal;
case video::EVT_TANGENTS:
return Vertices_Tangents[i].Normal;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Normal;
default:
return Vertices_Standard[i].Normal;
}
@ -306,6 +384,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].TCoords;
case video::EVT_TANGENTS:
return Vertices_Tangents[i].TCoords;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].TCoords;
default:
return Vertices_Standard[i].TCoords;
}
@ -320,6 +400,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].TCoords;
case video::EVT_TANGENTS:
return Vertices_Tangents[i].TCoords;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].TCoords;
default:
return Vertices_Standard[i].TCoords;
}
@ -381,6 +463,7 @@ struct SSkinMeshBuffer : public IMeshBuffer
core::array<video::S3DVertexTangents> Vertices_Tangents;
core::array<video::S3DVertex2TCoords> Vertices_2TCoords;
core::array<video::S3DVertexSkinnedMesh> Vertices_SkinnedMesh;
core::array<video::S3DVertex> Vertices_Standard;
core::array<u16> Indices;

View File

@ -12,18 +12,25 @@ namespace irr
namespace core
{
//! Sinks an element into the heap.
//! Function object which can be used for sorting (default)
template<class T>
inline void heapsink(T*array, s32 element, s32 max)
inline bool sortless(const T& a, const T& b)
{
return a < b;
}
//! Sinks an element into the heap with a custom compare function
template<class T, class Compare>
inline void heapsink(T*array, s32 element, s32 max, Compare cmp)
{
while ((element<<1) < max) // there is a left child
{
s32 j = (element<<1);
if (j+1 < max && array[j] < array[j+1])
if (j+1 < max && cmp(array[j], array[j+1]))
j = j+1; // take right child
if (array[element] < array[j])
if (cmp(array[element], array[j]))
{
T t = array[j]; // swap elements
array[j] = array[element];
@ -35,10 +42,9 @@ inline void heapsink(T*array, s32 element, s32 max)
}
}
//! Sorts an array with size 'size' using heapsort.
template<class T>
inline void heapsort(T* array_, s32 size)
//! Sorts an array with size 'size' using heapsort with a custom compare function
template<class T, class Compare>
inline void heapsort(T* array_, s32 size, Compare cmp)
{
// for heapsink we pretent this is not c++, where
// arrays start with index 0. So we decrease the array pointer,
@ -51,7 +57,7 @@ inline void heapsort(T* array_, s32 size)
// build heap
for (i=((size-1)/2); i>=0; --i)
heapsink(virtualArray, i+1, virtualSize-1);
heapsink(virtualArray, i+1, virtualSize-1, cmp);
// sort array, leave out the last element (0)
for (i=size-1; i>0; --i)
@ -59,7 +65,7 @@ inline void heapsort(T* array_, s32 size)
T t = array_[0];
array_[0] = array_[i];
array_[i] = t;
heapsink(virtualArray, 1, i + 1);
heapsink(virtualArray, 1, i + 1, cmp);
}
}

View File

@ -394,10 +394,17 @@ public:
void sort()
{
if (!is_sorted && used>1)
heapsort(data, used);
heapsort(data, used, sortless<T>);
is_sorted = true;
}
template<class Compare>
void sort(Compare cmp)
{
if (!is_sorted && used>1)
heapsort(data, used, cmp);
is_sorted = true;
}
//! Performs a binary search for an element, returns -1 if not found.
/** The array will be sorted before the binary search if it is not

View File

@ -178,7 +178,7 @@ void CAnimatedMeshSceneNode::OnRegisterSceneNode()
}
}
IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(SkinningCallback sc, int offset)
{
if(Mesh->getMeshType() != EAMT_SKINNED)
{
@ -203,7 +203,7 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
skinnedMesh->animateMesh(getFrameNr(), 1.0f);
// Update the skinned mesh for the current joint transforms.
skinnedMesh->skinMesh(AnimationStrength);
skinnedMesh->skinMesh(AnimationStrength, sc, offset);
if (JointMode == EJUOR_READ)//read from mesh
{

View File

@ -161,7 +161,7 @@ namespace scene
protected:
//! Get a static mesh for the current frame of this animated mesh
IMesh* getMeshForCurrentFrame();
virtual IMesh* getMeshForCurrentFrame(SkinningCallback sc = NULL, int offset = -1);
void buildFrameNr(u32 timeMs);
void checkJoints();

View File

@ -646,6 +646,8 @@ SMesh* CMeshManipulator::createMeshCopy(scene::IMesh* mesh) const
buffer->drop();
}
break;
default:
break;
}// end switch
}// end for all mesh buffers
@ -751,6 +753,8 @@ IMesh* CMeshManipulator::createMeshUniquePrimitives(IMesh* mesh) const
buffer->drop();
}
break;
default:
break;
}// end switch
}// end for all mesh buffers
@ -987,6 +991,8 @@ IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh, bool recalculateNor
vNew = v[idx[i]];
}
break;
default:
break;
}
core::map<video::S3DVertexTangents, int>::Node* n = vertMap.find(vNew);
if (n)
@ -1075,6 +1081,8 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
v[idx[i]].Pos, v[idx[i]].Normal, v[idx[i]].Color, v[idx[i]].TCoords, v[idx[i]].TCoords);
}
break;
default:
break;
}
core::map<video::S3DVertex2TCoords, int>::Node* n = vertMap.find(vNew);
if (n)
@ -1158,6 +1166,8 @@ IMesh* CMeshManipulator::createMeshWith1TCoords(IMesh* mesh) const
v[idx[i]].Pos, v[idx[i]].Normal, v[idx[i]].Color, v[idx[i]].TCoords);
}
break;
default:
break;
}
core::map<video::S3DVertex, int>::Node* n = vertMap.find(vNew);
if (n)
@ -1805,6 +1815,8 @@ IMesh* CMeshManipulator::createForsythOptimizedMesh(const IMesh *mesh) const
buf->drop();
}
break;
default:
break;
}
delete [] vc;

View File

@ -276,6 +276,8 @@ void COctreeSceneNode::render()
}
}
break;
default:
break;
}
}
@ -371,6 +373,8 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
break;
default:
break;
}
polyCount += b->getIndexCount();
@ -424,6 +428,8 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
break;
default:
break;
}
polyCount += b->getIndexCount();
@ -474,6 +480,8 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
break;
default:
break;
}
polyCount += b->getIndexCount();
@ -487,6 +495,8 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
nodeCount = TangentsOctree->getNodeCount();
}
break;
default:
break;
}
}

View File

@ -1581,6 +1581,8 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun
case EVT_TANGENTS:
glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);
break;
default:
break;
}
}
else
@ -1676,6 +1678,8 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun
glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48));
}
break;
default:
break;
}
renderArray(indexList, primitiveCount, pType, iType);
@ -1740,6 +1744,8 @@ void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERT
}
}
break;
default:
break;
}
}
@ -1913,6 +1919,8 @@ void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCo
case EVT_TANGENTS:
glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);
break;
default:
break;
}
}
else
@ -1984,6 +1992,8 @@ void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCo
glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));
}
break;
default:
break;
}

View File

@ -9,6 +9,7 @@
#include "CBoneSceneNode.h"
#include "IAnimatedMeshSceneNode.h"
#include "os.h"
#include "irrMap.h"
namespace irr
{
@ -22,12 +23,12 @@ CSkinnedMesh::CSkinnedMesh()
LastAnimatedFrame(-1), SkinnedLastFrame(false),
InterpolationMode(EIM_LINEAR),
HasAnimation(false), PreparedForSkinning(false),
AnimateNormals(true), HardwareSkinning(false)
AnimateNormals(true), HardwareSkinning(false), m_total_joints(0),
m_current_joint(0)
{
#ifdef _DEBUG
setDebugName("CSkinnedMesh");
#endif
SkinningBuffers=&LocalBuffers;
}
@ -74,12 +75,19 @@ void CSkinnedMesh::setAnimationSpeed(f32 fps)
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{
const bool is_hw_skinning_before = HardwareSkinning;
if (is_hw_skinning_before)
HardwareSkinning = false;
//animate(frame,startFrameLoop, endFrameLoop);
if (frame==-1)
return this;
animateMesh((f32)frame, 1.0f);
skinMesh();
if (is_hw_skinning_before)
HardwareSkinning = true;
return this;
}
@ -93,6 +101,12 @@ IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32
//! blend: {0-old position, 1-New position}
void CSkinnedMesh::animateMesh(f32 frame, f32 blend)
{
if (HardwareSkinning && LastAnimatedFrame==frame)
{
SkinnedLastFrame=false;
return;
}
if (!HasAnimation || LastAnimatedFrame==frame)
return;
@ -445,7 +459,7 @@ void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint,
//--------------------------------------------------------------------------
//! Preforms a software skin on this mesh based of joint positions
void CSkinnedMesh::skinMesh(f32 strength)
void CSkinnedMesh::skinMesh(f32 strength, SkinningCallback sc, int offset)
{
if (!HasAnimation || SkinnedLastFrame)
return;
@ -456,7 +470,13 @@ void CSkinnedMesh::skinMesh(f32 strength)
//-----------------
SkinnedLastFrame=true;
if (!HardwareSkinning)
m_current_joint = 0;
if (HardwareSkinning)
{
for (u32 i = 0; i < RootJoints.size(); i++)
skinJoint(RootJoints[i], 0, strength, sc, offset);
}
else
{
//Software skin....
u32 i;
@ -486,65 +506,73 @@ void CSkinnedMesh::skinMesh(f32 strength)
updateBoundingBox();
}
void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint, f32 strength)
void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint, f32 strength,
SkinningCallback sc, int offset)
{
if (joint->Weights.size())
{
//Find this joints pull on vertices...
core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING);
jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix);
core::vector3df thisVertexMove, thisNormalMove;
core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers;
//Skin Vertices Positions and Normals...
for (u32 i=0; i<joint->Weights.size(); ++i)
if (HardwareSkinning)
{
SWeight& weight = joint->Weights[i];
if (sc != NULL) sc(jointVertexPull, m_current_joint, offset);
m_current_joint++;
}
else
{
core::vector3df thisVertexMove, thisNormalMove;
// Pull this vertex...
jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers;
if (AnimateNormals)
jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal);
// Apply animation strength
if(strength != 1.f)
//Skin Vertices Positions and Normals...
for (u32 i=0; i<joint->Weights.size(); ++i)
{
thisVertexMove = core::lerp(weight.StaticPos, thisVertexMove, strength);
if(AnimateNormals)
thisNormalMove = core::lerp(weight.StaticNormal, thisNormalMove, strength);
}
SWeight& weight = joint->Weights[i];
if (! (*(weight.Moved)) )
{
*(weight.Moved) = true;
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength;
// Pull this vertex...
jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength;
jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal);
//*(weight._Pos) = thisVertexMove * weight.strength;
// Apply animation strength
if(strength != 1.f)
{
thisVertexMove = core::lerp(weight.StaticPos, thisVertexMove, strength);
if(AnimateNormals)
thisNormalMove = core::lerp(weight.StaticNormal, thisNormalMove, strength);
}
if (! (*(weight.Moved)) )
{
*(weight.Moved) = true;
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength;
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength;
//*(weight._Pos) = thisVertexMove * weight.strength;
}
else
{
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength;
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength;
//*(weight._Pos) += thisVertexMove * weight.strength;
}
buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated();
}
else
{
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength;
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength;
//*(weight._Pos) += thisVertexMove * weight.strength;
}
buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated();
}
}
//Skin all children
for (u32 j=0; j<joint->Children.size(); ++j)
skinJoint(joint->Children[j], joint, strength);
skinJoint(joint->Children[j], joint, strength, sc, offset);
}
@ -724,28 +752,28 @@ bool CSkinnedMesh::setHardwareSkinning(bool on)
if (HardwareSkinning!=on)
{
if (on)
{
//set mesh to static pose...
for (u32 i=0; i<AllJoints.size(); ++i)
{
SJoint *joint=AllJoints[i];
for (u32 j=0; j<joint->Weights.size(); ++j)
{
const u16 buffer_id=joint->Weights[j].buffer_id;
const u32 vertex_id=joint->Weights[j].vertex_id;
LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos;
LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal;
LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated();
}
}
}
toStaticPose();
HardwareSkinning=on;
}
return HardwareSkinning;
}
void CSkinnedMesh::toStaticPose()
{
for (u32 i=0; i<AllJoints.size(); ++i)
{
SJoint *joint=AllJoints[i];
for (u32 j=0; j<joint->Weights.size(); ++j)
{
const u16 buffer_id=joint->Weights[j].buffer_id;
const u32 vertex_id=joint->Weights[j].vertex_id;
LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos;
LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal;
LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated();
}
}
}
void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint,SJoint *parentJoint)
{
@ -1139,7 +1167,7 @@ void CSkinnedMesh::finalize()
void CSkinnedMesh::updateBoundingBox(void)
{
if(!SkinningBuffers)
if(HardwareSkinning || !SkinningBuffers)
return;
core::array<SSkinMeshBuffer*> & buffer = *SkinningBuffers;
@ -1382,26 +1410,133 @@ void CSkinnedMesh::addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
SkinnedLastFrame=false;
}
void CSkinnedMesh::convertMeshToTangents()
void CSkinnedMesh::convertForSkinning()
{
// now calculate tangents
for (u32 b=0; b < LocalBuffers.size(); ++b)
if (HardwareSkinning) return;
setHardwareSkinning(true);
WeightInfluence wi;
for (u32 b = 0; b < LocalBuffers.size(); b++)
{
if (LocalBuffers[b])
LocalBuffers[b]->convertForSkinning();
wi.push_back(core::array<core::array<JointInfluence> > ());
for (u32 i = 0; i < LocalBuffers[b]->getVertexCount(); i++)
wi[b].push_back(core::array<JointInfluence>());
}
size_t idx = 0;
for (u32 i = 0; i < RootJoints.size(); i++)
computeWeightInfluence(RootJoints[i], idx, wi);
for (u32 b = 0; b < LocalBuffers.size(); b++)
{
if (LocalBuffers[b])
{
LocalBuffers[b]->convertToTangents();
const u32 total = wi[b].size();
_IRR_DEBUG_BREAK_IF(LocalBuffers[b]->getVertexCount() != total);
for (u32 i = 0; i < total; i++)
{
core::array<JointInfluence> this_influence;
core::array<JointInfluence> reported_weight = wi[b][i];
reported_weight.sort([]
(const JointInfluence& a, const JointInfluence& b)
{ return a.weight > b.weight; });
float remaining_weight = 1.0f;
for (u32 j = 0; j < 4; j++)
{
JointInfluence influence;
if (reported_weight.size() > j)
influence = reported_weight[j];
else
{
influence.joint_idx = -100000;
influence.weight = remaining_weight;
}
remaining_weight -= influence.weight;
this_influence.push_back(influence);
}
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx1 = this_influence[0].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx2 = this_influence[1].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx3 = this_influence[2].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx4 = this_influence[3].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight1 = this_influence[0].weight;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight2 = this_influence[1].weight;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight3 = this_influence[2].weight;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight4 = this_influence[3].weight;
}
}
}
SkinnedLastFrame = false;
skinMesh();
m_total_joints = m_current_joint;
}
const s32 idxCnt = LocalBuffers[b]->getIndexCount();
void CSkinnedMesh::computeWeightInfluence(SJoint *joint, size_t &index, WeightInfluence& wi)
{
if (!joint->Weights.empty())
{
for (u32 i = 0; i < joint->Weights.size(); i++)
{
SWeight& weight = joint->Weights[i];
JointInfluence tmp;
tmp.joint_idx = index;
tmp.weight = weight.strength;
wi[weight.buffer_id][weight.vertex_id].push_back(tmp);
}
index++;
}
u16* idx = LocalBuffers[b]->getIndices();
video::S3DVertexTangents* v =
(video::S3DVertexTangents*)LocalBuffers[b]->getVertices();
for (u32 j = 0; j < joint->Children.size(); j++)
computeWeightInfluence(joint->Children[j], index, wi);
}
for (s32 i=0; i<idxCnt; i+=3)
void CSkinnedMesh::convertMeshToTangents(bool(*predicate)(IMeshBuffer*))
{
bool recalculate_animation = false;
toStaticPose();
for (u32 b = 0; b < LocalBuffers.size(); b++)
{
bool recalculate_joints = false;
core::map<u32, u32> vert_loc_map;
SSkinMeshBuffer* ssmb = LocalBuffers[b];
if (ssmb)
{
if (!predicate(ssmb)) continue;
recalculate_joints = true;
recalculate_animation = true;
core::map<video::S3DVertexTangents, u32> vert_map;
core::array<u16> tmp_indices;
for (u32 i = 0; i < ssmb->Indices.size(); i++)
{
u32 vert_location = 0;
const u32 cur_ver_loc = ssmb->Indices[i];
const video::S3DVertex& v_old = ssmb->Vertices_Standard[cur_ver_loc];
video::S3DVertexTangents v(v_old.Pos, v_old.Normal, v_old.Color, v_old.TCoords);
core::map<video::S3DVertexTangents, u32>::Node *n = vert_map.find(v);
if (n)
{
vert_location = n->getValue();
}
else
{
vert_location = ssmb->Vertices_Tangents.size();
ssmb->Vertices_Tangents.push_back(v);
vert_map.insert(v, vert_location);
}
vert_loc_map[cur_ver_loc] = vert_location;
tmp_indices.push_back(vert_location);
}
const s32 index_count = tmp_indices.size();
u16* idx = tmp_indices.pointer();
video::S3DVertexTangents* v = ssmb->Vertices_Tangents.pointer();
core::vector3df local_normal;
for (s32 i = 0; i < index_count; i += 3)
{
calculateTangents(
v[idx[i+0]].Normal,
local_normal,
v[idx[i+0]].Tangent,
v[idx[i+0]].Binormal,
v[idx[i+0]].Pos,
@ -1412,7 +1547,7 @@ void CSkinnedMesh::convertMeshToTangents()
v[idx[i+2]].TCoords);
calculateTangents(
v[idx[i+1]].Normal,
local_normal,
v[idx[i+1]].Tangent,
v[idx[i+1]].Binormal,
v[idx[i+1]].Pos,
@ -1423,7 +1558,7 @@ void CSkinnedMesh::convertMeshToTangents()
v[idx[i+0]].TCoords);
calculateTangents(
v[idx[i+2]].Normal,
local_normal,
v[idx[i+2]].Tangent,
v[idx[i+2]].Binormal,
v[idx[i+2]].Pos,
@ -1433,11 +1568,38 @@ void CSkinnedMesh::convertMeshToTangents()
v[idx[i+0]].TCoords,
v[idx[i+1]].TCoords);
}
ssmb->Indices = tmp_indices;
ssmb->Vertices_Standard.clear();
ssmb->VertexType = video::EVT_TANGENTS;
}
if (recalculate_joints)
{
Vertices_Moved[b].set_used(ssmb->getVertexCount());
for (u32 i = 0; i < AllJoints.size(); i++)
{
SJoint *joint = AllJoints[i];
for (u32 j = 0; j <joint->Weights.size(); j++)
{
if (joint->Weights[j].buffer_id == b)
{
core::map<u32, u32>::Node *n =
vert_loc_map.find(joint->Weights[j].vertex_id);
if (n)
{
joint->Weights[j].vertex_id = n->getValue();
}
}
}
}
}
}
if (recalculate_animation)
{
PreparedForSkinning = false;
checkForAnimation();
}
}
void CSkinnedMesh::calculateTangents(
core::vector3df& normal,
core::vector3df& tangent,

View File

@ -14,6 +14,16 @@
#include "matrix4.h"
#include "quaternion.h"
class JointInfluence
{
public:
int joint_idx;
float weight;
};
typedef irr::core::array<irr::core::array
<irr::core::array<JointInfluence> > > WeightInfluence;
namespace irr
{
namespace scene
@ -25,7 +35,6 @@ namespace scene
class CSkinnedMesh: public ISkinnedMesh
{
public:
//! constructor
CSkinnedMesh();
@ -52,7 +61,7 @@ namespace scene
virtual void animateMesh(f32 frame, f32 blend);
//! Preforms a software skin on this mesh based of joint positions
virtual void skinMesh(f32 strength=1.f);
virtual void skinMesh(f32 strength=1.f, SkinningCallback sc = NULL, int offset = -1);
//! returns amount of mesh buffers.
virtual u32 getMeshBufferCount() const;
@ -105,7 +114,7 @@ namespace scene
virtual void setInterpolationMode(E_INTERPOLATION_MODE mode);
//! Convertes the mesh to contain tangent information
virtual void convertMeshToTangents();
virtual void convertMeshToTangents(bool(*predicate)(IMeshBuffer*));
//! Does the mesh have no animation
virtual bool isStatic();
@ -159,7 +168,16 @@ namespace scene
void addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
IAnimatedMeshSceneNode* node,
ISceneManager* smgr);
void convertForSkinning();
void computeWeightInfluence(SJoint *joint, size_t &index, WeightInfluence& wi);
u32 getTotalJoints() const { return m_total_joints; }
private:
void toStaticPose();
void checkForAnimation();
void normalizeWeights();
@ -175,7 +193,8 @@ private:
void calculateGlobalMatrices(SJoint *Joint,SJoint *ParentJoint);
void skinJoint(SJoint *Joint, SJoint *ParentJoint, f32 strength=1.f);
void skinJoint(SJoint *Joint, SJoint *ParentJoint, f32 strength=1.f,
SkinningCallback sc = NULL, int offset = -1);
void calculateTangents(core::vector3df& normal,
core::vector3df& tangent, core::vector3df& binormal,
@ -205,6 +224,8 @@ private:
bool PreparedForSkinning;
bool AnimateNormals;
bool HardwareSkinning;
u32 m_total_joints;
u32 m_current_joint;
};
} // end namespace scene

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -400,6 +400,8 @@ void CBatchingMesh::recalculateDestBufferBoundingBox(u32 i)
case video::EVT_TANGENTS:
((SMeshBufferTangents*)DestBuffers[i].Buffer)->recalculateBoundingBox();
break;
default:
break;
}
}

View File

@ -444,4 +444,8 @@ bool CentralVideoSettings::isDefferedEnabled() const
return UserConfigParams::m_dynamic_lights && !GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_ADVANCED_PIPELINE);
}
bool CentralVideoSettings::supportsHardwareSkinning() const
{
return isARBUniformBufferObjectUsable() && isARBExplicitAttribLocationUsable() && getGLSLVersion() >= 330;
}
#endif // !SERVER_ONLY

View File

@ -95,6 +95,7 @@ public:
bool supportsIndirectInstancingRendering() const;
bool supportsComputeShadersFiltering() const;
bool supportsAsyncInstanceUpload() const;
bool supportsHardwareSkinning() const;
// "Macro" around feature support and user config
bool isShadowEnabled() const;

View File

@ -29,6 +29,7 @@ void InstanceFiller<InstanceDataSingleTex>::add(GLMesh* mesh,
{
fillOriginOrientationScale<InstanceDataSingleTex>(STK::tuple_get<0>(is), instance);
instance.Texture = mesh->TextureHandles[0];
instance.skinning_offset = STK::tuple_get<3>(is);
}
// ----------------------------------------------------------------------------
@ -45,6 +46,7 @@ void InstanceFiller<InstanceDataThreeTex>::add(GLMesh* mesh,
instance.Texture = mesh->TextureHandles[0];
instance.SecondTexture = mesh->TextureHandles[1];
instance.ThirdTexture = mesh->TextureHandles[2];
instance.skinning_offset = STK::tuple_get<3>(is);
}
// ----------------------------------------------------------------------------
@ -62,6 +64,7 @@ void InstanceFiller<InstanceDataFourTex>::add(GLMesh* mesh,
instance.SecondTexture = mesh->TextureHandles[1];
instance.ThirdTexture = mesh->TextureHandles[2];
instance.FourthTexture = mesh->TextureHandles[3];
instance.skinning_offset = STK::tuple_get<3>(is);
}
// ----------------------------------------------------------------------------
@ -155,7 +158,7 @@ SolidCommandBuffer::SolidCommandBuffer(): CommandBuffer()
}
// ----------------------------------------------------------------------------
void SolidCommandBuffer::fill(SolidPassMeshMap *mesh_map)
void SolidCommandBuffer::fill(MeshMap *mesh_map)
{
clearMeshes();
@ -167,16 +170,20 @@ void SolidCommandBuffer::fill(SolidPassMeshMap *mesh_map)
Material::SHADERTYPE_ALPHA_TEST,
Material::SHADERTYPE_SOLID_UNLIT,
Material::SHADERTYPE_SPHERE_MAP,
Material::SHADERTYPE_VEGETATION);
Material::SHADERTYPE_VEGETATION,
Material::SHADERTYPE_SOLID_SKINNED_MESH,
Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH,
Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH);
fillInstanceData<InstanceDataThreeTex, SolidPassMeshMap>
fillInstanceData<InstanceDataThreeTex, MeshMap>
(mesh_map, three_tex_material_list, InstanceTypeThreeTex);
std::vector<int> four_tex_material_list =
createVector<int>(Material::SHADERTYPE_DETAIL_MAP,
Material::SHADERTYPE_NORMAL_MAP);
Material::SHADERTYPE_NORMAL_MAP,
Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH);
fillInstanceData<InstanceDataFourTex, SolidPassMeshMap>
fillInstanceData<InstanceDataFourTex, MeshMap>
(mesh_map, four_tex_material_list, InstanceTypeFourTex);
if (!CVS->supportsAsyncInstanceUpload())
@ -189,7 +196,7 @@ ShadowCommandBuffer::ShadowCommandBuffer(): CommandBuffer()
}
// ----------------------------------------------------------------------------
void ShadowCommandBuffer::fill(OtherMeshMap *mesh_map)
void ShadowCommandBuffer::fill(MeshMap *mesh_map)
{
clearMeshes();
@ -215,9 +222,17 @@ void ShadowCommandBuffer::fill(OtherMeshMap *mesh_map)
+ Material::SHADERTYPE_VEGETATION);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SPLATTING);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SOLID_SKINNED_MESH);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH);
}
fillInstanceData<InstanceDataSingleTex, OtherMeshMap>
fillInstanceData<InstanceDataSingleTex, MeshMap>
(mesh_map, shadow_tex_material_list, InstanceTypeShadow);
if (!CVS->supportsAsyncInstanceUpload())
@ -231,7 +246,7 @@ ReflectiveShadowMapCommandBuffer::ReflectiveShadowMapCommandBuffer()
}
// ----------------------------------------------------------------------------
void ReflectiveShadowMapCommandBuffer::fill(OtherMeshMap *mesh_map)
void ReflectiveShadowMapCommandBuffer::fill(MeshMap *mesh_map)
{
clearMeshes();
@ -245,7 +260,7 @@ void ReflectiveShadowMapCommandBuffer::fill(OtherMeshMap *mesh_map)
Material::SHADERTYPE_DETAIL_MAP,
Material::SHADERTYPE_NORMAL_MAP);
fillInstanceData<InstanceDataSingleTex, OtherMeshMap>
fillInstanceData<InstanceDataSingleTex, MeshMap>
(mesh_map, rsm_material_list, InstanceTypeRSM);
if (!CVS->supportsAsyncInstanceUpload())
@ -259,14 +274,14 @@ GlowCommandBuffer::GlowCommandBuffer()
}
// ----------------------------------------------------------------------------
void GlowCommandBuffer::fill(OtherMeshMap *mesh_map)
void GlowCommandBuffer::fill(MeshMap *mesh_map)
{
clearMeshes();
if(!CVS->supportsAsyncInstanceUpload())
mapIndirectBuffer();
fillInstanceData<GlowInstanceData, OtherMeshMap>
fillInstanceData<GlowInstanceData, MeshMap>
(mesh_map, createVector<int>(0), InstanceTypeGlow);
if (!CVS->supportsAsyncInstanceUpload())
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);

View File

@ -31,7 +31,7 @@
#include <array>
#include <unordered_map>
typedef STK::Tuple<scene::ISceneNode*, core::vector2df, core::vector2df> InstanceSettings;
typedef STK::Tuple<scene::ISceneNode*, core::vector2df, core::vector2df, int32_t> InstanceSettings;
struct InstanceList
{
@ -39,10 +39,7 @@ struct InstanceList
std::vector<InstanceSettings> m_instance_settings;
};
typedef std::unordered_map <std::pair<scene::IMeshBuffer*, RenderInfo*>, InstanceList,
MeshRenderInfoHash, MeshRenderInfoEquals> SolidPassMeshMap;
typedef std::unordered_map <irr::scene::IMeshBuffer *, InstanceList > OtherMeshMap;
typedef std::unordered_map <irr::scene::IMeshBuffer *, InstanceList > MeshMap;
// ----------------------------------------------------------------------------
/** Fill origin, orientation and scale attributes
@ -271,7 +268,7 @@ class SolidCommandBuffer: public CommandBuffer<static_cast<int>(Material::SHADER
{
public:
SolidCommandBuffer();
void fill(SolidPassMeshMap *mesh_map);
void fill(MeshMap *mesh_map);
// ----------------------------------------------------------------------------
/** First rendering pass; draw all meshes associated with the same material
@ -458,7 +455,7 @@ class ShadowCommandBuffer: public CommandBuffer<4*static_cast<int>(Material::SHA
{
public:
ShadowCommandBuffer();
void fill(OtherMeshMap *mesh_map);
void fill(MeshMap *mesh_map);
// ----------------------------------------------------------------------------
/** Draw shadowmaps for meshes with the same material
@ -532,7 +529,7 @@ class ReflectiveShadowMapCommandBuffer: public CommandBuffer<static_cast<int>(Ma
{
public:
ReflectiveShadowMapCommandBuffer();
void fill(OtherMeshMap *mesh_map);
void fill(MeshMap *mesh_map);
// ----------------------------------------------------------------------------
/** Draw reflective shadow map for meshes with the same material
@ -615,7 +612,7 @@ class GlowCommandBuffer: public CommandBuffer<1>
{
public:
GlowCommandBuffer();
void fill(OtherMeshMap *mesh_map);
void fill(MeshMap *mesh_map);
// ----------------------------------------------------------------------------
/** Draw glowing meshes.

View File

@ -24,6 +24,7 @@
#include "graphics/lod_node.hpp"
#include "graphics/materials.hpp"
#include "graphics/shadow_matrices.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "graphics/stk_billboard.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
@ -31,11 +32,14 @@
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
#include <numeric>
// ----------------------------------------------------------------------------
void DrawCalls::clearLists()
{
ListBlendTransparent::getInstance()->clear();
ListAdditiveTransparent::getInstance()->clear();
ListTranslucentSkinned::getInstance()->clear();
ListTranslucentStandard::getInstance()->clear();
ListTranslucentTangents::getInstance()->clear();
ListTranslucent2TCoords::getInstance()->clear();
@ -43,6 +47,10 @@ void DrawCalls::clearLists()
ListAdditiveTransparentFog::getInstance()->clear();
ListDisplacement::getInstance()->clear();
ListSkinnedSolid::getInstance()->clear();
ListSkinnedAlphaRef::getInstance()->clear();
ListSkinnedNormalMap::getInstance()->clear();
ListSkinnedUnlit::getInstance()->clear();
ListMatDefault::getInstance()->clear();
ListMatAlphaRef::getInstance()->clear();
ListMatSphereMap::getInstance()->clear();
@ -243,8 +251,34 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
for (GLMesh *mesh : node->TransparentMesh[TM_DISPLACEMENT])
pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation());
int32_t skinning_offset = 0;
STKAnimatedMesh* am = dynamic_cast<STKAnimatedMesh*>(Node);
if (am && am->useHardwareSkinning() &&
(!culled_for_cams[0] || !culled_for_cams[1] || !culled_for_cams[2] ||
!culled_for_cams[3] || !culled_for_cams[4] || !culled_for_cams[5]))
{
skinning_offset = getSkinningOffset() + 1/*reserved identity matrix*/;
if (skinning_offset + am->getTotalJoints() >
SharedGPUObjects::getMaxMat4Size())
{
Log::error("DrawCalls", "Don't have enough space to render skinned"
" mesh %s! Max joints can hold: %d",
am->getMeshDebugName().c_str(),
SharedGPUObjects::getMaxMat4Size());
return;
}
m_mesh_for_skinning.insert(am);
am->setSkinningOffset(skinning_offset * 16 * sizeof(float));
}
if (!culled_for_cams[0])
{
for (GLMesh *mesh : node->TransparentMesh[TM_TRANSLUCENT_SKN])
{
pushVector(ListTranslucentSkinned::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->texture_trans,
skinning_offset, (mesh->m_render_info && mesh->m_render_info->isTransparent() ? custom_alpha : 1.0f));
}
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
@ -255,7 +289,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{
m_glow_pass_mesh[mesh->mb].m_mesh = mesh;
m_glow_pass_mesh[mesh->mb].m_instance_settings
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f));
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f), skinning_offset);
}
if (Mat == Material::SHADERTYPE_SPLATTING)
{
@ -267,15 +301,11 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
}
else
{
// Only take render info into account if the node is not static (animated)
// So they can have different animation
std::pair<scene::IMeshBuffer*, RenderInfo*> mesh_render_info(mesh->mb,
dynamic_cast<STKMeshSceneNode*>(Node) == NULL ? mesh->m_render_info : NULL);
m_solid_pass_mesh[Mat][mesh_render_info].m_mesh = mesh;
m_solid_pass_mesh[Mat][mesh_render_info].m_instance_settings.emplace_back(Node, mesh->texture_trans,
m_solid_pass_mesh[Mat][mesh->mb].m_mesh = mesh;
m_solid_pass_mesh[Mat][mesh->mb].m_instance_settings.emplace_back(Node, mesh->texture_trans,
(mesh->m_render_info && mesh->m_material ?
core::vector2df(mesh->m_render_info->getHue(), mesh->m_material->getColorizationFactor()) :
core::vector2df(0.0f, 0.0f)));
core::vector2df(0.0f, 0.0f)), skinning_offset);
}
}
}
@ -288,6 +318,28 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID_SKINNED_MESH:
ListSkinnedSolid::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
(mesh->m_render_info && mesh->m_material ?
core::vector2df(mesh->m_render_info->getHue(), mesh->m_material->getColorizationFactor()) :
core::vector2df(0.0f, 0.0f)), skinning_offset);
break;
case Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH:
ListSkinnedAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
(mesh->m_render_info && mesh->m_material ?
core::vector2df(mesh->m_render_info->getHue(), mesh->m_material->getColorizationFactor()) :
core::vector2df(0.0f, 0.0f)), skinning_offset);
break;
case Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH:
ListSkinnedUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
core::vector2df(0.0f, 0.0f), skinning_offset);
break;
case Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH:
ListSkinnedNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
(mesh->m_render_info && mesh->m_material ?
core::vector2df(mesh->m_render_info->getHue(), mesh->m_material->getColorizationFactor()) :
core::vector2df(0.0f, 0.0f)), skinning_offset);
break;
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
(mesh->m_render_info && mesh->m_material ?
@ -351,7 +403,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{
m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_mesh = mesh;
m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_instance_settings
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f));
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f), skinning_offset);
}
}
else
@ -363,6 +415,22 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID_SKINNED_MESH:
ListSkinnedSolid::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
core::vector2df(0.0f, 0.0f), skinning_offset);
break;
case Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH:
ListSkinnedAlphaRef::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
core::vector2df(0.0f, 0.0f), skinning_offset);
break;
case Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH:
ListSkinnedUnlit::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
core::vector2df(0.0f, 0.0f), skinning_offset);
break;
case Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH:
ListSkinnedNormalMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans,
core::vector2df(0.0f, 0.0f), skinning_offset);
break;
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans, core::vector2df(0.0f, 0.0f));
break;
@ -419,7 +487,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{
m_reflective_shadow_map_mesh[Mat][mesh->mb].m_mesh = mesh;
m_reflective_shadow_map_mesh[Mat][mesh->mb].m_instance_settings
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f));
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f), skinning_offset);
}
}
}
@ -432,6 +500,12 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{
switch (Mat)
{
// Todo: RSMs
case Material::SHADERTYPE_SOLID_SKINNED_MESH:
case Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH:
case Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH:
case Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH:
break;
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->texture_trans, core::vector2df(0.0f, 0.0f));
break;
@ -551,7 +625,7 @@ void DrawCalls::prepareDrawCalls( ShadowMatrices& shadow_matrices,
{
m_wind_dir = getWindDir();
clearLists();
m_mesh_for_skinning.clear();
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
m_solid_pass_mesh[Mat].clear();
@ -569,6 +643,7 @@ void DrawCalls::prepareDrawCalls( ShadowMatrices& shadow_matrices,
&m_immediate_draw_list, camnode, shadow_matrices);
PROFILER_POP_CPU_MARKER();
irr_driver->setSkinningJoint(getSkinningOffset());
// Add a 1 s timeout
if (!m_sync)
m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
@ -688,7 +763,13 @@ void DrawCalls::drawIndirectSolidFirstPass() const
m_solid_cmd_buffer->drawIndirectFirstPass<SphereMap>();
m_solid_cmd_buffer->drawIndirectFirstPass<GrassMat>(m_wind_dir);
m_solid_cmd_buffer->drawIndirectFirstPass<DetailMat>();
m_solid_cmd_buffer->drawIndirectFirstPass<NormalMat>();
m_solid_cmd_buffer->drawIndirectFirstPass<NormalMat>();
if (!CVS->supportsHardwareSkinning()) return;
m_solid_cmd_buffer->drawIndirectFirstPass<SkinnedSolid>();
m_solid_cmd_buffer->drawIndirectFirstPass<SkinnedAlphaRef>();
m_solid_cmd_buffer->drawIndirectFirstPass<SkinnedUnlitMat>();
m_solid_cmd_buffer->drawIndirectFirstPass<SkinnedNormalMat>();
}
// ----------------------------------------------------------------------------
@ -704,7 +785,13 @@ void DrawCalls::multidrawSolidFirstPass() const
m_solid_cmd_buffer->multidrawFirstPass<UnlitMat>();
m_solid_cmd_buffer->multidrawFirstPass<GrassMat>(m_wind_dir);
m_solid_cmd_buffer->multidrawFirstPass<NormalMat>();
m_solid_cmd_buffer->multidrawFirstPass<DetailMat>();
m_solid_cmd_buffer->multidrawFirstPass<DetailMat>();
if (!CVS->supportsHardwareSkinning()) return;
m_solid_cmd_buffer->multidrawFirstPass<SkinnedSolid>();
m_solid_cmd_buffer->multidrawFirstPass<SkinnedAlphaRef>();
m_solid_cmd_buffer->multidrawFirstPass<SkinnedUnlitMat>();
m_solid_cmd_buffer->multidrawFirstPass<SkinnedNormalMat>();
}
// ----------------------------------------------------------------------------
@ -724,6 +811,12 @@ void DrawCalls::drawIndirectSolidSecondPass(const std::vector<GLuint> &prefilled
m_solid_cmd_buffer->drawIndirectSecondPass<GrassMat>(prefilled_tex, m_wind_dir);
m_solid_cmd_buffer->drawIndirectSecondPass<DetailMat>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<NormalMat>(prefilled_tex);
if (!CVS->supportsHardwareSkinning()) return;
m_solid_cmd_buffer->drawIndirectSecondPass<SkinnedSolid>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<SkinnedAlphaRef>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<SkinnedUnlitMat>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<SkinnedNormalMat>(prefilled_tex);
}
// ----------------------------------------------------------------------------
@ -742,6 +835,12 @@ void DrawCalls::multidrawSolidSecondPass(const std::vector<uint64_t> &handles) c
m_solid_cmd_buffer->multidraw2ndPass<NormalMat>(handles);
m_solid_cmd_buffer->multidraw2ndPass<DetailMat>(handles);
m_solid_cmd_buffer->multidraw2ndPass<GrassMat>(handles, m_wind_dir);
if (!CVS->supportsHardwareSkinning()) return;
m_solid_cmd_buffer->multidraw2ndPass<SkinnedSolid>(handles);
m_solid_cmd_buffer->multidraw2ndPass<SkinnedAlphaRef>(handles);
m_solid_cmd_buffer->multidraw2ndPass<SkinnedUnlitMat>(handles);
m_solid_cmd_buffer->multidraw2ndPass<SkinnedNormalMat>(handles);
}
// ----------------------------------------------------------------------------
@ -792,6 +891,12 @@ void DrawCalls::drawIndirectShadows(unsigned cascade) const
m_shadow_cmd_buffer->drawIndirect<NormalMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<SplattingMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<SphereMap>(cascade);
if (!CVS->supportsHardwareSkinning()) return;
m_shadow_cmd_buffer->drawIndirect<SkinnedSolid>(cascade);
m_shadow_cmd_buffer->drawIndirect<SkinnedAlphaRef>(cascade);
m_shadow_cmd_buffer->drawIndirect<SkinnedUnlitMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<SkinnedNormalMat>(cascade);
}
// ----------------------------------------------------------------------------
@ -810,6 +915,12 @@ void DrawCalls::multidrawShadows(unsigned cascade) const
m_shadow_cmd_buffer->multidrawShadow<GrassMat,irr::core::vector3df>(cascade, m_wind_dir);
m_shadow_cmd_buffer->multidrawShadow<SplattingMat>(cascade);
m_shadow_cmd_buffer->multidrawShadow<SphereMap>(cascade);
if (!CVS->supportsHardwareSkinning()) return;
m_shadow_cmd_buffer->multidrawShadow<SkinnedSolid>(cascade);
m_shadow_cmd_buffer->multidrawShadow<SkinnedAlphaRef>(cascade);
m_shadow_cmd_buffer->multidrawShadow<SkinnedUnlitMat>(cascade);
m_shadow_cmd_buffer->multidrawShadow<SkinnedNormalMat>(cascade);
}
// ----------------------------------------------------------------------------
@ -866,4 +977,12 @@ void DrawCalls::multidrawGlow() const
}
#endif // !defined(USE_GLES2)
#endif // !SERVER_ONLY
// ----------------------------------------------------------------------------
int32_t DrawCalls::getSkinningOffset() const
{
return std::accumulate(m_mesh_for_skinning.begin(),
m_mesh_for_skinning.end(), 0, []
(const size_t previous, const STKAnimatedMesh* m)
{ return previous + m->getTotalJoints(); });
} // getSkinningOffset
#endif // !SERVER_ONLY

View File

@ -25,6 +25,7 @@
class ParticleSystemProxy;
class ShadowMatrices;
class STKAnimatedMesh;
class STKBillboard;
class DrawCalls
@ -37,14 +38,15 @@ private:
std::vector<irr::scene::ISceneNode *> m_immediate_draw_list;
std::vector<STKBillboard *> m_billboard_list;
std::vector<ParticleSystemProxy *> m_particles_list;
std::set<STKAnimatedMesh*> m_mesh_for_skinning;
std::vector<float> m_bounding_boxes;
/** meshes to draw */
SolidPassMeshMap m_solid_pass_mesh [ Material::SHADERTYPE_COUNT];
OtherMeshMap m_shadow_pass_mesh [4 * Material::SHADERTYPE_COUNT];
OtherMeshMap m_reflective_shadow_map_mesh [ Material::SHADERTYPE_COUNT];
OtherMeshMap m_glow_pass_mesh;
MeshMap m_solid_pass_mesh [ Material::SHADERTYPE_COUNT];
MeshMap m_shadow_pass_mesh [4 * Material::SHADERTYPE_COUNT];
MeshMap m_reflective_shadow_map_mesh [ Material::SHADERTYPE_COUNT];
MeshMap m_glow_pass_mesh;
#if !defined(USE_GLES2)
/** meshes data in VRAM */
@ -106,6 +108,7 @@ public:
void drawIndirectGlow() const;
void multidrawGlow() const;
void renderBoundingBoxes();
int32_t getSkinningOffset() const;
};
#endif // !SERVER_ONLY

View File

@ -185,6 +185,12 @@ void GL3DrawPolicy::drawSolidFirstPass(const DrawCalls& draw_calls) const
renderMeshes1stPass<NormalMat, 2, 1>();
renderMeshes1stPass<SphereMap, 2, 1>();
renderMeshes1stPass<DetailMat, 2, 1>();
if (!CVS->supportsHardwareSkinning()) return;
renderMeshes1stPass<SkinnedSolid, 5, 2, 1>();
renderMeshes1stPass<SkinnedAlphaRef, 5, 3, 2, 1>();
renderMeshes1stPass<SkinnedUnlitMat, 5, 3, 2, 1>();
renderMeshes1stPass<SkinnedNormalMat, 5, 2, 1>();
}
// ----------------------------------------------------------------------------
@ -200,6 +206,12 @@ void GL3DrawPolicy::drawSolidSecondPass (const DrawCalls& draw_calls,
renderMeshes2ndPass<DetailMat, 1 > (handles, prefilled_tex);
renderMeshes2ndPass<GrassMat, 4, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<NormalMat, 4, 3, 1> (handles, prefilled_tex);
if (!CVS->supportsHardwareSkinning()) return;
renderMeshes2ndPass<SkinnedSolid, 5, 4, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<SkinnedAlphaRef, 5, 4, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<SkinnedUnlitMat, 5, 3, 1 > (handles, prefilled_tex);
renderMeshes2ndPass<SkinnedNormalMat, 5, 4, 3, 1> (handles, prefilled_tex);
}
// ----------------------------------------------------------------------------
@ -222,6 +234,12 @@ void GL3DrawPolicy::drawShadows(const DrawCalls& draw_calls, unsigned cascade) c
renderShadow<AlphaRef, 1>(cascade);
renderShadow<UnlitMat, 1>(cascade);
renderShadow<GrassMat, 3, 1>(cascade);
if (!CVS->supportsHardwareSkinning()) return;
renderShadow<SkinnedSolid, 5, 1>(cascade);
renderShadow<SkinnedAlphaRef, 5, 1>(cascade);
renderShadow<SkinnedUnlitMat, 5, 1>(cascade);
renderShadow<SkinnedNormalMat, 5, 1>(cascade);
}
// ----------------------------------------------------------------------------

View File

@ -242,6 +242,14 @@ void AbstractGeometryPasses::renderTransparent(const DrawCalls& draw_calls,
glBlendEquation(GL_FUNC_ADD);
glEnable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
if (CVS->supportsHardwareSkinning())
{
renderTransparenPass<Shaders::SkinnedTransparentShader, video::EVT_SKINNED_MESH, 4, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListTranslucentSkinned::getInstance());
}
renderTransparenPass<Shaders::TransparentShader, video::EVT_STANDARD, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListTranslucentStandard::getInstance());

View File

@ -142,6 +142,22 @@ public:
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)48);
break;
case video::EVT_SKINNED_MESH:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)12);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, getVertexPitchFromType(tp), (GLvoid*)24);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)28);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)44);
glEnableVertexAttribArray(5);
glVertexAttribIPointer(5, 4, GL_INT, getVertexPitchFromType(tp), (GLvoid*)60);
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)76);
break;
}
}
};

View File

@ -143,6 +143,8 @@ IrrDriver::IrrDriver()
m_boundingboxesviz = false;
m_last_light_bucket_distance = 0;
m_clear_color = video::SColor(255, 100, 101, 140);
m_skinning_joint = 0;
} // IrrDriver
// ----------------------------------------------------------------------------
@ -917,7 +919,6 @@ void IrrDriver::applyResolutionSettings()
// FIXME: this load sequence is (mostly) duplicated from main.cpp!!
// That's just error prone
// (we're sure to update main.cpp at some point and forget this one...)
ShaderBase::updateShaders();
VAOManager::getInstance()->kill();
resetTextureTable();
cleanUnicolorTextures();
@ -928,6 +929,7 @@ void IrrDriver::applyResolutionSettings()
}
delete m_renderer;
initDevice();
ShaderBase::updateShaders();
font_manager = new FontManager();
font_manager->loadFonts();
@ -1959,10 +1961,12 @@ void IrrDriver::displayFPS()
if ((UserConfigParams::m_artist_debug_mode)&&(CVS->isGLSL()))
{
fps_string = _("FPS: %d/%d/%d - PolyCount: %d Solid, "
"%d Shadows - LightDist : %d",
fps_string = StringUtils::insertValues
(L"FPS: %d/%d/%d - PolyCount: %d Solid, "
"%d Shadows - LightDist : %d, Total skinning joints: %d",
min, fps, max, m_renderer->getPolyCount(SOLID_NORMAL_AND_DEPTH_PASS),
m_renderer->getPolyCount(SHADOW_PASS), m_last_light_bucket_distance);
m_renderer->getPolyCount(SHADOW_PASS), m_last_light_bucket_distance,
m_skinning_joint);
}
else
fps_string = _("FPS: %d/%d/%d - %d KTris", min, fps, max, (int)roundf(kilotris));

View File

@ -177,6 +177,7 @@ private:
unsigned m_last_light_bucket_distance;
unsigned m_skinning_joint;
u32 m_renderpass;
class STKMeshSceneNode *m_sun_interposer;
core::vector3df m_sun_direction;
@ -296,6 +297,7 @@ public:
void showPointer();
void hidePointer();
void setLastLightBucketDistance(unsigned d) { m_last_light_bucket_distance = d; }
void setSkinningJoint(unsigned d) { m_skinning_joint = d; }
bool isPointerShown() const { return m_pointer_shown; }
core::position2di getMouseLocation();

View File

@ -48,15 +48,19 @@ public:
enum ShaderType
{
SHADERTYPE_SOLID = 0,
SHADERTYPE_SOLID_SKINNED_MESH,
SHADERTYPE_ALPHA_TEST,
SHADERTYPE_ALPHA_TEST_SKINNED_MESH,
SHADERTYPE_ALPHA_BLEND,
SHADERTYPE_ADDITIVE,
SHADERTYPE_SOLID_UNLIT,
SHADERTYPE_SOLID_UNLIT_SKINNED_MESH,
/** Effect that makes grass wave as in the wind */
SHADERTYPE_VEGETATION,
SHADERTYPE_WATER,
SHADERTYPE_SPHERE_MAP,
SHADERTYPE_NORMAL_MAP,
SHADERTYPE_NORMAL_MAP_SKINNED_MESH,
SHADERTYPE_DETAIL_MAP,
SHADERTYPE_SPLATTING,
SHADERTYPE_COUNT,

View File

@ -19,6 +19,37 @@
#ifndef SERVER_ONLY
const STK::Tuple<size_t> SkinnedSolid::FirstPassTextures
= STK::Tuple<size_t>(1);
const STK::Tuple<size_t, size_t, size_t> SkinnedSolid::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 1, 2);
const STK::Tuple<> SkinnedSolid::ShadowTextures;
const STK::Tuple<size_t> SkinnedSolid::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> SkinnedAlphaRef::FirstPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t, size_t, size_t> SkinnedAlphaRef::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 1, 2);
const STK::Tuple<size_t> SkinnedAlphaRef::ShadowTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> SkinnedAlphaRef::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> SkinnedUnlitMat::FirstPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t> SkinnedUnlitMat::SecondPassTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> SkinnedUnlitMat::ShadowTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> SkinnedUnlitMat::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> SkinnedNormalMat::FirstPassTextures
= STK::Tuple<size_t, size_t>(3, 1);
const STK::Tuple<size_t, size_t, size_t> SkinnedNormalMat::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 1, 2);
const STK::Tuple<> SkinnedNormalMat::ShadowTextures;
const STK::Tuple<size_t> SkinnedNormalMat::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t> DefaultMaterial::FirstPassTextures
= STK::Tuple<size_t>(1);
const STK::Tuple<size_t, size_t, size_t> DefaultMaterial::SecondPassTextures

View File

@ -145,18 +145,17 @@ public:
InstancedShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedshadow.vert",
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_shadow.vert",
GL_FRAGMENT_SHADER, "shadow.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedshadow.vert",
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_shadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "shadow.frag");
}
@ -297,8 +296,8 @@ public:
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "normalmap.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix");
assignSamplerNames(1, "normalMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
0, "DiffuseForAlpha", ST_TRILINEAR_ANISOTROPIC_FILTERED);
assignSamplerNames(0, "normalMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glossMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // NormalMapShader
}; // NormalMapShader
@ -391,12 +390,12 @@ public:
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT,GL_VERTEX_SHADER, "instanciedshadow.vert",
loadProgram(OBJECT,GL_VERTEX_SHADER, "instanced_shadow.vert",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
else
{
loadProgram(OBJECT,GL_VERTEX_SHADER, "instanciedshadow.vert",
loadProgram(OBJECT,GL_VERTEX_SHADER, "instanced_shadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
@ -523,12 +522,12 @@ public:
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedgrassshadow.vert",
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_grassshadow.vert",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedgrassshadow.vert",
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_grassshadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
@ -618,8 +617,415 @@ public:
} // InstancedDetailedObjectPass2Shader
}; // InstancedDetailedObjectPass2Shader
// ============================================================================
class SkinnedPass1Shader : public TextureShader<SkinnedPass1Shader, 1,
core::matrix4, core::matrix4,
int>
{
public:
SkinnedPass1Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "object_pass1.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix", "skinning_offset");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedPass1Shader
}; // SkinnedPass1Shader
// ============================================================================
class InstancedSkinnedPass1Shader : public TextureShader<InstancedSkinnedPass1Shader, 1>
{
public:
InstancedSkinnedPass1Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_object_pass1.frag");
assignUniforms();
assignSamplerNames(0, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedPass1Shader
}; // InstancedSkinnedPass1Shader
// ============================================================================
class SkinnedPass2Shader : public TextureShader<SkinnedPass2Shader, 6,
core::matrix4, core::vector2df,
core::vector2df, int >
{
public:
SkinnedPass2Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "object_pass2.frag");
assignUniforms("ModelMatrix", "texture_trans", "color_change",
"skinning_offset");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedPass2Shader
}; // SkinnedPass2Shader
// ============================================================================
class InstancedSkinnedPass2Shader : public TextureShader<InstancedSkinnedPass2Shader, 6>
{
public:
InstancedSkinnedPass2Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_object_pass2.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedPass2Shader
}; // InstancedSkinnedPass2Shader
// ============================================================================
class SkinnedRefPass1Shader : public TextureShader<SkinnedRefPass1Shader, 2,
core::matrix4,
core::matrix4,
core::vector2df, int>
{
public:
SkinnedRefPass1Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "objectref_pass1.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix", "texture_trans",
"skinning_offset");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedRefPass1Shader
}; // SkinnedRefPass1Shader
// ============================================================================
class InstancedSkinnedRefPass1Shader : public TextureShader<InstancedSkinnedRefPass1Shader, 2>
{
public:
InstancedSkinnedRefPass1Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_objectref_pass1.frag");
assignUniforms();
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedRefPass1Shader
}; // InstancedSkinnedRefPass1Shader
// ============================================================================
class SkinnedRefPass2Shader : public TextureShader<SkinnedRefPass2Shader, 6,
core::matrix4,
core::vector2df,
core::vector2df, int>
{
public:
SkinnedRefPass2Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "objectref_pass2.frag");
assignUniforms("ModelMatrix", "texture_trans", "color_change",
"skinning_offset");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedRefPass2Shader
}; // SkinnedRefPass2Shader
// ============================================================================
class InstancedSkinnedRefPass2Shader : public TextureShader<InstancedSkinnedRefPass2Shader, 6>
{
public:
InstancedSkinnedRefPass2Shader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_objectref_pass2.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedRefPass2Shader
}; // InstancedSkinnedRefPass2Shader
// ============================================================================
class SkinnedUnlitShader : public TextureShader<SkinnedUnlitShader, 4,
core::matrix4, core::vector2df,
int>
{
public:
SkinnedUnlitShader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "object_unlit.frag");
assignUniforms("ModelMatrix", "texture_trans", "skinning_offset");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedUnlitShader
}; // SkinnedUnlitShader
// ============================================================================
class InstancedSkinnedUnlitShader : public TextureShader<InstancedSkinnedUnlitShader, 4>
{
public:
InstancedSkinnedUnlitShader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_object_unlit.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedUnlitShader
}; // InstancedSkinnedUnlitShader
// ============================================================================
class SkinnedNormalMapShader : public TextureShader<SkinnedNormalMapShader, 2,
core::matrix4,
core::matrix4, int>
{
public:
SkinnedNormalMapShader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "normalmap.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix", "skinning_offset");
assignSamplerNames(0, "normalMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glossMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedNormalMapShader
}; // SkinnedNormalMapShader
// ============================================================================
class InstancedSkinnedNormalMapShader : public TextureShader<InstancedSkinnedNormalMapShader, 2>
{
public:
InstancedSkinnedNormalMapShader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_normalmap.frag");
assignUniforms();
assignSamplerNames(0, "normalMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glossMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedNormalMapShader
}; // InstancedSkinnedNormalMapShader
// ============================================================================
class SkinnedShadowShader : public TextureShader<SkinnedShadowShader, 0,
core::matrix4, int, int>
{
public:
SkinnedShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150 || !CVS->supportsHardwareSkinning())
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning_shadow.vert",
GL_FRAGMENT_SHADER, "shadow.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning_shadow.vert",
GL_GEOMETRY_SHADER, "shadow.geom",
GL_FRAGMENT_SHADER, "shadow.frag");
}
assignUniforms("ModelMatrix", "skinning_offset", "layer");
#endif
} // SkinnedShadowShader
}; // SkinnedShadowShader
// ============================================================================
class InstancedSkinnedShadowShader : public TextureShader<InstancedSkinnedShadowShader, 0, int>
{
public:
InstancedSkinnedShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150 || !CVS->supportsHardwareSkinning())
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning_shadow.vert",
GL_FRAGMENT_SHADER, "shadow.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning_shadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "shadow.frag");
}
assignUniforms("layer");
#endif
} // InstancedSkinnedShadowShader
}; // InstancedSkinnedShadowShader
// ============================================================================
class SkinnedRefShadowShader : public TextureShader<SkinnedRefShadowShader, 1,
core::matrix4, int, int>
{
public:
SkinnedRefShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150 || !CVS->supportsHardwareSkinning())
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning_shadow.vert",
GL_FRAGMENT_SHADER, "shadowref.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning_shadow.vert",
GL_GEOMETRY_SHADER, "shadow.geom",
GL_FRAGMENT_SHADER, "shadowref.frag");
}
assignUniforms("ModelMatrix", "skinning_offset", "layer");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
#endif
} // SkinnedRefShadowShader
}; // SkinnedRefShadowShader
// ============================================================================
class InstancedSkinnedRefShadowShader : public TextureShader<InstancedSkinnedRefShadowShader,
1, int>
{
public:
InstancedSkinnedRefShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150 || !CVS->supportsHardwareSkinning())
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning_shadow.vert",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning_shadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
assignUniforms("layer");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
#endif
} // InstancedSkinnedRefShadowShader
}; // InstancedSkinnedRefShadowShader
// ============================================================================
struct SkinnedSolid
{
typedef InstancedSkinnedPass1Shader InstancedFirstPassShader;
typedef InstancedSkinnedPass2Shader InstancedSecondPassShader;
typedef InstancedSkinnedShadowShader InstancedShadowPassShader;
typedef SkinnedPass1Shader FirstPassShader;
typedef SkinnedPass2Shader SecondPassShader;
typedef SkinnedShadowShader ShadowPassShader;
// Todo: RSMs
typedef ListSkinnedSolid List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_SKINNED_MESH;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_SOLID_SKINNED_MESH;
static const enum InstanceType Instance = InstanceTypeThreeTex;
static const STK::Tuple<size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct SkinnedSolid
// ----------------------------------------------------------------------------
struct SkinnedAlphaRef
{
typedef InstancedSkinnedRefPass1Shader InstancedFirstPassShader;
typedef InstancedSkinnedRefPass2Shader InstancedSecondPassShader;
typedef InstancedSkinnedRefShadowShader InstancedShadowPassShader;
typedef SkinnedRefPass1Shader FirstPassShader;
typedef SkinnedRefPass2Shader SecondPassShader;
typedef SkinnedRefShadowShader ShadowPassShader;
// Todo: RSMs
typedef ListSkinnedAlphaRef List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_SKINNED_MESH;
static const enum Material::ShaderType MaterialType =
Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH;
static const enum InstanceType Instance = InstanceTypeThreeTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<size_t> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct SkinnedAlphaRef
// ----------------------------------------------------------------------------
struct SkinnedNormalMat
{
typedef InstancedSkinnedNormalMapShader InstancedFirstPassShader;
typedef InstancedSkinnedPass2Shader InstancedSecondPassShader;
typedef InstancedSkinnedShadowShader InstancedShadowPassShader;
typedef SkinnedNormalMapShader FirstPassShader;
typedef SkinnedPass2Shader SecondPassShader;
typedef SkinnedShadowShader ShadowPassShader;
// Todo: RSMs
typedef ListSkinnedNormalMap List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_SKINNED_MESH;
static const enum Material::ShaderType MaterialType =
Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH;
static const enum InstanceType Instance = InstanceTypeFourTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct SkinnedNormalMat
// ----------------------------------------------------------------------------
struct SkinnedUnlitMat
{
typedef InstancedSkinnedRefPass1Shader InstancedFirstPassShader;
typedef InstancedSkinnedUnlitShader InstancedSecondPassShader;
typedef InstancedSkinnedRefShadowShader InstancedShadowPassShader;
typedef SkinnedRefPass1Shader FirstPassShader;
typedef SkinnedUnlitShader SecondPassShader;
typedef SkinnedRefShadowShader ShadowPassShader;
// Todo: RSMs
typedef ListSkinnedUnlit List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_SKINNED_MESH;
static const enum Material::ShaderType MaterialType =
Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH;
static const enum InstanceType Instance = InstanceTypeThreeTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t> SecondPassTextures;
static const STK::Tuple<size_t> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct SkinnedUnlitMat
// ----------------------------------------------------------------------------
struct DefaultMaterial
{
typedef InstancedObjectPass1Shader InstancedFirstPassShader;

View File

@ -421,6 +421,8 @@ scene::IMesh* MeshTools::createMeshWithTangents(scene::IMesh* mesh,
vNew = v[idx[i]];
}
break;
default:
break;
}
core::map<video::S3DVertexTangents, int>::Node* n = vertMap.find(vNew);
if (n)
@ -480,54 +482,5 @@ scene::IMesh* MeshTools::createMeshWithTangents(scene::IMesh* mesh,
void MeshTools::createSkinnedMeshWithTangents(scene::ISkinnedMesh* mesh,
bool(*predicate)(scene::IMeshBuffer*))
{
core::array<scene::SSkinMeshBuffer*>& all_mb = mesh->getMeshBuffers();
const int all_mb_size = all_mb.size();
for (int i = 0; i < all_mb_size; i++)
{
scene::SSkinMeshBuffer* mb = all_mb[i];
if (mb && predicate(mb))
{
mb->convertToTangents();
const int index_count = mb->getIndexCount();
uint16_t* idx = mb->getIndices();
video::S3DVertexTangents* v =
(video::S3DVertexTangents*)mb->getVertices();
for (int i = 0; i < index_count; i += 3)
{
calculateTangents(
v[idx[i+0]].Normal,
v[idx[i+0]].Tangent,
v[idx[i+0]].Binormal,
v[idx[i+0]].Pos,
v[idx[i+1]].Pos,
v[idx[i+2]].Pos,
v[idx[i+0]].TCoords,
v[idx[i+1]].TCoords,
v[idx[i+2]].TCoords);
calculateTangents(
v[idx[i+1]].Normal,
v[idx[i+1]].Tangent,
v[idx[i+1]].Binormal,
v[idx[i+1]].Pos,
v[idx[i+2]].Pos,
v[idx[i+0]].Pos,
v[idx[i+1]].TCoords,
v[idx[i+2]].TCoords,
v[idx[i+0]].TCoords);
calculateTangents(
v[idx[i+2]].Normal,
v[idx[i+2]].Tangent,
v[idx[i+2]].Binormal,
v[idx[i+2]].Pos,
v[idx[i+0]].Pos,
v[idx[i+1]].Pos,
v[idx[i+2]].TCoords,
v[idx[i+0]].TCoords,
v[idx[i+1]].TCoords);
}
}
}
mesh->convertMeshToTangents(predicate);
}

View File

@ -19,197 +19,16 @@
#ifndef SERVER_ONLY
#include "graphics/shader.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/gl_headers.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/spherical_harmonics.hpp"
#include "io/file_manager.hpp"
#include "utils/log.hpp"
#include <fstream>
#include <sstream>
#include <stdio.h>
std::string ShaderBase::m_shader_header = "";
std::vector<void(*)()> ShaderBase::m_all_kill_functions;
// ----------------------------------------------------------------------------
/** Returns a string with the content of header.txt (which contains basic
* shader defines).
*/
const std::string& ShaderBase::getHeader()
{
// Only read file first time
if (m_shader_header.empty())
{
std::ifstream stream(file_manager->getShader("header.txt"), std::ios::in);
if (stream.is_open())
{
std::string line = "";
while (getline(stream, line))
m_shader_header += "\n" + line;
stream.close();
}
} // if m_shader_header.empty()
return m_shader_header;
} // getHeader
// ----------------------------------------------------------------------------
/** Loads a single shader.
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
GLuint ShaderBase::loadShader(const std::string &file, unsigned type)
{
GLuint id = glCreateShader(type);
std::ostringstream code;
#if !defined(USE_GLES2)
code << "#version " << CVS->getGLSLVersion()<<"\n";
#else
if (CVS->isGLSL())
code << "#version 300 es\n";
#endif
#if !defined(USE_GLES2)
// Some drivers report that the compute shaders extension is available,
// but they report only OpenGL 3.x version, and thus these extensions
// must be enabled manually. Otherwise the shaders compilation will fail
// because STK tries to use extensions which are available, but disabled
// by default.
if (type == GL_COMPUTE_SHADER)
{
if (CVS->isARBComputeShaderUsable())
code << "#extension GL_ARB_compute_shader : enable\n";
if (CVS->isARBImageLoadStoreUsable())
code << "#extension GL_ARB_shader_image_load_store : enable\n";
if (CVS->isARBArraysOfArraysUsable())
code << "#extension GL_ARB_arrays_of_arrays : enable\n";
}
#endif
if (CVS->isAMDVertexShaderLayerUsable())
code << "#extension GL_AMD_vertex_shader_layer : enable\n";
if (CVS->isARBExplicitAttribLocationUsable())
code << "#extension GL_ARB_explicit_attrib_location : enable\n";
if (CVS->isAZDOEnabled())
{
code << "#extension GL_ARB_bindless_texture : enable\n";
code << "#define Use_Bindless_Texture\n";
}
code << "//" << file << "\n";
if (!CVS->isARBUniformBufferObjectUsable())
code << "#define UBO_DISABLED\n";
if (CVS->isAMDVertexShaderLayerUsable())
code << "#define VSLayer\n";
if (CVS->needsRGBBindlessWorkaround())
code << "#define SRGBBindlessFix\n";
#if !defined(USE_GLES2)
//shader compilation fails with some drivers if there is no precision qualifier
if (type == GL_FRAGMENT_SHADER)
code << "precision mediump float;\n";
#else
int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);
if (precision > 0)
code << "precision highp float;\n";
else
code << "precision mediump float;\n";
#endif
code << getHeader();
std::ifstream stream(file_manager->getShader(file), std::ios::in);
if (stream.is_open())
{
std::string Line = "";
while (getline(stream, Line))
{
const std::string stk_include = "#stk_include";
std::size_t pos = Line.find(stk_include);
if (pos != std::string::npos)
{
std::size_t pos = Line.find("\"");
if (pos == std::string::npos)
{
Log::error("shader", "Invalid #stk_include line: '%s'.", Line.c_str());
continue;
}
std::string filename = Line.substr(pos+1);
pos = filename.find("\"");
if (pos == std::string::npos)
{
Log::error("shader", "Invalid #stk_include line: '%s'.", Line.c_str());
continue;
}
filename = filename.substr(0, pos);
std::ifstream include_stream(file_manager->getShader(filename), std::ios::in);
if (!include_stream.is_open())
{
Log::error("shader", "Couldn't open included shader: '%s'.", filename.c_str());
continue;
}
std::string include_line = "";
while (getline(include_stream, include_line))
{
code << "\n" << include_line;
}
include_stream.close();
}
else
{
code << "\n" << Line;
}
}
stream.close();
}
else
{
Log::error("shader", "Can not open '%s'.", file.c_str());
}
Log::info("shader", "Compiling shader : %s", file.c_str());
const std::string &source = code.str();
char const *source_pointer = source.c_str();
int len = source.size();
glShaderSource(id, 1, &source_pointer, &len);
glCompileShader(id);
GLint result = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int info_length;
Log::error("GLWrap", "Error in shader %s", file.c_str());
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_length);
if (info_length<0)
info_length = 1024;
char *error_message = new char[info_length];
error_message[0] = 0;
glGetShaderInfoLog(id, info_length, NULL, error_message);
Log::error("GLWrap", error_message);
delete[] error_message;
}
glGetError();
return id;
} // loadShader
// ----------------------------------------------------------------------------
/** Loads a transform feedback buffer shader with a given number of varying
* parameters.
@ -238,7 +57,7 @@ int ShaderBase::loadTFBProgram(const std::string &shader_name,
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &info_log_length);
char *error_message = new char[info_log_length];
glGetProgramInfoLog(m_program, info_log_length, NULL, error_message);
Log::error("GLWrap", error_message);
Log::error("ShaderBase", error_message);
delete[] error_message;
}

View File

@ -22,6 +22,7 @@
#include "graphics/central_settings.hpp"
#include "graphics/gl_headers.hpp"
#include "graphics/shader_files_manager.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "utils/singleton.hpp"
@ -40,13 +41,6 @@
*/
class ShaderBase
{
private:
// Static members
/** Stores the context of header.txt, to avoid reading
* this file repeatedly. */
static std::string m_shader_header;
protected:
/** Maintains a list of all shaders. */
static std::vector<void (*)()> m_all_kill_functions;
@ -75,9 +69,13 @@ protected:
void loadAndAttachShader(GLint shader_type, const std::string &name,
Types ... args)
{
GLint shader_id = loadShader(name, shader_type);
GLint shader_id = ShaderFilesManager::getInstance()
->getShaderFile(name, shader_type);
glAttachShader(m_program, shader_id);
glDeleteShader(shader_id);
GLint is_deleted = GL_TRUE;
glGetShaderiv(shader_id, GL_DELETE_STATUS, &is_deleted);
if (is_deleted == GL_FALSE)
glDeleteShader(shader_id);
loadAndAttachShader(args...);
} // loadAndAttachShader
// ------------------------------------------------------------------------
@ -89,9 +87,6 @@ protected:
loadAndAttachShader(shader_type, std::string(name), args...);
} // loadAndAttachShader
// ------------------------------------------------------------------------
const std::string& getHeader();
GLuint loadShader(const std::string &file, unsigned type);
void setAttribute(AttributeType type);
public:
@ -152,6 +147,7 @@ private:
{
bindPoint("MatrixData", 0);
bindPoint("LightingData", 1);
bindPoint("SkinningData", 2);
} // assignUniformsImpl
// ------------------------------------------------------------------------
@ -360,12 +356,12 @@ public:
glGetProgramiv(m_program, GL_LINK_STATUS, &Result);
if (Result == GL_FALSE) {
int info_length;
Log::error("GLWrapp", "Error when linking these shaders :");
Log::error("Shader", "Error when linking these shaders :");
printFileList(args...);
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &info_length);
char *error_message = new char[info_length];
glGetProgramInfoLog(m_program, info_length, NULL, error_message);
Log::error("GLWrapp", error_message);
Log::error("Shader", error_message);
delete[] error_message;
}
} // loadProgram

View File

@ -268,10 +268,12 @@ void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode,
bool hasShadow,
bool forceRTT)
{
if(CVS->isARBUniformBufferObjectUsable())
if (CVS->isARBUniformBufferObjectUsable())
{
glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedGPUObjects::getViewProjectionMatricesUBO());
glBindBufferBase(GL_UNIFORM_BUFFER, 1, SharedGPUObjects::getLightingDataUBO());
if (CVS->supportsHardwareSkinning())
glBindBufferBase(GL_UNIFORM_BUFFER, 2, SharedGPUObjects::getSkinningUBO());
}
irr_driver->getSceneManager()->setActiveCamera(camnode);
@ -639,7 +641,9 @@ ShaderBasedRenderer::ShaderBasedRenderer()
m_skybox = NULL;
m_spherical_harmonics = new SphericalHarmonics(irr_driver->getAmbientLight().toSColor());
m_nb_static_glowing = 0;
Log::info("ShaderBasedRenderer", "Preloading shaders...");
preloadShaderFiles();
if (CVS->isAZDOEnabled())
{
m_geometry_passes = new GeometryPasses<MultidrawPolicy>();
@ -655,7 +659,7 @@ ShaderBasedRenderer::ShaderBasedRenderer()
m_geometry_passes = new GeometryPasses<GL3DrawPolicy>();
Log::info("ShaderBasedRenderer", "Geometry will be rendered with GL3 policy.");
}
m_post_processing = new PostProcessing(irr_driver->getVideoDriver());
}
@ -679,6 +683,7 @@ ShaderBasedRenderer::~ShaderBasedRenderer()
delete m_spherical_harmonics;
delete m_skybox;
delete m_rtts;
ShaderFilesManager::kill();
}
// ----------------------------------------------------------------------------
@ -698,7 +703,7 @@ void ShaderBasedRenderer::onUnloadWorld()
{
delete m_rtts;
m_rtts = NULL;
removeSkyBox();
removeSkyBox();
}
// ----------------------------------------------------------------------------
@ -959,4 +964,60 @@ void ShaderBasedRenderer::renderToTexture(GL3RenderTarget *render_target,
} //renderToTexture
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::preloadShaderFiles()
{
ShaderFilesManager* sfm = ShaderFilesManager::getInstance();
sfm->addShaderFile("object_pass.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("object_pass1.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("splatting.frag", GL_FRAGMENT_SHADER);
if (CVS->supportsHardwareSkinning())
sfm->addShaderFile("skinning.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("transparent.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("coloredquad.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("coloredquad.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("screenquad.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("tonemap.frag", GL_FRAGMENT_SHADER);
if (!GraphicsRestrictions::isDisabled
(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_WORKING))
sfm->addShaderFile("passthrough.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("billboard.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("billboard.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("pointemitter.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("particle.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("particle.frag", GL_FRAGMENT_SHADER);
if (CVS->supportsIndirectInstancingRendering())
{
sfm->addShaderFile("instanced_object_pass.vert", GL_VERTEX_SHADER);
if (CVS->supportsHardwareSkinning())
sfm->addShaderFile("instanced_skinning.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("instanced_object_pass1.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_object_pass2.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_objectref_pass1.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_objectref_pass2.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_object_unlit.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_normalmap.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_grass.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("instanced_grass_pass2.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_objectpass_spheremap.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("instanced_detailed_object_pass2.frag", GL_FRAGMENT_SHADER);
}
else
{
sfm->addShaderFile("object_pass2.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("objectref_pass1.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("objectref_pass2.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("object_unlit.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("normalmap.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("grass_pass.vert", GL_VERTEX_SHADER);
sfm->addShaderFile("grass_pass2.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("objectpass_spheremap.frag", GL_FRAGMENT_SHADER);
sfm->addShaderFile("detailed_object_pass2.frag", GL_FRAGMENT_SHADER);
}
} //preloadShaderFiles
#endif // !SERVER_ONLY

View File

@ -85,7 +85,7 @@ private:
void debugPhysics();
void renderPostProcessing(Camera * const camera);
void preloadShaderFiles();
public:
ShaderBasedRenderer();

View File

@ -0,0 +1,253 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef SERVER_ONLY
#include "graphics/shader_files_manager.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "io/file_manager.hpp"
#include "utils/log.hpp"
#include <fstream>
#include <sstream>
// ----------------------------------------------------------------------------
/** Returns a string with the content of header.txt (which contains basic
* shader defines).
*/
const std::string& ShaderFilesManager::getHeader()
{
// Stores the content of header.txt, to avoid reading this file repeatedly.
static std::string shader_header;
// Only read file first time
if (shader_header.empty())
{
std::ifstream stream(file_manager->getShader("header.txt"), std::ios::in);
if (stream.is_open())
{
std::string line = "";
while (std::getline(stream, line))
shader_header += "\n" + line;
stream.close();
}
} // if shader_header.empty()
return shader_header;
} // getHeader
// ----------------------------------------------------------------------------
/** Loads a single shader. This is NOT cached, use addShaderFile for that.
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
GLuint ShaderFilesManager::loadShader(const std::string &file, unsigned type)
{
const GLuint id = glCreateShader(type);
std::ostringstream code;
#if !defined(USE_GLES2)
code << "#version " << CVS->getGLSLVersion()<<"\n";
#else
if (CVS->isGLSL())
code << "#version 300 es\n";
#endif
#if !defined(USE_GLES2)
// Some drivers report that the compute shaders extension is available,
// but they report only OpenGL 3.x version, and thus these extensions
// must be enabled manually. Otherwise the shaders compilation will fail
// because STK tries to use extensions which are available, but disabled
// by default.
if (type == GL_COMPUTE_SHADER)
{
if (CVS->isARBComputeShaderUsable())
code << "#extension GL_ARB_compute_shader : enable\n";
if (CVS->isARBImageLoadStoreUsable())
code << "#extension GL_ARB_shader_image_load_store : enable\n";
if (CVS->isARBArraysOfArraysUsable())
code << "#extension GL_ARB_arrays_of_arrays : enable\n";
}
#endif
if (CVS->isAMDVertexShaderLayerUsable())
code << "#extension GL_AMD_vertex_shader_layer : enable\n";
if (CVS->isARBExplicitAttribLocationUsable())
code << "#extension GL_ARB_explicit_attrib_location : enable\n";
if (CVS->isAZDOEnabled())
{
code << "#extension GL_ARB_bindless_texture : enable\n";
code << "#define Use_Bindless_Texture\n";
}
code << "//" << file << "\n";
if (!CVS->isARBUniformBufferObjectUsable())
code << "#define UBO_DISABLED\n";
if (CVS->isAMDVertexShaderLayerUsable())
code << "#define VSLayer\n";
if (CVS->needsRGBBindlessWorkaround())
code << "#define SRGBBindlessFix\n";
#if !defined(USE_GLES2)
// shader compilation fails with some drivers if there is no precision
// qualifier
if (type == GL_FRAGMENT_SHADER)
code << "precision mediump float;\n";
#else
int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range,
&precision);
if (precision > 0)
code << "precision highp float;\n";
else
code << "precision mediump float;\n";
#endif
code << "#define MAX_BONES " << SharedGPUObjects::getMaxMat4Size() << "\n";
code << getHeader();
std::ifstream stream(file_manager->getShader(file), std::ios::in);
if (stream.is_open())
{
const std::string stk_include = "#stk_include";
std::string line;
while (std::getline(stream, line))
{
const std::size_t pos = line.find(stk_include);
// load the custom file pointed by the #stk_include directive
if (pos != std::string::npos)
{
// find the start "
std::size_t pos = line.find("\"");
if (pos == std::string::npos)
{
Log::error("ShaderFilesManager", "Invalid #stk_include"
" line: '%s'.", line.c_str());
continue;
}
std::string filename = line.substr(pos + 1);
// find the end "
pos = filename.find("\"");
if (pos == std::string::npos)
{
Log::error("ShaderFilesManager", "Invalid #stk_include"
" line: '%s'.", line.c_str());
continue;
}
filename = filename.substr(0, pos);
// read the whole include file
std::ifstream include_stream(file_manager->getShader(filename), std::ios::in);
if (!include_stream.is_open())
{
Log::error("ShaderFilesManager", "Couldn't open included"
" shader: '%s'.", filename.c_str());
continue;
}
std::string include_line = "";
while (std::getline(include_stream, include_line))
{
code << "\n" << include_line;
}
include_stream.close();
}
else
{
code << "\n" << line;
}
}
stream.close();
}
else
{
Log::error("ShaderFilesManager", "Can not open '%s'.", file.c_str());
}
Log::info("ShaderFilesManager", "Compiling shader : %s", file.c_str());
const std::string &source = code.str();
char const *source_pointer = source.c_str();
int len = source.size();
glShaderSource(id, 1, &source_pointer, &len);
glCompileShader(id);
GLint result = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
// failed to compile
int info_length;
Log::error("ShaderFilesManager", "Error in shader %s", file.c_str());
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_length);
if (info_length < 0)
info_length = 1024;
char *error_message = new char[info_length];
error_message[0] = 0;
glGetShaderInfoLog(id, info_length, NULL, error_message);
Log::error("ShaderFilesManager", error_message);
delete[] error_message;
}
glGetError();
return id;
} // loadShader
// ----------------------------------------------------------------------------
/** Loads a single shader file, and add it to the loaded (cached) list
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
GLuint ShaderFilesManager::addShaderFile(const std::string &file, unsigned type)
{
#ifdef DEBUG
// Make sure no duplicated shader is added somewhere else
std::unordered_map<std::string, GLuint>::const_iterator i =
m_shader_files_loaded.find(file);
assert(i == m_shader_files_loaded.end());
#endif
const GLuint id = loadShader(file, type);
m_shader_files_loaded[file] = id;
return id;
} // addShaderFile
// ----------------------------------------------------------------------------
/** Get a shader file. If the shader is not already in the cache it will be loaded and cached.
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
GLuint ShaderFilesManager::getShaderFile(const std::string &file, unsigned type)
{
// found in cache
auto it = m_shader_files_loaded.find(file);
if (it != m_shader_files_loaded.end())
return it->second;
// add to the cache now
return addShaderFile(file, type);
} // getShaderFile
#endif // !SERVER_ONLY

View File

@ -0,0 +1,60 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef SERVER_ONLY
#ifndef HEADER_SHADER_FILES_MANAGER_HPP
#define HEADER_SHADER_FILES_MANAGER_HPP
#include "graphics/gl_headers.hpp"
#include "utils/no_copy.hpp"
#include "utils/singleton.hpp"
#include <algorithm>
#include <string>
#include <unordered_map>
class ShaderFilesManager : public Singleton<ShaderFilesManager>, NoCopy
{
private:
/**
* Map from a filename to a shader indentifier. Used for caching shaders.
*/
std::unordered_map<std::string, GLuint> m_shader_files_loaded;
// ------------------------------------------------------------------------
const std::string& getHeader();
public:
// ------------------------------------------------------------------------
ShaderFilesManager() {}
// ------------------------------------------------------------------------
~ShaderFilesManager() { clean(); }
// ------------------------------------------------------------------------
void clean() { m_shader_files_loaded.clear(); }
// ------------------------------------------------------------------------
GLuint loadShader(const std::string &file, unsigned type);
// ------------------------------------------------------------------------
GLuint addShaderFile(const std::string &file, unsigned type);
// ------------------------------------------------------------------------
GLuint getShaderFile(const std::string &file, unsigned type);
}; // ShaderFilesManager
#endif
#endif // !SERVER_ONLY

View File

@ -174,69 +174,6 @@ static std::string loadHeader()
return result;
} // loadHeader
// ----------------------------------------------------------------------------
// Mostly from shader tutorial
GLuint loadShader(const char * file, unsigned type)
{
GLuint Id = glCreateShader(type);
char versionString[20];
#if !defined(USE_GLES2)
sprintf(versionString, "#version %d\n", CVS->getGLSLVersion());
#else
if (CVS->isGLSL())
sprintf(versionString, "#version 300 es\n");
#endif
std::string Code = versionString;
if (CVS->isAMDVertexShaderLayerUsable())
Code += "#extension GL_AMD_vertex_shader_layer : enable\n";
if (CVS->isAZDOEnabled())
{
Code += "#extension GL_ARB_bindless_texture : enable\n";
Code += "#define Use_Bindless_Texture\n";
}
std::ifstream Stream(file, std::ios::in);
Code += "//" + std::string(file) + "\n";
if (!CVS->isARBUniformBufferObjectUsable())
Code += "#define UBO_DISABLED\n";
if (CVS->isAMDVertexShaderLayerUsable())
Code += "#define VSLayer\n";
if (CVS->needsRGBBindlessWorkaround())
Code += "#define SRGBBindlessFix\n";
Code += loadHeader();
if (Stream.is_open())
{
std::string Line = "";
while (getline(Stream, Line))
Code += "\n" + Line;
Stream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
Log::info("GLWrap", "Compiling shader : %s", file);
char const * SourcePointer = Code.c_str();
int length = (int)strlen(SourcePointer);
glShaderSource(Id, 1, &SourcePointer, &length);
glCompileShader(Id);
glGetShaderiv(Id, GL_COMPILE_STATUS, &Result);
if (Result == GL_FALSE)
{
Log::error("GLWrap", "Error in shader %s", file);
glGetShaderiv(Id, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength<0)
InfoLogLength = 1024;
char *ErrorMessage = new char[InfoLogLength];
ErrorMessage[0] = 0;
glGetShaderInfoLog(Id, InfoLogLength, NULL, ErrorMessage);
Log::error("GLWrap", ErrorMessage);
delete[] ErrorMessage;
}
glGetError();
return Id;
} // loadShader
// ----------------------------------------------------------------------------
void Shaders::loadShaders()
{
@ -361,6 +298,16 @@ Shaders::ObjectPass2Shader::ObjectPass2Shader()
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // ObjectPass2Shader
// ============================================================================
Shaders::SkinnedTransparentShader::SkinnedTransparentShader()
{
if (!CVS->supportsHardwareSkinning()) return;
loadProgram(OBJECT, GL_VERTEX_SHADER, "skinning.vert",
GL_FRAGMENT_SHADER, "transparent.frag");
assignUniforms("ModelMatrix", "texture_trans", "skinning_offset", "custom_alpha");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SkinnedTransparentShader
// ============================================================================
Shaders::TransparentShader::TransparentShader()
{

View File

@ -155,6 +155,15 @@ public:
}; // ObjectPass2Shader
// ========================================================================
class SkinnedTransparentShader : public TextureShader<SkinnedTransparentShader, 1,
core::matrix4, core::vector2df,
int, float >
{
public:
SkinnedTransparentShader();
}; // SkinnedTransparentShader
// ========================================================================
}; // class Shaders

View File

@ -19,6 +19,10 @@
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/central_settings.hpp"
#include "utils/log.hpp"
#include "matrix4.h"
#include <algorithm>
GLuint SharedGPUObjects::m_billboard_vbo;
GLuint SharedGPUObjects::m_sky_tri_vbo;
@ -31,6 +35,8 @@ GLuint SharedGPUObjects::m_full_screen_quad_vao;
GLuint SharedGPUObjects::m_ui_vao;
GLuint SharedGPUObjects::m_quad_buffer;
GLuint SharedGPUObjects::m_quad_vbo;
GLuint SharedGPUObjects::m_skinning_ubo;
int SharedGPUObjects::m_max_mat4_size = 1024;
bool SharedGPUObjects::m_has_been_initialised = false;
/** Initialises m_full_screen_quad_vbo.
@ -168,6 +174,26 @@ void SharedGPUObjects::initLightingDataUBO()
glBindBuffer(GL_UNIFORM_BUFFER, 0);
} // initLightingDataUBO
// ----------------------------------------------------------------------------
void SharedGPUObjects::initSkinningUBO()
{
assert(CVS->isARBUniformBufferObjectUsable());
irr::core::matrix4 m;
glGenBuffers(1, &m_skinning_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, m_skinning_ubo);
int max_size = 0;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_size);
max_size = std::min(max_size, 65536);
m_max_mat4_size = max_size / 16 / sizeof(float);
Log::info("SharedGPUObjects", "Hardware skinning supported, max joints"
" support: %d", m_max_mat4_size);
glBufferData(GL_UNIFORM_BUFFER, max_size, 0, GL_STREAM_DRAW);
// Reserve a identity matrix for non moving mesh in animated model used by
// vertex shader calculation
glBufferSubData(GL_UNIFORM_BUFFER, 0, 16 * sizeof(float), m.pointer());
glBindBuffer(GL_UNIFORM_BUFFER, 0);
} // initSkinningUBO
// ----------------------------------------------------------------------------
void SharedGPUObjects::initParticleQuadVBO()
{
@ -197,10 +223,12 @@ void SharedGPUObjects::init()
initFrustrumVBO();
initParticleQuadVBO();
if(CVS->isARBUniformBufferObjectUsable())
if (CVS->isARBUniformBufferObjectUsable())
{
initShadowVPMUBO();
initLightingDataUBO();
initLightingDataUBO();
if (CVS->supportsHardwareSkinning())
initSkinningUBO();
}
m_has_been_initialised = true;

View File

@ -37,6 +37,8 @@ private:
static GLuint m_ui_vao;
static GLuint m_quad_buffer;
static GLuint m_quad_vbo;
static GLuint m_skinning_ubo;
static int m_max_mat4_size;
static void initQuadVBO();
static void initQuadBuffer();
@ -46,6 +48,7 @@ private:
static void initShadowVPMUBO();
static void initLightingDataUBO();
static void initParticleQuadVBO();
static void initSkinningUBO();
public:
static void init();
@ -116,7 +119,18 @@ public:
assert(m_has_been_initialised);
return m_quad_vbo;
} // getQuadVBO
}; // class SharedGPUObjecctS
// ------------------------------------------------------------------------
static GLuint getSkinningUBO()
{
assert(m_has_been_initialised);
return m_skinning_ubo;
} // getSkinningUBO
// ------------------------------------------------------------------------
static int getMaxMat4Size()
{
return m_max_mat4_size;
} // getMaxMat4Size
}; // class SharedGPUObjects
#endif

View File

@ -22,12 +22,13 @@
#include "graphics/central_settings.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/render_info.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/vao_manager.hpp"
#include <IMaterialRenderer.h>
#include <ISceneManager.h>
#include <ISkinnedMesh.h>
#include "../../lib/irrlicht/source/Irrlicht/CSkinnedMesh.h"
using namespace irr;
@ -36,7 +37,8 @@ irr::scene::ISceneManager* mgr, s32 id, const std::string& debug_name,
const core::vector3df& position,
const core::vector3df& rotation,
const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized) :
CAnimatedMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale)
CAnimatedMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale),
m_skinned_mesh(NULL), m_skinning_offset(-1)
{
isGLInitialized = false;
isMaterialInitialized = false;
@ -46,6 +48,7 @@ const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized)
#ifdef DEBUG
m_debug_name = debug_name;
#endif
resetSkinningState(mesh);
}
STKAnimatedMesh::~STKAnimatedMesh()
@ -80,6 +83,7 @@ void STKAnimatedMesh::setMesh(scene::IAnimatedMesh* mesh)
isMaterialInitialized = false;
cleanGLMeshes();
CAnimatedMeshSceneNode::setMesh(mesh);
resetSkinningState(mesh);
}
void STKAnimatedMesh::updateNoGL()
@ -96,21 +100,22 @@ void STKAnimatedMesh::updateNoGL()
if (!isMaterialInitialized)
{
// Use a default render info to distinguish same mesh buffer created by
// different animated mesh node in vao manager when using instanced
// rendering
RenderInfo* default_ri = NULL;
if (CVS->isARBBaseInstanceUsable())
{
default_ri = new RenderInfo();
m_static_render_info.push_back(default_ri);
}
video::IVideoDriver* driver = SceneManager->getVideoDriver();
const u32 mb_count = m->getMeshBufferCount();
for (u32 i = 0; i < mb_count; ++i)
{
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
if (!mb)
continue;
scene::SSkinMeshBuffer* ssmb = NULL;
video::E_VERTEX_TYPE prev_type = mb->getVertexType();
if (m_skinned_mesh)
{
ssmb = dynamic_cast<scene::SSkinMeshBuffer*>(mb);
ssmb->VertexType = video::EVT_SKINNED_MESH;
}
bool affected = false;
RenderInfo* cur_ri = m_mesh_render_info;
if (!m_all_parts_colorized && mb && cur_ri)
@ -128,7 +133,7 @@ void STKAnimatedMesh::updateNoGL()
}
else
{
cur_ri = default_ri;
cur_ri = NULL;
}
}
else
@ -144,7 +149,9 @@ void STKAnimatedMesh::updateNoGL()
assert(cur_ri ? cur_ri->isStatic() : true);
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name,
affected || m_all_parts_colorized || (cur_ri
&& cur_ri->isTransparent()) ? cur_ri : default_ri));
&& cur_ri->isTransparent()) ? cur_ri : NULL));
if (m_skinned_mesh) ssmb->VertexType = prev_type;
}
for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
@ -152,6 +159,15 @@ void STKAnimatedMesh::updateNoGL()
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
if (!mb)
continue;
scene::SSkinMeshBuffer* ssmb = NULL;
video::E_VERTEX_TYPE prev_type = mb->getVertexType();
if (m_skinned_mesh)
{
ssmb = dynamic_cast<scene::SSkinMeshBuffer*>(mb);
ssmb->VertexType = video::EVT_SKINNED_MESH;
}
video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType;
f32 MaterialTypeParam = mb->getMaterial().MaterialTypeParam;
video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type);
@ -163,25 +179,29 @@ void STKAnimatedMesh::updateNoGL()
continue;
}
GLMesh &mesh = GLmeshes[i];
video::E_VERTEX_TYPE vt = mb->getVertexType();
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
if (rnd->isTransparent())
{
TransparentMaterial TranspMat = getTransparentMaterialFromType(type, MaterialTypeParam, material);
TransparentMaterial TranspMat = getTransparentMaterialFromType(type, vt, MaterialTypeParam, material);
TransparentMesh[TranspMat].push_back(&mesh);
}
else if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent())
{
if (mesh.VAOType == video::EVT_TANGENTS)
if (mesh.VAOType == video::EVT_SKINNED_MESH)
TransparentMesh[TM_TRANSLUCENT_SKN].push_back(&mesh);
else if (mesh.VAOType == video::EVT_TANGENTS)
TransparentMesh[TM_TRANSLUCENT_TAN].push_back(&mesh);
else
TransparentMesh[TM_TRANSLUCENT_STD].push_back(&mesh);
}
else
{
Material::ShaderType MatType = getMeshMaterialFromType(type, mb->getVertexType(), material, NULL);
Material::ShaderType MatType = getMeshMaterialFromType(type, vt, material, NULL);
MeshSolidMaterial[MatType].push_back(&mesh);
}
if (m_skinned_mesh) ssmb->VertexType = prev_type;
}
isMaterialInitialized = true;
}
@ -207,16 +227,21 @@ void STKAnimatedMesh::updateNoGL()
void STKAnimatedMesh::updateGL()
{
scene::IMesh* m = getMeshForCurrentFrame();
if (!isGLInitialized)
{
for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
if (!mb)
continue;
scene::SSkinMeshBuffer* ssmb = NULL;
video::E_VERTEX_TYPE prev_type = mb->getVertexType();
if (m_skinned_mesh)
{
ssmb = dynamic_cast<scene::SSkinMeshBuffer*>(mb);
ssmb->VertexType = video::EVT_SKINNED_MESH;
}
video::IVideoDriver* driver = SceneManager->getVideoDriver();
video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType;
video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type);
@ -237,7 +262,7 @@ void STKAnimatedMesh::updateGL()
if (CVS->isARBBaseInstanceUsable())
{
std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb, GLmeshes[i].m_render_info);
std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb);
mesh.vaoBaseVertex = p.first;
mesh.vaoOffset = p.second;
}
@ -247,10 +272,20 @@ void STKAnimatedMesh::updateGL()
mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType());
glBindVertexArray(0);
}
if (m_skinned_mesh) ssmb->VertexType = prev_type;
}
isGLInitialized = true;
}
if (useHardwareSkinning() && m_skinned_mesh->getTotalJoints() == 0) return;
scene::IMesh* m = getMeshForCurrentFrame();
if (useHardwareSkinning())
{
m_skinning_offset = -1;
return;
}
for (u32 i = 0; i<m->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* mb = m->getMeshBuffer(i);
@ -294,5 +329,48 @@ void STKAnimatedMesh::render()
updateGL();
}
#endif // !SERVER_ONLY
int STKAnimatedMesh::getTotalJoints() const
{
return m_skinned_mesh->getTotalJoints();
}
void STKAnimatedMesh::resetSkinningState(scene::IAnimatedMesh* mesh)
{
if (!CVS->supportsHardwareSkinning()) return;
m_skinning_offset = -1;
setHardwareSkinning(true);
if (m_skinned_mesh)
m_skinned_mesh->convertForSkinning();
}
scene::IMesh* STKAnimatedMesh::getMeshForCurrentFrame(SkinningCallback sc,
int offset)
{
if (!useHardwareSkinning())
return scene::CAnimatedMeshSceneNode::getMeshForCurrentFrame();
if (m_skinning_offset == -1)
return Mesh;
return scene::CAnimatedMeshSceneNode::getMeshForCurrentFrame
(uploadJoints, m_skinning_offset);
}
void STKAnimatedMesh::setHardwareSkinning(bool val)
{
if (!CVS->supportsHardwareSkinning()) return;
if (val)
m_skinned_mesh = dynamic_cast<scene::CSkinnedMesh*>(Mesh);
else
m_skinned_mesh = NULL;
}
void STKAnimatedMesh::uploadJoints(const irr::core::matrix4& m,
int joint, int offset)
{
assert(offset != -1);
glBindBuffer(GL_UNIFORM_BUFFER, SharedGPUObjects::getSkinningUBO());
glBufferSubData(GL_UNIFORM_BUFFER, offset + joint * 16 * sizeof(float),
16 * sizeof(float), m.pointer());
}
#endif // !SERVER_ONLY

View File

@ -26,6 +26,10 @@
#include <irrTypes.h>
class RenderInfo;
namespace irr
{
namespace scene { class CSkinnedMesh; }
}
class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode, public STKMeshCommon
{
@ -50,10 +54,23 @@ public:
virtual void render();
virtual void setMesh(irr::scene::IAnimatedMesh* mesh);
virtual bool glow() const { return false; }
virtual irr::scene::IMesh* getMeshForCurrentFrame(SkinningCallback sc = NULL,
int offset = -1);
int getTotalJoints() const;
void setSkinningOffset(int offset) { m_skinning_offset = offset; }
bool useHardwareSkinning() const { return m_skinned_mesh != NULL; }
void setHardwareSkinning(bool val);
void resetSkinningState(scene::IAnimatedMesh*);
// Callback for skinning mesh
static void uploadJoints(const irr::core::matrix4& m,
int joint, int offset);
private:
RenderInfo* m_mesh_render_info;
bool m_all_parts_colorized;
bool m_got_animated_matrix;
irr::scene::CSkinnedMesh* m_skinned_mesh;
int m_skinning_offset;
};
#endif // STKANIMATEDMESH_HPP

View File

@ -40,6 +40,24 @@ Material::ShaderType getMeshMaterialFromType(video::E_MATERIAL_TYPE material_typ
layer2_material->getShaderType() == Material::SHADERTYPE_SPLATTING)
return Material::SHADERTYPE_SPLATTING;
if (tp == video::EVT_SKINNED_MESH)
{
switch (material->getShaderType())
{
case Material::SHADERTYPE_SOLID:
if (material_type == Shaders::getShader(ES_NORMAL_MAP))
return Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH;
else
return Material::SHADERTYPE_SOLID_SKINNED_MESH;
case Material::SHADERTYPE_ALPHA_TEST:
return Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH;
case Material::SHADERTYPE_SOLID_UNLIT:
return Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH;
default:
return Material::SHADERTYPE_SOLID_SKINNED_MESH;
}
}
switch (material->getShaderType())
{
default:
@ -55,9 +73,13 @@ Material::ShaderType getMeshMaterialFromType(video::E_MATERIAL_TYPE material_typ
// ----------------------------------------------------------------------------
TransparentMaterial getTransparentMaterialFromType(video::E_MATERIAL_TYPE type,
video::E_VERTEX_TYPE tp,
f32 MaterialTypeParam,
Material* material)
{
if (tp == video::EVT_SKINNED_MESH)
return TM_TRANSLUCENT_SKN;
if (type == Shaders::getShader(ES_DISPLACE))
{
if (CVS->isDefferedEnabled())
@ -157,6 +179,22 @@ GLuint createVAO(GLuint vbo, GLuint idx, video::E_VERTEX_TYPE type)
glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE,
getVertexPitchFromType(type), (GLvoid*)48);
break;
case video::EVT_SKINNED_MESH:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)12);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, getVertexPitchFromType(type), (GLvoid*)24);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)28);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)44);
glEnableVertexAttribArray(5);
glVertexAttribIPointer(5, 4, GL_INT, getVertexPitchFromType(type), (GLvoid*)60);
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)76);
break;
default:
assert(0 && "Wrong vertex type");
}
@ -205,8 +243,6 @@ GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb, const std::string& debug_name,
}
result.VAOType = mb->getVertexType();
result.Stride = getVertexPitchFromType(result.VAOType);
result.IndexCount = mb->getIndexCount();
switch (mb->getPrimitiveType())
{
@ -236,7 +272,7 @@ GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb, const std::string& debug_name,
for (unsigned i = 0; i < 8; i++)
result.textures[i] = mb->getMaterial().getTexture(i);
result.texture_trans = core::vector2df(0.0f, 0.0f);
result.VAOType = mb->getVertexType();
return result;
} // allocateMeshBuffer
@ -409,12 +445,16 @@ void initTextures(GLMesh &mesh, Material::ShaderType mat)
case Material::SHADERTYPE_SPHERE_MAP:
case Material::SHADERTYPE_SOLID_UNLIT:
case Material::SHADERTYPE_VEGETATION:
case Material::SHADERTYPE_SOLID_SKINNED_MESH:
case Material::SHADERTYPE_ALPHA_TEST_SKINNED_MESH:
case Material::SHADERTYPE_SOLID_UNLIT_SKINNED_MESH:
setTexture(mesh, 0, true, getShaderTypeName(mat));
setTexture(mesh, 1, false, getShaderTypeName(mat));
setTexture(mesh, 2, false, getShaderTypeName(mat));
break;
case Material::SHADERTYPE_DETAIL_MAP:
case Material::SHADERTYPE_NORMAL_MAP:
case Material::SHADERTYPE_NORMAL_MAP_SKINNED_MESH:
setTexture(mesh, 0, true, getShaderTypeName(mat));
setTexture(mesh, 1, false, getShaderTypeName(mat));
setTexture(mesh, 2, false, getShaderTypeName(mat));

View File

@ -37,6 +37,7 @@ enum TransparentMaterial
TM_DEFAULT,
TM_ADDITIVE,
TM_DISPLACEMENT,
TM_TRANSLUCENT_SKN,
TM_TRANSLUCENT_STD,
TM_TRANSLUCENT_TAN,
TM_TRANSLUCENT_2TC,
@ -91,6 +92,7 @@ public:
virtual void updateGL() = 0;
virtual bool glow() const = 0;
virtual bool isImmediateDraw() const { return false; }
const std::string& getMeshDebugName() const { return m_debug_name; }
}; // STKMeshCommon
@ -110,10 +112,34 @@ public:
}; // MeshList
// ----------------------------------------------------------------------------
class ListSkinnedSolid : public MeshList<ListSkinnedSolid, GLMesh *, core::matrix4,
core::matrix4, core::vector2df,
core::vector2df, int>
{};
// ----------------------------------------------------------------------------
class ListSkinnedAlphaRef : public MeshList<ListSkinnedAlphaRef, GLMesh *,
core::matrix4, core::matrix4,
core::vector2df, core::vector2df, int>
{};
// ----------------------------------------------------------------------------
class ListSkinnedNormalMap : public MeshList<ListSkinnedNormalMap, GLMesh *,
core::matrix4, core::matrix4,
core::vector2df, core::vector2df, int>
{};
// ----------------------------------------------------------------------------
class ListSkinnedUnlit : public MeshList<ListSkinnedUnlit, GLMesh *,
core::matrix4, core::matrix4,
core::vector2df, core::vector2df, int>
{};
// ----------------------------------------------------------------------------
class ListMatDefault : public MeshList<ListMatDefault, GLMesh *, core::matrix4,
core::matrix4, core::vector2df,
core::vector2df>
core::matrix4, core::vector2df,
core::vector2df>
{};
// ----------------------------------------------------------------------------
@ -172,6 +198,12 @@ class ListAdditiveTransparent : public MiscList<ListAdditiveTransparent,
core::vector2df, float>
{};
// ----------------------------------------------------------------------------
class ListTranslucentSkinned : public MiscList<ListTranslucentSkinned,
GLMesh *, core::matrix4,
core::vector2df, int, float>
{};
// ----------------------------------------------------------------------------
class ListTranslucentStandard : public MiscList<ListTranslucentStandard,
GLMesh *, core::matrix4,
@ -218,6 +250,7 @@ Material::ShaderType getMeshMaterialFromType(video::E_MATERIAL_TYPE MaterialType
Material* layer2Material);
// ----------------------------------------------------------------------------
TransparentMaterial getTransparentMaterialFromType(video::E_MATERIAL_TYPE,
video::E_VERTEX_TYPE tp,
f32 MaterialTypeParam,
Material* material);

View File

@ -207,6 +207,7 @@ void STKMeshSceneNode::updateNoGL()
}
GLMesh &mesh = GLmeshes[i];
video::E_VERTEX_TYPE vt = mb->getVertexType();
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent() && !rnd->isTransparent())
{
@ -218,7 +219,7 @@ void STKMeshSceneNode::updateNoGL()
}
else if (rnd->isTransparent())
{
TransparentMaterial TranspMat = getTransparentMaterialFromType(type, MaterialTypeParam, material);
TransparentMaterial TranspMat = getTransparentMaterialFromType(type, vt, MaterialTypeParam, material);
if (!immediate_draw)
TransparentMesh[TranspMat].push_back(&mesh);
else
@ -230,7 +231,7 @@ void STKMeshSceneNode::updateNoGL()
Material* material2 = NULL;
if (mb->getMaterial().getTexture(1) != NULL)
material2 = material_manager->getMaterialFor(mb->getMaterial().getTexture(1), mb);
Material::ShaderType MatType = getMeshMaterialFromType(type, mb->getVertexType(), material, material2);
Material::ShaderType MatType = getMeshMaterialFromType(type, vt, material, material2);
if (!immediate_draw)
MeshSolidMaterial[MatType].push_back(&mesh);
}

View File

@ -163,6 +163,9 @@ void VAOInstanceUtil<InstanceDataSingleTex>::SetVertexAttrib()
glEnableVertexAttribArray(11);
glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(9 * sizeof(float)));
glVertexAttribDivisorARB(11, 1);
glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 1, GL_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(11 * sizeof(float)));
glVertexAttribDivisorARB(15, 1);
}
template<>
@ -181,6 +184,9 @@ void VAOInstanceUtil<InstanceDataThreeTex>::SetVertexAttrib()
glEnableVertexAttribArray(13);
glVertexAttribIPointer(13, 2, GL_UNSIGNED_INT, sizeof(InstanceDataThreeTex), (GLvoid*)(13 * sizeof(float) + 4 * sizeof(unsigned)));
glVertexAttribDivisorARB(13, 1);
glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 1, GL_INT, sizeof(InstanceDataThreeTex), (GLvoid*)(13 * sizeof(float) + 6 * sizeof(unsigned)));;
glVertexAttribDivisorARB(15, 1);
}
template<>
@ -202,6 +208,9 @@ void VAOInstanceUtil<InstanceDataFourTex>::SetVertexAttrib()
glEnableVertexAttribArray(14);
glVertexAttribIPointer(14, 2, GL_UNSIGNED_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 6 * sizeof(unsigned)));
glVertexAttribDivisorARB(14, 1);
glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 1, GL_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 8 * sizeof(unsigned)));
glVertexAttribDivisorARB(15, 1);
}
template<>
@ -218,7 +227,7 @@ void VAOManager::regenerateInstancedVAO()
{
cleanInstanceVAOs();
enum video::E_VERTEX_TYPE IrrVT[] = { video::EVT_STANDARD, video::EVT_2TCOORDS, video::EVT_TANGENTS };
enum video::E_VERTEX_TYPE IrrVT[] = { video::EVT_STANDARD, video::EVT_2TCOORDS, video::EVT_TANGENTS, video::EVT_SKINNED_MESH };
for (unsigned i = 0; i < VTXTYPE_COUNT; i++)
{
video::E_VERTEX_TYPE tp = IrrVT[i];
@ -266,6 +275,8 @@ size_t VAOManager::getVertexPitch(enum VTXTYPE tp) const
return getVertexPitchFromType(video::EVT_2TCOORDS);
case VTXTYPE_TANGENT:
return getVertexPitchFromType(video::EVT_TANGENTS);
case VTXTYPE_SKINNED_MESH:
return getVertexPitchFromType(video::EVT_SKINNED_MESH);
default:
assert(0 && "Wrong vtxtype");
return -1;
@ -284,6 +295,8 @@ VAOManager::VTXTYPE VAOManager::getVTXTYPE(video::E_VERTEX_TYPE type)
return VTXTYPE_TCOORD;
case video::EVT_TANGENTS:
return VTXTYPE_TANGENT;
case video::EVT_SKINNED_MESH:
return VTXTYPE_SKINNED_MESH;
}
};
@ -298,10 +311,12 @@ irr::video::E_VERTEX_TYPE VAOManager::getVertexType(enum VTXTYPE tp)
return video::EVT_2TCOORDS;
case VTXTYPE_TANGENT:
return video::EVT_TANGENTS;
case VTXTYPE_SKINNED_MESH:
return video::EVT_SKINNED_MESH;
}
}
void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp, RenderInfo* ri)
void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp)
{
size_t old_vtx_cnt = last_vertex[tp];
size_t old_idx_cnt = last_index[tp];
@ -332,28 +347,26 @@ void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp, RenderInfo* ri)
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, old_idx_cnt * sizeof(u16), mb->getIndexCount() * sizeof(u16), mb->getIndices());
}
std::pair<scene::IMeshBuffer*, RenderInfo*> key(mb, ri);
mappedBaseVertex[tp][key] = old_vtx_cnt;
mappedBaseIndex[tp][key] = old_idx_cnt * sizeof(u16);
mappedBaseVertex[tp][mb] = old_vtx_cnt;
mappedBaseIndex[tp][mb] = old_idx_cnt * sizeof(u16);
}
std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb, RenderInfo* ri)
std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb)
{
VTXTYPE tp = getVTXTYPE(mb->getVertexType());
std::pair<scene::IMeshBuffer*, RenderInfo*> key(mb, ri);
if (mappedBaseVertex[tp].find(key) == mappedBaseVertex[tp].end())
if (mappedBaseVertex[tp].find(mb) == mappedBaseVertex[tp].end())
{
assert(mappedBaseIndex[tp].find(key) == mappedBaseIndex[tp].end());
append(mb, tp, ri);
assert(mappedBaseIndex[tp].find(mb) == mappedBaseIndex[tp].end());
append(mb, tp);
regenerateVAO(tp);
regenerateInstancedVAO();
}
std::unordered_map<std::pair<scene::IMeshBuffer*, RenderInfo*>, unsigned, MeshRenderInfoHash, MeshRenderInfoEquals>::iterator It;
It = mappedBaseVertex[tp].find(key);
std::unordered_map<scene::IMeshBuffer*, unsigned>::iterator It;
It = mappedBaseVertex[tp].find(mb);
assert(It != mappedBaseVertex[tp].end());
unsigned vtx = It->second;
It = mappedBaseIndex[tp].find(key);
It = mappedBaseIndex[tp].find(mb);
assert(It != mappedBaseIndex[tp].end());
return std::pair<unsigned, unsigned>(vtx, It->second);
}

View File

@ -26,8 +26,6 @@
#include <map>
#include <unordered_map>
class RenderInfo;
enum InstanceType
{
InstanceTypeThreeTex,
@ -62,6 +60,7 @@ struct InstanceDataSingleTex
float Z;
} Scale;
uint64_t Texture;
int32_t skinning_offset;
#ifdef WIN32
};
#else
@ -98,6 +97,7 @@ struct InstanceDataThreeTex
uint64_t Texture;
uint64_t SecondTexture;
uint64_t ThirdTexture;
int32_t skinning_offset;
#ifdef WIN32
};
#else
@ -135,6 +135,7 @@ struct InstanceDataFourTex
uint64_t SecondTexture;
uint64_t ThirdTexture;
uint64_t FourthTexture;
int32_t skinning_offset;
#ifdef WIN32
};
#else
@ -171,40 +172,16 @@ struct GlowInstanceData
#pragma pack(pop)
#endif
#include <functional>
class MeshRenderInfoHash
{
public:
size_t operator() (const std::pair<irr::scene::IMeshBuffer*, RenderInfo*> &p) const
{
return (std::hash<irr::scene::IMeshBuffer*>()(p.first) ^
(std::hash<RenderInfo*>()(p.second) << 1));
}
};
struct MeshRenderInfoEquals : std::binary_function
<const std::pair<irr::scene::IMeshBuffer*, RenderInfo*>&,
const std::pair<irr::scene::IMeshBuffer*, RenderInfo*>&, bool>
{
result_type operator() (first_argument_type lhs,
second_argument_type rhs) const
{
return (lhs.first == rhs.first) &&
(lhs.second == rhs.second);
}
};
class VAOManager : public Singleton<VAOManager>
{
enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_COUNT };
enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_SKINNED_MESH, VTXTYPE_COUNT };
GLuint vbo[VTXTYPE_COUNT], ibo[VTXTYPE_COUNT], vao[VTXTYPE_COUNT];
GLuint instance_vbo[InstanceTypeCount];
void *Ptr[InstanceTypeCount];
void *VBOPtr[VTXTYPE_COUNT], *IBOPtr[VTXTYPE_COUNT];
size_t RealVBOSize[VTXTYPE_COUNT], RealIBOSize[VTXTYPE_COUNT];
size_t last_vertex[VTXTYPE_COUNT], last_index[VTXTYPE_COUNT];
std::unordered_map <std::pair<irr::scene::IMeshBuffer*, RenderInfo*>, unsigned, MeshRenderInfoHash, MeshRenderInfoEquals> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT];
std::unordered_map<irr::scene::IMeshBuffer*, unsigned> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT];
std::map<std::pair<irr::video::E_VERTEX_TYPE, InstanceType>, GLuint> InstanceVAO;
void cleanInstanceVAOs();
@ -214,10 +191,10 @@ class VAOManager : public Singleton<VAOManager>
size_t getVertexPitch(enum VTXTYPE) const;
VTXTYPE getVTXTYPE(irr::video::E_VERTEX_TYPE type);
irr::video::E_VERTEX_TYPE getVertexType(enum VTXTYPE tp);
void append(irr::scene::IMeshBuffer *, VTXTYPE tp, RenderInfo* ri = NULL);
void append(irr::scene::IMeshBuffer *, VTXTYPE tp);
public:
VAOManager();
std::pair<unsigned, unsigned> getBase(irr::scene::IMeshBuffer *, RenderInfo* ri = NULL);
std::pair<unsigned, unsigned> getBase(irr::scene::IMeshBuffer *);
GLuint getInstanceBuffer(InstanceType it) { return instance_vbo[it]; }
void *getInstanceBufferPtr(InstanceType it) { return Ptr[it]; }
unsigned getVBO(irr::video::E_VERTEX_TYPE type) { return vbo[getVTXTYPE(type)]; }

View File

@ -31,6 +31,7 @@
#include "graphics/material_manager.hpp"
#include "graphics/mesh_tools.hpp"
#include "graphics/render_info.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "karts/abstract_kart.hpp"
@ -361,11 +362,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
node = irr_driver->addAnimatedMesh(m_mesh, "kartmesh",
NULL/*parent*/, getRenderInfo());
// as animated mesh are not cheap to render use frustum box culling
if (CVS->isGLSL())
node->setAutomaticCulling(scene::EAC_OFF);
else
node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX);
node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX);
#endif
if (always_animated)
{
@ -1031,7 +1028,17 @@ void KartModel::attachHat()
m_hat_node = irr_driver->addMesh(hat_mesh, "hat");
bone->addChild(m_hat_node);
m_animated_node->setCurrentFrame((float)m_animation_frame[AF_STRAIGHT]);
m_animated_node->OnAnimate(0);
#ifndef SERVER_ONLY
STKAnimatedMesh* am = dynamic_cast<STKAnimatedMesh*>(m_animated_node);
if (am)
{
am->setHardwareSkinning(false);
am->OnAnimate(0);
am->setHardwareSkinning(true);
}
else
#endif
m_animated_node->OnAnimate(0);
bone->updateAbsolutePosition();
// With the hat node attached to the head bone, we have to
// reverse the transformation of the bone, so that the hat

View File

@ -24,6 +24,7 @@
#include "utils/translation.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include <IGUIEnvironment.h>
@ -36,8 +37,12 @@ using namespace irr::gui;
// -----------------------------------------------------------------------------
CustomVideoSettingsDialog::CustomVideoSettingsDialog(const float w, const float h) :
ModalDialog(w, h)
ModalDialog(w, h), m_all_kart_animated(true)
{
#ifndef SERVER_ONLY
m_all_kart_animated = SharedGPUObjects::getMaxMat4Size() > 512 ||
!CVS->supportsHardwareSkinning();
#endif
loadFromFile("custom_video_settings.stkgui");
updateActivation();
}
@ -64,8 +69,11 @@ void CustomVideoSettingsDialog::beforeAddingWidgets()
//I18N: animations setting (only karts with human players are animated)
kart_anim->addLabel(_("Human players only")); // 1
//I18N: animations setting (all karts are animated)
kart_anim->addLabel(_("Enabled for all")); // 2
kart_anim->setValue(UserConfigParams::m_show_steering_animations);
if (m_all_kart_animated)
kart_anim->addLabel(_("Enabled for all")); // 2
kart_anim->setValue(!m_all_kart_animated &&
UserConfigParams::m_show_steering_animations == 2 ?
1 : UserConfigParams::m_show_steering_animations);
SpinnerWidget* filtering = getWidget<SpinnerWidget>("filtering");
int value = 0;
@ -242,6 +250,8 @@ void CustomVideoSettingsDialog::updateActivation()
getWidget<CheckBoxWidget>("global_illumination")->setActive(light);
getWidget<CheckBoxWidget>("glow")->setActive(light);
getWidget<CheckBoxWidget>("bloom")->setActive(light);
getWidget<SpinnerWidget>("steering_animations")
->setMax(m_all_kart_animated ? 2 : 1);
if (!CVS->supportsShadows() && !CVS->supportsGlobalIllumination())
{

View File

@ -27,7 +27,8 @@
*/
class CustomVideoSettingsDialog : public GUIEngine::ModalDialog
{
private:
bool m_all_kart_animated;
public:
/**
* Creates a modal dialog with given percentage of screen width and height

View File

@ -20,7 +20,9 @@
#include "audio/sfx_manager.hpp"
#include "audio/sfx_base.hpp"
#include "config/user_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "guiengine/screen.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/check_box_widget.hpp"
@ -44,73 +46,71 @@ using namespace GUIEngine;
DEFINE_SCREEN_SINGLETON( OptionsScreenVideo );
struct GFXPreset
// ----------------------------------------------------------------------------
void OptionsScreenVideo::initPresets()
{
bool lights;
int shadows;
bool bloom;
bool motionblur;
bool lightshaft;
bool glow;
bool mlaa;
bool ssao;
bool weather;
bool animatedScenery;
int animatedCharacters;
int anisotropy;
/** Depth of field */
bool dof;
bool global_illumination;
bool degraded_ibl;
int hd_textures;
};
static GFXPreset GFX_PRESETS[] =
{
{
m_presets.push_back
({
false /* light */, 0 /* shadow */, false /* bloom */, false /* motionblur */,
false /* lightshaft */, false /* glow */, false /* mlaa */, false /* ssao */, false /* weather */,
false /* animatedScenery */, 0 /* animatedCharacters */, 0 /* anisotropy */,
false /* depth of field */, false /* global illumination */, true /* degraded IBL */, 0 /* hd_textures */
},
});
{
m_presets.push_back
({
false /* light */, 0 /* shadow */, false /* bloom */, false /* motionblur */,
false /* lightshaft */, false /* glow */, false /* mlaa */, false /* ssao */, false /* weather */,
true /* animatedScenery */, 1 /* animatedCharacters */, 4 /* anisotropy */,
false /* depth of field */, false /* global illumination */, true /* degraded IBL */, 0 /* hd_textures */
},
});
{
m_presets.push_back
({
true /* light */, 0 /* shadow */, false /* bloom */, false /* motionblur */,
false /* lightshaft */, false /* glow */, false /* mlaa */, false /* ssao */, true /* weather */,
true /* animatedScenery */, 1 /* animatedCharacters */, 4 /* anisotropy */,
false /* depth of field */, false /* global illumination */, true /* degraded IBL */, 1 /* hd_textures */
},
});
{
m_presets.push_back
({
true /* light */, 0 /* shadow */, false /* bloom */, true /* motionblur */,
true /* lightshaft */, true /* glow */, true /* mlaa */, false /* ssao */, true /* weather */,
true /* animatedScenery */, 1 /* animatedCharacters */, 8 /* anisotropy */,
false /* depth of field */, false /* global illumination */, false /* degraded IBL */, 1 /* hd_textures */
},
});
{
m_presets.push_back
({
true /* light */, 512 /* shadow */, true /* bloom */, true /* motionblur */,
true /* lightshaft */, true /* glow */, true /* mlaa */, true /* ssao */, true /* weather */,
true /* animatedScenery */, 2 /* animatedCharacters */, 16 /* anisotropy */,
true /* animatedScenery */,
#ifndef SERVER_ONLY
(SharedGPUObjects::getMaxMat4Size() > 512 || !CVS->supportsHardwareSkinning() ? 2 : 1),
#else
2 /* animatedCharacters */,
#endif
16 /* anisotropy */,
true /* depth of field */, false /* global illumination */, false /* degraded IBL */, 1 /* hd_textures */
},
});
{
m_presets.push_back
({
true /* light */, 1024 /* shadow */, true /* bloom */, true /* motionblur */,
true /* lightshaft */, true /* glow */, true /* mlaa */, true /* ssao */, true /* weather */,
true /* animatedScenery */, 2 /* animatedCharacters */, 16 /* anisotropy */,
true /* animatedScenery */,
#ifndef SERVER_ONLY
(SharedGPUObjects::getMaxMat4Size() > 512 || !CVS->supportsHardwareSkinning() ? 2 : 1),
#else
2 /* animatedCharacters */,
#endif
16 /* anisotropy */,
true /* depth of field */, true /* global illumination */, false /* degraded IBL */, 1 /* hd_textures */
}
};
});
static const int GFX_LEVEL_AMOUNT = 6;
} // initPresets
// ----------------------------------------------------------------------------
struct Resolution
{
@ -144,6 +144,7 @@ struct Resolution
OptionsScreenVideo::OptionsScreenVideo() : Screen("options_video.stkgui")
{
m_inited = false;
initPresets();
} // OptionsScreenVideo
// ----------------------------------------------------------------------------
@ -151,12 +152,12 @@ OptionsScreenVideo::OptionsScreenVideo() : Screen("options_video.stkgui")
void OptionsScreenVideo::loadedFromFile()
{
m_inited = false;
assert(m_presets.size() == 6);
GUIEngine::SpinnerWidget* gfx =
getWidget<GUIEngine::SpinnerWidget>("gfx_level");
gfx->m_properties[GUIEngine::PROP_MAX_VALUE] =
StringUtils::toString(GFX_LEVEL_AMOUNT);
StringUtils::toString(m_presets.size());
} // loadedFromFile
@ -334,25 +335,25 @@ void OptionsScreenVideo::updateGfxSlider()
assert( gfx != NULL );
bool found = false;
for (int l=0; l<GFX_LEVEL_AMOUNT; l++)
for (unsigned int l = 0; l < m_presets.size(); l++)
{
if (GFX_PRESETS[l].animatedCharacters == UserConfigParams::m_show_steering_animations &&
GFX_PRESETS[l].animatedScenery == UserConfigParams::m_graphical_effects &&
GFX_PRESETS[l].anisotropy == UserConfigParams::m_anisotropic &&
GFX_PRESETS[l].bloom == UserConfigParams::m_bloom &&
GFX_PRESETS[l].glow == UserConfigParams::m_glow &&
GFX_PRESETS[l].lights == UserConfigParams::m_dynamic_lights &&
GFX_PRESETS[l].lightshaft == UserConfigParams::m_light_shaft &&
GFX_PRESETS[l].mlaa == UserConfigParams::m_mlaa &&
GFX_PRESETS[l].motionblur == UserConfigParams::m_motionblur &&
//GFX_PRESETS[l].shaders == UserConfigParams::m_pixel_shaders
GFX_PRESETS[l].shadows == UserConfigParams::m_shadows_resolution &&
GFX_PRESETS[l].ssao == UserConfigParams::m_ssao &&
GFX_PRESETS[l].weather == UserConfigParams::m_weather_effects &&
GFX_PRESETS[l].dof == UserConfigParams::m_dof &&
GFX_PRESETS[l].global_illumination == UserConfigParams::m_gi &&
GFX_PRESETS[l].degraded_ibl == UserConfigParams::m_degraded_IBL &&
GFX_PRESETS[l].hd_textures == (UserConfigParams::m_high_definition_textures & 0x01))
if (m_presets[l].animatedCharacters == UserConfigParams::m_show_steering_animations &&
m_presets[l].animatedScenery == UserConfigParams::m_graphical_effects &&
m_presets[l].anisotropy == UserConfigParams::m_anisotropic &&
m_presets[l].bloom == UserConfigParams::m_bloom &&
m_presets[l].glow == UserConfigParams::m_glow &&
m_presets[l].lights == UserConfigParams::m_dynamic_lights &&
m_presets[l].lightshaft == UserConfigParams::m_light_shaft &&
m_presets[l].mlaa == UserConfigParams::m_mlaa &&
m_presets[l].motionblur == UserConfigParams::m_motionblur &&
//m_presets[l].shaders == UserConfigParams::m_pixel_shaders
m_presets[l].shadows == UserConfigParams::m_shadows_resolution &&
m_presets[l].ssao == UserConfigParams::m_ssao &&
m_presets[l].weather == UserConfigParams::m_weather_effects &&
m_presets[l].dof == UserConfigParams::m_dof &&
m_presets[l].global_illumination == UserConfigParams::m_gi &&
m_presets[l].degraded_ibl == UserConfigParams::m_degraded_IBL &&
m_presets[l].hd_textures == (UserConfigParams::m_high_definition_textures & 0x01))
{
gfx->setValue(l + 1);
found = true;
@ -513,23 +514,23 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name,
const int level = gfx_level->getValue() - 1;
UserConfigParams::m_show_steering_animations = GFX_PRESETS[level].animatedCharacters;
UserConfigParams::m_graphical_effects = GFX_PRESETS[level].animatedScenery;
UserConfigParams::m_anisotropic = GFX_PRESETS[level].anisotropy;
UserConfigParams::m_bloom = GFX_PRESETS[level].bloom;
UserConfigParams::m_glow = GFX_PRESETS[level].glow;
UserConfigParams::m_dynamic_lights = GFX_PRESETS[level].lights;
UserConfigParams::m_light_shaft = GFX_PRESETS[level].lightshaft;
UserConfigParams::m_mlaa = GFX_PRESETS[level].mlaa;
UserConfigParams::m_motionblur = GFX_PRESETS[level].motionblur;
//UserConfigParams::m_pixel_shaders = GFX_PRESETS[level].shaders;
UserConfigParams::m_shadows_resolution = GFX_PRESETS[level].shadows;
UserConfigParams::m_ssao = GFX_PRESETS[level].ssao;
UserConfigParams::m_weather_effects = GFX_PRESETS[level].weather;
UserConfigParams::m_dof = GFX_PRESETS[level].dof;
UserConfigParams::m_gi = GFX_PRESETS[level].global_illumination;
UserConfigParams::m_degraded_IBL = GFX_PRESETS[level].degraded_ibl;
UserConfigParams::m_high_definition_textures = 0x02 | GFX_PRESETS[level].hd_textures;
UserConfigParams::m_show_steering_animations = m_presets[level].animatedCharacters;
UserConfigParams::m_graphical_effects = m_presets[level].animatedScenery;
UserConfigParams::m_anisotropic = m_presets[level].anisotropy;
UserConfigParams::m_bloom = m_presets[level].bloom;
UserConfigParams::m_glow = m_presets[level].glow;
UserConfigParams::m_dynamic_lights = m_presets[level].lights;
UserConfigParams::m_light_shaft = m_presets[level].lightshaft;
UserConfigParams::m_mlaa = m_presets[level].mlaa;
UserConfigParams::m_motionblur = m_presets[level].motionblur;
//UserConfigParams::m_pixel_shaders = m_presets[level].shaders;
UserConfigParams::m_shadows_resolution = m_presets[level].shadows;
UserConfigParams::m_ssao = m_presets[level].ssao;
UserConfigParams::m_weather_effects = m_presets[level].weather;
UserConfigParams::m_dof = m_presets[level].dof;
UserConfigParams::m_gi = m_presets[level].global_illumination;
UserConfigParams::m_degraded_IBL = m_presets[level].degraded_ibl;
UserConfigParams::m_high_definition_textures = 0x02 | m_presets[level].hd_textures;
updateGfxSlider();
}

View File

@ -25,7 +25,26 @@
namespace GUIEngine { class Widget; }
struct Input;
struct GFXPreset
{
bool lights;
int shadows;
bool bloom;
bool motionblur;
bool lightshaft;
bool glow;
bool mlaa;
bool ssao;
bool weather;
bool animatedScenery;
int animatedCharacters;
int anisotropy;
/** Depth of field */
bool dof;
bool global_illumination;
bool degraded_ibl;
int hd_textures;
};
/**
* \brief Graphics options screen
@ -33,11 +52,14 @@ struct Input;
*/
class OptionsScreenVideo : public GUIEngine::Screen, public GUIEngine::ScreenSingleton<OptionsScreenVideo>
{
private:
OptionsScreenVideo();
bool m_inited;
std::vector<GFXPreset> m_presets;
void updateTooltip();
void initPresets();
public:
friend class GUIEngine::ScreenSingleton<OptionsScreenVideo>;

View File

@ -203,7 +203,6 @@ TrackObjectPresentationLibraryNode::TrackObjectPresentationLibraryNode(
}
std::string lib_node_path = lib_path + "node.xml";
std::string lib_script_file_path = lib_path + "scripting.as";
World* world = World::getWorld();
if (local_lib_node_path.size() > 0 && file_manager->fileExists(local_lib_node_path))
{

View File

@ -236,9 +236,10 @@ bool handleContextMenuAction(s32 cmd_id)
case DEBUG_GRAPHICS_RELOAD_SHADERS:
#ifndef SERVER_ONLY
Log::info("Debug", "Reloading shaders...");
ShaderBase::updateShaders();
ShaderFilesManager::getInstance()->clean();
ShaderBase::updateShaders();
#endif
break;
break;
case DEBUG_GRAPHICS_RESET:
if (physics)
physics->setDebugMode(IrrDebugDrawer::DM_NONE);

View File

@ -434,9 +434,7 @@ void Profiler::draw()
s32 y_up_sync = (s32)(MARGIN_Y*screen_size.Height);
s32 y_down_sync = (s32)( (MARGIN_Y + (2+nb_thread_infos)*LINE_HEIGHT)*screen_size.Height );
driver->draw2DLine(core::vector2di(x_sync, y_up_sync),
core::vector2di(x_sync, y_down_sync),
video::SColor(0xFF, 0x00, 0x00, 0x00));
GL32_draw2DRectangle(video::SColor(0xFF, 0x00, 0x00, 0x00), core::rect<s32>(x_sync, y_up_sync, x_sync + 1, y_down_sync));
}
// Draw the hovered markers' names