1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-01 17:38:41 +00:00

Fixes and proper tangent space

This commit is contained in:
Gefüllte Taubenbrust 2024-11-11 17:07:52 +01:00
parent 6ad43575ff
commit 2fd22c1850
12 changed files with 417 additions and 70 deletions

View file

@ -44,6 +44,8 @@ uniform vec2 windowSize;
uniform float fov; uniform float fov;
varying vec3 vNormal; varying vec3 vNormal;
varying vec3 vTangent;
varying vec3 vBinormal;
varying vec3 vPosition; varying vec3 vPosition;
// World position in the visible world (i.e. relative to the cameraOffset.) // World position in the visible world (i.e. relative to the cameraOffset.)
// This can be used for many shader effects without loss of precision. // This can be used for many shader effects without loss of precision.
@ -100,36 +102,6 @@ vec3 gnoise(vec3 p){
); );
} }
float snoise(vec3 p)
{
vec3 a = floor(p);
vec3 d = p - a;
d = d * d * (3.0 - 2.0 * d);
vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
vec4 k1 = perm(b.xyxy);
vec4 k2 = perm(k1.xyxy + b.zzww);
vec4 c = k2 + a.zzzz;
vec4 k3 = perm(c);
vec4 k4 = perm(c + 1.0);
vec4 o1 = fract(k3 * (1.0 / 41.0));
vec4 o2 = fract(k4 * (1.0 / 41.0));
vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);
vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);
return o4.y * d.y + o4.x * (1.0 - d.y);
}
vec3 hnoise(vec3 p) {
vec3 g = gnoise(p);
float s = snoise(p);
g *= 3.0 / (1.0 + exp(-16.0 * (s - 0.5))) - 1.5;
return g;
}
vec2 wave_noise(vec3 p, float off) { vec2 wave_noise(vec3 p, float off) {
return (gnoise(p + vec3(0.0, 0.0, off)) * 0.4 + gnoise(2.0 * p + vec3(0.0, off, off)) * 0.2 + gnoise(3.0 * p + vec3(0.0, off, off)) * 0.225 + gnoise(4.0 * p + vec3(-off, off, 0.0)) * 0.2).xz; return (gnoise(p + vec3(0.0, 0.0, off)) * 0.4 + gnoise(2.0 * p + vec3(0.0, off, off)) * 0.2 + gnoise(3.0 * p + vec3(0.0, off, off)) * 0.225 + gnoise(4.0 * p + vec3(-off, off, 0.0)) * 0.2).xz;
} }
@ -457,13 +429,11 @@ vec3 getBumpMap(vec2 uv) {
float fx0y0 = texture2D(baseTexture, uv).r; float fx0y0 = texture2D(baseTexture, uv).r;
float fx1y0 = texture2D(baseTexture, uv + vec2(dr.x, 0.0)).r; float fx1y0 = texture2D(baseTexture, uv + vec2(dr.x, 0.0)).r;
float fx0y1 = texture2D(baseTexture, uv + vec2(0.0, dr.y)).r; float fx0y1 = texture2D(baseTexture, uv + vec2(0.0, dr.y)).r;
// We get the gradient using partial derivatives
vec2 gradient = 0.1 * vec2((fx1y0 - fx0y0) / dr.x, (fx0y1 - fx0y0) / dr.y) + 0.05 * gnoise(vec3(2.0 * uv / texelSize0, 0.0)).xy; vec2 gradient = 0.1 * vec2((fx1y0 - fx0y0) / dr.x, (fx0y1 - fx0y0) / dr.y) + 0.05 * gnoise(vec3(2.0 * uv / texelSize0, 0.0)).xy;
// Compute a set of orthonormal basis vectors representing the node's surface plane. vec3 tangent_space = normalize(vec3(gradient, 1.0));
vec3 orth1 = normalize(cross(vNormal, mix(vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, -1.0), step(0.9, abs(vNormal.y))))); // Convert tangent space information to real space
vec3 orth2 = normalize(cross(vNormal, orth1)); return -vTangent * tangent_space.x + vBinormal * tangent_space.y + vNormal * tangent_space.z;
// The normal is computed using the partial derivatives along the texture space x and y axes.
// These axes in world space are assumed to be parallel to the basis vectors we defined before.
return orth1 * gradient.x + orth2 * gradient.y;
} }
#endif #endif
@ -501,8 +471,8 @@ void main(void)
// When applied to all blocks, these bump maps produce irritating Moiré effects. // When applied to all blocks, these bump maps produce irritating Moiré effects.
// So we hide the bump maps when close up. // So we hide the bump maps when close up.
float moire_factor = abs(dot(vNormal, viewVec)); float moire_factor = abs(dot(vNormal, viewVec));
bump_normal *= mtsmoothstep(0.4 * moire_factor, 0.2 * moire_factor, length(eyeVec) * fov / windowSize.x); moire_factor = mtsmoothstep(0.4 * moire_factor, 0.2 * moire_factor, length(eyeVec) * fov / windowSize.x);
fNormal = normalize(vNormal + bump_normal); fNormal = normalize(mix(fNormal, bump_normal, moire_factor));
float adj_cosLight = max(1e-5, dot(fNormal, -v_LightDirection)); float adj_cosLight = max(1e-5, dot(fNormal, -v_LightDirection));
#else #else
float adj_cosLight = cosLight; float adj_cosLight = cosLight;

