Add skid marks rendering for legacy video drivers

This commit is contained in:
Benau
2022-11-15 12:28:33 +08:00
parent 86391e8b8e
commit 0cd458cff4
3 changed files with 152 additions and 24 deletions

View File

@@ -21,6 +21,7 @@
#include "config/stk_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/sp/sp_dynamic_draw_call.hpp"
@@ -37,6 +38,10 @@
#ifndef SERVER_ONLY
#include <SMesh.h>
#include <SMeshBuffer.h>
#include <ge_render_info.hpp>
float SkidMarks::m_avoid_z_fighting = 0.005f;
const int SkidMarks::m_start_alpha = 200;
const int SkidMarks::m_start_grey = 32;
@@ -47,11 +52,14 @@ SkidMarks::SkidMarks(const AbstractKart& kart, float width) : m_kart(kart)
m_width = width;
m_material = material_manager->getMaterialSPM("skidmarks.png", "",
"alphablend");
m_shader = SP::SPShaderManager::get()->getSPShader("alphablend");
assert(m_shader);
auto texture = SP::SPTextureManager::get()->getTexture(
m_material->getSamplerPath(0), m_material,
m_shader->isSrgbForTextureLayer(0), m_material->getContainerId());
if (CVS->isGLSL())
{
m_shader = SP::SPShaderManager::get()->getSPShader("alphablend");
assert(m_shader);
auto texture = SP::SPTextureManager::get()->getTexture(
m_material->getSamplerPath(0), m_material,
m_shader->isSrgbForTextureLayer(0), m_material->getContainerId());
}
m_skid_marking = false;
} // SkidMark
@@ -222,19 +230,39 @@ SkidMarks::SkidMarkQuads::SkidMarkQuads(const Vec3 &left,
std::shared_ptr<SP::SPShader> shader,
float z_offset,
video::SColor* custom_color)
: m_node(NULL)
{
m_center_start = (left + right)/2;
m_z_offset = z_offset;
m_fade_out = 0.0f;
m_dy_dc = std::make_shared<SP::SPDynamicDrawCall>
(scene::EPT_TRIANGLE_STRIP, shader, material);
static_cast<SP::SPPerObjectUniform*>(m_dy_dc.get())->addAssignerFunction
("custom_alpha", [this](SP::SPUniformAssigner* ua)->void
{
// SP custom_alpha is assigned 1 - x, so this is correct
ua->setValue(m_fade_out);
});
SP::addDynamicDrawCall(m_dy_dc);
if (CVS->isGLSL())
{
m_dy_dc = std::make_shared<SP::SPDynamicDrawCall>
(scene::EPT_TRIANGLE_STRIP, shader, material);
static_cast<SP::SPPerObjectUniform*>(m_dy_dc.get())->addAssignerFunction
("custom_alpha", [this](SP::SPUniformAssigner* ua)->void
{
// SP custom_alpha is assigned 1 - x, so this is correct
ua->setValue(m_fade_out);
});
SP::addDynamicDrawCall(m_dy_dc);
}
else
{
scene::SMeshBuffer* buffer = new scene::SMeshBuffer();
material->setMaterialProperties(&buffer->getMaterial(), buffer);
buffer->getMaterial().setTexture(0, material->getTexture());
buffer->setHardwareMappingHint(scene::EHM_STREAM);
scene::SMesh* mesh = new scene::SMesh();
mesh->addMeshBuffer(buffer);
mesh->setBoundingBox(buffer->getBoundingBox());
buffer->drop();
m_node = static_cast<scene::IMeshSceneNode*>(
irr_driver->addMesh(mesh, "skidmark"));
m_node->getMaterial(0).getRenderInfo() =
std::make_shared<GE::GERenderInfo>();
mesh->drop();
}
m_start_color = (custom_color != NULL ? *custom_color :
video::SColor(255, SkidMarks::m_start_grey, SkidMarks::m_start_grey,
SkidMarks::m_start_grey));
@@ -252,17 +280,17 @@ SkidMarks::SkidMarkQuads::SkidMarkQuads(const Vec3 &left,
//-----------------------------------------------------------------------------
SkidMarks::SkidMarkQuads::~SkidMarkQuads()
{
m_dy_dc->removeFromSP();
if (m_dy_dc)
m_dy_dc->removeFromSP();
else if (m_node)
irr_driver->removeNode(m_node);
} // ~SkidMarkQuads
//-----------------------------------------------------------------------------
/** Adds the two points to this SkidMarkQuads.
* \param left,right Left and right coordinates.
*/
void SkidMarks::SkidMarkQuads::add(const Vec3 &left,
const Vec3 &right,
const Vec3 &normal,
float distance)
void SkidMarks::SkidMarkQuads::addSP(const Vec3& left,
const Vec3& right,
const Vec3& normal,
float distance)
{
// The skid marks must be raised slightly higher, otherwise it blends
// too much with the track.
@@ -294,7 +322,81 @@ void SkidMarks::SkidMarkQuads::add(const Vec3 &left,
m_dy_dc->addSPMVertex(v);
m_dy_dc->setUpdateOffset(n > 3 ? n - 2 : n);
m_dy_dc->recalculateBoundingBox();
} // addSP
//-----------------------------------------------------------------------------
void SkidMarks::SkidMarkQuads::addLegacy(const Vec3& left,
const Vec3& right,
const Vec3& normal,
float distance)
{
scene::IMesh* mesh = m_node->getMesh();
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(0);
// The skid marks must be raised slightly higher, otherwise it blends
// too much with the track.
int n = buffer->getVertexCount();
std::array<video::S3DVertex, 2> v;
v[0].Color = m_start_color;
v[0].Color.setAlpha(0); // initially create all vertices at alpha=0...
v[1] = v[0];
// then when adding a new set of vertices, make the previous 2 opaque.
// this ensures that the last two vertices are always at alpha=0,
// producing a fade-out effect
video::S3DVertex* vertices = (video::S3DVertex*)buffer->getVertices();
if (n > 4)
{
vertices[n - 1].Color.setAlpha(m_start_alpha);
vertices[n - 2].Color.setAlpha(m_start_alpha);
}
v[0].Pos = Vec3(left + normal * m_z_offset).toIrrVector();
v[0].Normal = normal.toIrrVector();
v[0].TCoords = core::vector2df(0.0f, distance * 0.5f);
v[1].Pos = Vec3(right + normal * m_z_offset).toIrrVector();
v[1].Normal = normal.toIrrVector();
v[1].TCoords = core::vector2df(1.0f, distance * 0.5f);
buffer->append(v.data(), v.size(), NULL, 0);
// Out of the box Irrlicht only supports triangle meshes and not
// triangle strips. Since this is a strip it would be more efficient
// to use a special triangle strip scene node.
if (n >= 2)
{
if (!m_node->isVisible())
m_node->setVisible(true);
std::array<uint16_t, 6> indices = {{ }};
buffer->append(NULL, 0, indices.data(), indices.size());
unsigned idx = buffer->getIndexCount() - indices.size();
buffer->getIndices()[idx + 0] = n - 2;
buffer->getIndices()[idx + 1] = n - 1;
buffer->getIndices()[idx + 2] = n;
buffer->getIndices()[idx + 3] = n - 1;
buffer->getIndices()[idx + 4] = n + 1;
buffer->getIndices()[idx + 5] = n;
}
else
m_node->setVisible(false);
// Adjust the axis-aligned boundary boxes.
mesh->setBoundingBox(buffer->getBoundingBox());
buffer->setDirty();
} // addLegacy
//-----------------------------------------------------------------------------
/** Adds the two points to this SkidMarkQuads.
* \param left,right Left and right coordinates.
*/
void SkidMarks::SkidMarkQuads::add(const Vec3 &left,
const Vec3 &right,
const Vec3 &normal,
float distance)
{
if (CVS->isGLSL())
addSP(left, right, normal, distance);
else
addLegacy(left, right, normal, distance);
} // add
// ----------------------------------------------------------------------------
@@ -304,6 +406,13 @@ void SkidMarks::SkidMarkQuads::add(const Vec3 &left,
*/
bool SkidMarks::SkidMarkQuads::fade(float f)
{
if (!CVS->isGLSL())
{
float a = (1.0f - m_fade_out) * 255.0f;
if (a > 255.0f)
a = 255.0f;
m_node->getMaterial(0).getRenderInfo()->getVertexColor().setAlpha(a);
}
m_fade_out += f;
if (m_fade_out >= 1.0f)
{

View File

@@ -20,7 +20,6 @@
#ifndef HEADER_SKID_MARK_HPP
#define HEADER_SKID_MARK_HPP
#include <aabbox3d.h>
#include <memory>
#include <SColor.h>
#include <vector>
@@ -35,6 +34,14 @@ namespace SP
class SPShader;
}
namespace irr
{
namespace scene
{
class IMeshSceneNode;
}
}
#include "utils/no_copy.hpp"
#include "utils/vec3.hpp"
@@ -85,12 +92,24 @@ private:
std::shared_ptr<SP::SPDynamicDrawCall> m_dy_dc;
irr::scene::IMeshSceneNode* m_node;
void addSP (const Vec3 &left,
const Vec3 &right,
const Vec3 &normal,
float distance);
void addLegacy (const Vec3 &left,
const Vec3 &right,
const Vec3 &normal,
float distance);
public:
SkidMarkQuads (const Vec3 &left, const Vec3 &right,
const Vec3 &normal, Material* material,
std::shared_ptr<SP::SPShader> shader,
float z_offset, video::SColor* custom_color = NULL);
~SkidMarkQuads();
void add (const Vec3 &left,
const Vec3 &right,
const Vec3 &normal,

View File

@@ -3006,7 +3006,7 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model)
m_skidmarks = nullptr;
m_shadow = nullptr;
if (!GUIEngine::isNoGraphics() &&
m_kart_properties->getSkidEnabled() && CVS->isGLSL())
m_kart_properties->getSkidEnabled())
{
m_skidmarks.reset(new SkidMarks(*this));
}