View file

@ -7,6 +7,8 @@ uniform highp vec3 cameraOffset;
uniform float animationTimer; uniform float animationTimer;
varying vec3 vNormal; varying vec3 vNormal;
varying vec3 vTangent;
varying vec3 vBinormal;
varying vec3 vPosition; varying vec3 vPosition;
// World position in the visible world (i.e. relative to the cameraOffset.) // World position in the visible world (i.e. relative to the cameraOffset.)
// This can be used for many shader effects without loss of precision. // This can be used for many shader effects without loss of precision.
@ -209,6 +211,8 @@ void main(void)
normalPass = normalize((inVertexNormal+1)/2); normalPass = normalize((inVertexNormal+1)/2);
#endif #endif
vNormal = inVertexNormal; vNormal = inVertexNormal;
vTangent = inVertexTangent.xyz;
vBinormal = inVertexBinormal.xyz;
// Calculate color. // Calculate color.
vec4 color = inVertexColor; vec4 color = inVertexColor;

View file

@ -111,11 +111,6 @@ vec3 screen_space_dither(highp vec2 frag_coord) {
} }
#endif #endif
float sFunction(float x, float a) {
x = 2.0 * x - 1.0;
return 0.5 * sign(x) * pow(abs(x), a) + 0.5;
}
void main(void) void main(void)
{ {
vec2 uv = varTexCoord.st; vec2 uv = varTexCoord.st;

View file

@ -42,6 +42,26 @@ public:
virtual void recalculateNormals(IMeshBuffer *buffer, virtual void recalculateNormals(IMeshBuffer *buffer,
bool smooth = false, bool angleWeighted = false) const = 0; bool smooth = false, bool angleWeighted = false) const = 0;
//! Recalculates tangents, requires a tangent mesh
/** \param mesh Mesh on which the operation is performed.
\param recalculateNormals If the normals shall be recalculated, otherwise original normals of the mesh are used unchanged.
\param smooth If the normals shall be smoothed.
\param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision.
*/
virtual void recalculateTangents(IMesh* mesh,
bool recalculateNormals = false, bool smooth = false,
bool angleWeighted = false) const = 0;
//! Recalculates tangents, requires a tangent mesh buffer
/** \param buffer Meshbuffer on which the operation is performed.
\param recalculateNormals If the normals shall be recalculated, otherwise original normals of the buffer are used unchanged.
\param smooth If the normals shall be smoothed.
\param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision.
*/
virtual void recalculateTangents(IMeshBuffer* buffer,
bool recalculateNormals = false, bool smooth = false,
bool angleWeighted = false) const = 0;
//! Scales the actual mesh, not a scene node. //! Scales the actual mesh, not a scene node.
/** \param mesh Mesh on which the operation is performed. /** \param mesh Mesh on which the operation is performed.
\param factor Scale factor for each axis. */ \param factor Scale factor for each axis. */

View file

@ -80,6 +80,335 @@ void recalculateNormalsT(IMeshBuffer *buffer, bool smooth, bool angleWeighted)
} }
} }
namespace
{
void calculateTangents(
core::vector3df& normal,
core::vector3df& tangent,
core::vector3df& binormal,
const core::vector3df& vt1, const core::vector3df& vt2, const core::vector3df& vt3, // vertices
const core::vector2df& tc1, const core::vector2df& tc2, const core::vector2df& tc3) // texture coords
{
// choose one of them:
//#define USE_NVIDIA_GLH_VERSION // use version used by nvidia in glh headers
#define USE_IRR_VERSION
#ifdef USE_IRR_VERSION
core::vector3df v1 = vt1 - vt2;
core::vector3df v2 = vt3 - vt1;
normal = v2.crossProduct(v1);
normal.normalize();
// binormal
f32 deltaX1 = tc1.X - tc2.X;
f32 deltaX2 = tc3.X - tc1.X;
binormal = (v1 * deltaX2) - (v2 * deltaX1);
binormal.normalize();
// tangent
f32 deltaY1 = tc1.Y - tc2.Y;
f32 deltaY2 = tc3.Y - tc1.Y;
tangent = (v1 * deltaY2) - (v2 * deltaY1);
tangent.normalize();
// adjust
core::vector3df txb = tangent.crossProduct(binormal);
if (txb.dotProduct(normal) < 0.0f)
{
tangent *= -1.0f;
binormal *= -1.0f;
}
#endif // USE_IRR_VERSION
#ifdef USE_NVIDIA_GLH_VERSION
tangent.set(0, 0, 0);
binormal.set(0, 0, 0);
core::vector3df v1(vt2.X - vt1.X, tc2.X - tc1.X, tc2.Y - tc1.Y);
core::vector3df v2(vt3.X - vt1.X, tc3.X - tc1.X, tc3.Y - tc1.Y);
core::vector3df txb = v1.crossProduct(v2);
if (!core::iszero(txb.X))
{
tangent.X = -txb.Y / txb.X;
binormal.X = -txb.Z / txb.X;
}
v1.X = vt2.Y - vt1.Y;
v2.X = vt3.Y - vt1.Y;
txb = v1.crossProduct(v2);
if (!core::iszero(txb.X))
{
tangent.Y = -txb.Y / txb.X;
binormal.Y = -txb.Z / txb.X;
}
v1.X = vt2.Z - vt1.Z;
v2.X = vt3.Z - vt1.Z;
txb = v1.crossProduct(v2);
if (!core::iszero(txb.X))
{
tangent.Z = -txb.Y / txb.X;
binormal.Z = -txb.Z / txb.X;
}
tangent.normalize();
binormal.normalize();
normal = tangent.crossProduct(binormal);
normal.normalize();
binormal = tangent.crossProduct(normal);
binormal.normalize();
core::plane3d<f32> pl(vt1, vt2, vt3);
if (normal.dotProduct(pl.Normal) < 0.0f)
normal *= -1.0f;
#endif // USE_NVIDIA_GLH_VERSION
}
//! Recalculates tangents for a tangent mesh buffer
template <typename T>
void recalculateTangentsT(IMeshBuffer* buffer, bool recalculateNormals, bool smooth, bool angleWeighted)
{
if (!buffer || (buffer->getVertexType() != video::EVT_TANGENTS))
return;
const u32 vtxCnt = buffer->getVertexCount();
const u32 idxCnt = buffer->getIndexCount();
T* idx = reinterpret_cast<T*>(buffer->getIndices());
video::S3DVertexTangents* v =
(video::S3DVertexTangents*)buffer->getVertices();
if (smooth)
{
u32 i;
for (i = 0; i != vtxCnt; ++i)
{
if (recalculateNormals)
v[i].Normal.set(0.f, 0.f, 0.f);
v[i].Tangent.set(0.f, 0.f, 0.f);
v[i].Binormal.set(0.f, 0.f, 0.f);
}
//Each vertex gets the sum of the tangents and binormals from the faces around it
for (i = 0; i < idxCnt; i += 3)
{
// if this triangle is degenerate, skip it!
if (v[idx[i + 0]].Pos == v[idx[i + 1]].Pos ||
v[idx[i + 0]].Pos == v[idx[i + 2]].Pos ||
v[idx[i + 1]].Pos == v[idx[i + 2]].Pos
/*||
v[idx[i+0]].TCoords == v[idx[i+1]].TCoords ||
v[idx[i+0]].TCoords == v[idx[i+2]].TCoords ||
v[idx[i+1]].TCoords == v[idx[i+2]].TCoords */
)
continue;
//Angle-weighted normals look better, but are slightly more CPU intensive to calculate
core::vector3df weight(1.f, 1.f, 1.f);
if (angleWeighted)
weight = irr::scene::getAngleWeight(v[i + 0].Pos, v[i + 1].Pos, v[i + 2].Pos); // writing irr::scene:: necessary for borland
core::vector3df localNormal;
core::vector3df localTangent;
core::vector3df localBinormal;
calculateTangents(
localNormal,
localTangent,
localBinormal,
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);
if (recalculateNormals)
v[idx[i + 0]].Normal += localNormal * weight.X;
v[idx[i + 0]].Tangent += localTangent * weight.X;
v[idx[i + 0]].Binormal += localBinormal * weight.X;
calculateTangents(
localNormal,
localTangent,
localBinormal,
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);
if (recalculateNormals)
v[idx[i + 1]].Normal += localNormal * weight.Y;
v[idx[i + 1]].Tangent += localTangent * weight.Y;
v[idx[i + 1]].Binormal += localBinormal * weight.Y;
calculateTangents(
localNormal,
localTangent,
localBinormal,
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);
if (recalculateNormals)
v[idx[i + 2]].Normal += localNormal * weight.Z;
v[idx[i + 2]].Tangent += localTangent * weight.Z;
v[idx[i + 2]].Binormal += localBinormal * weight.Z;
}
// Normalize the tangents and binormals
if (recalculateNormals)
{
for (i = 0; i != vtxCnt; ++i)
v[i].Normal.normalize();
}
for (i = 0; i != vtxCnt; ++i)
{
v[i].Tangent.normalize();
v[i].Binormal.normalize();
}
}
else
{
core::vector3df localNormal;
for (u32 i = 0; i < idxCnt; i += 3)
{
calculateTangents(
localNormal,
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);
if (recalculateNormals)
v[idx[i + 0]].Normal = localNormal;
calculateTangents(
localNormal,
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);
if (recalculateNormals)
v[idx[i + 1]].Normal = localNormal;
calculateTangents(
localNormal,
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);
if (recalculateNormals)
v[idx[i + 2]].Normal = localNormal;
}
}
}
}
//! Recalculates tangents for a tangent mesh buffer
void CMeshManipulator::recalculateTangents(IMeshBuffer* buffer, bool recalculateNormals, bool smooth, bool angleWeighted) const
{
if (buffer && (buffer->getVertexType() == video::EVT_TANGENTS))
{
if (buffer->getIndexType() == video::EIT_16BIT)
recalculateTangentsT<u16>(buffer, recalculateNormals, smooth, angleWeighted);
else
recalculateTangentsT<u32>(buffer, recalculateNormals, smooth, angleWeighted);
}
}
//! Recalculates tangents for all tangent mesh buffers
void CMeshManipulator::recalculateTangents(IMesh* mesh, bool recalculateNormals, bool smooth, bool angleWeighted) const
{
if (!mesh)
return;
const u32 meshBufferCount = mesh->getMeshBufferCount();
for (u32 b = 0; b < meshBufferCount; ++b)
{
recalculateTangents(mesh->getMeshBuffer(b), recalculateNormals, smooth, angleWeighted);
}
}
namespace
{
//! Creates a planar texture mapping on the meshbuffer
template<typename T>
void makePlanarTextureMappingT(scene::IMeshBuffer* buffer, f32 resolution)
{
u32 idxcnt = buffer->getIndexCount();
T* idx = reinterpret_cast<T*>(buffer->getIndices());
for (u32 i = 0; i < idxcnt; i += 3)
{
core::plane3df p(buffer->getPosition(idx[i + 0]), buffer->getPosition(idx[i + 1]), buffer->getPosition(idx[i + 2]));
p.Normal.X = fabsf(p.Normal.X);
p.Normal.Y = fabsf(p.Normal.Y);
p.Normal.Z = fabsf(p.Normal.Z);
// calculate planar mapping worldspace coordinates
if (p.Normal.X > p.Normal.Y && p.Normal.X > p.Normal.Z)
{
for (u32 o = 0; o != 3; ++o)
{
buffer->getTCoords(idx[i + o]).X = buffer->getPosition(idx[i + o]).Y * resolution;
buffer->getTCoords(idx[i + o]).Y = buffer->getPosition(idx[i + o]).Z * resolution;
}
}
else
if (p.Normal.Y > p.Normal.X && p.Normal.Y > p.Normal.Z)
{
for (u32 o = 0; o != 3; ++o)
{
buffer->getTCoords(idx[i + o]).X = buffer->getPosition(idx[i + o]).X * resolution;
buffer->getTCoords(idx[i + o]).Y = buffer->getPosition(idx[i + o]).Z * resolution;
}
}
else
{
for (u32 o = 0; o != 3; ++o)
{
buffer->getTCoords(idx[i + o]).X = buffer->getPosition(idx[i + o]).X * resolution;
buffer->getTCoords(idx[i + o]).Y = buffer->getPosition(idx[i + o]).Y * resolution;
}
}
}
}
}
//! Recalculates all normals of the mesh buffer. //! Recalculates all normals of the mesh buffer.
/** \param buffer: Mesh buffer on which the operation is performed. */ /** \param buffer: Mesh buffer on which the operation is performed. */
void CMeshManipulator::recalculateNormals(IMeshBuffer *buffer, bool smooth, bool angleWeighted) const void CMeshManipulator::recalculateNormals(IMeshBuffer *buffer, bool smooth, bool angleWeighted) const

View file

@ -29,6 +29,12 @@ public:
\param smooth: Whether to use smoothed normals. */ \param smooth: Whether to use smoothed normals. */
void recalculateNormals(IMeshBuffer *buffer, bool smooth = false, bool angleWeighted = false) const override; void recalculateNormals(IMeshBuffer *buffer, bool smooth = false, bool angleWeighted = false) const override;
//! Recalculates tangents, requires a tangent mesh buffer
virtual void recalculateTangents(IMeshBuffer* buffer, bool recalculateNormals = false, bool smooth = false, bool angleWeighted = false) const _IRR_OVERRIDE_;
//! Recalculates tangents, requires a tangent mesh
virtual void recalculateTangents(IMesh* mesh, bool recalculateNormals = false, bool smooth = false, bool angleWeighted = false) const _IRR_OVERRIDE_;
//! Clones a static IMesh into a modifiable SMesh. //! Clones a static IMesh into a modifiable SMesh.
SMesh *createMeshCopy(scene::IMesh *mesh) const override; SMesh *createMeshCopy(scene::IMesh *mesh) const override;

View file

@ -40,10 +40,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
MeshMakeData MeshMakeData
*/ */
MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length, bool use_shaders): MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length, bool use_shaders, bool use_tangent_vertices):
side_length(side_length), side_length(side_length),
nodedef(ndef), nodedef(ndef),
m_use_shaders(use_shaders) m_use_shaders(use_shaders),
m_use_tangent_vertices(use_tangent_vertices)
{} {}
void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
@ -617,6 +618,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
for (auto &m : m_mesh) for (auto &m : m_mesh)
m = make_irr<scene::SMesh>(); m = make_irr<scene::SMesh>();
m_enable_shaders = data->m_use_shaders; m_enable_shaders = data->m_use_shaders;
m_use_tangent_vertices = data->m_use_tangent_vertices;
auto mesh_grid = client->getMeshGrid(); auto mesh_grid = client->getMeshGrid();
v3s16 bp = data->m_blockpos; v3s16 bp = data->m_blockpos;
@ -752,6 +754,22 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
p.layer.applyMaterialOptions(material); p.layer.applyMaterialOptions(material);
} }
if (m_use_tangent_vertices && !p.layer.isTransparent()) {
scene::SMeshBufferTangents* buf = new scene::SMeshBufferTangents();
buf->Material = material;
std::vector<video::S3DVertexTangents> vertices;
vertices.reserve(p.vertices.size());
for (video::S3DVertex &v : p.vertices)
vertices.push_back(video::S3DVertexTangents(v.Pos, v.Normal, v.Color, v.TCoords));
buf->append(&vertices[0], vertices.size(),
&p.indices[0], p.indices.size());
buf->recalculateBoundingBox();
scene::IMeshManipulator* meshmanip =
client->getSceneManager()->getMeshManipulator();
meshmanip->recalculateTangents(buf);
mesh->addMeshBuffer(buf);
buf->drop();
} else {
scene::SMeshBuffer *buf = new scene::SMeshBuffer(); scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Material = material; buf->Material = material;
if (p.layer.isTransparent()) { if (p.layer.isTransparent()) {
@ -774,6 +792,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
mesh->addMeshBuffer(buf); mesh->addMeshBuffer(buf);
buf->drop(); buf->drop();
} }
}
if (mesh) { if (mesh) {
// Use VBO for mesh (this just would set this for every buffer) // Use VBO for mesh (this just would set this for every buffer)

View file

@ -51,8 +51,9 @@ struct MeshMakeData
const NodeDefManager *nodedef; const NodeDefManager *nodedef;
bool m_use_shaders; bool m_use_shaders;
bool m_use_tangent_vertices;
MeshMakeData(const NodeDefManager *ndef, u16 side_length, bool use_shaders); MeshMakeData(const NodeDefManager *ndef, u16 side_length, bool use_shaders, bool use_tangent_vertices = false);
/* /*
Copy block data manually (to allow optimizations by the caller) Copy block data manually (to allow optimizations by the caller)
@ -251,6 +252,7 @@ private:
v3f m_bounding_sphere_center; v3f m_bounding_sphere_center;
bool m_enable_shaders; bool m_enable_shaders;
bool m_use_tangent_vertices;
// Must animate() be called before rendering? // Must animate() be called before rendering?
bool m_has_animation; bool m_has_animation;

View file

@ -55,6 +55,7 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
m_client(client) m_client(client)
{ {
m_cache_enable_shaders = g_settings->getBool("enable_shaders"); m_cache_enable_shaders = g_settings->getBool("enable_shaders");
m_cache_use_tangent_vertices = m_cache_enable_shaders && g_settings->getBool("enable_bumpmaps");
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting"); m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
} }
@ -192,7 +193,7 @@ void MeshUpdateQueue::done(v3s16 pos)
void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q) void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
{ {
auto mesh_grid = m_client->getMeshGrid(); auto mesh_grid = m_client->getMeshGrid();
MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size, m_cache_enable_shaders); MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size, m_cache_enable_shaders, m_cache_use_tangent_vertices);
q->data = data; q->data = data;
data->fillBlockDataBegin(q->p); data->fillBlockDataBegin(q->p);

View file

@ -86,6 +86,7 @@ private:
// TODO: Add callback to update these when g_settings changes // TODO: Add callback to update these when g_settings changes
bool m_cache_enable_shaders; bool m_cache_enable_shaders;
bool m_cache_use_tangent_vertices;
bool m_cache_smooth_lighting; bool m_cache_smooth_lighting;
void fillDataFromMapBlocks(QueuedMeshUpdate *q); void fillDataFromMapBlocks(QueuedMeshUpdate *q);