STARK: Implement lighting for props 3d models

This commit is contained in:
Bastien Bouclet 2018-12-01 11:25:55 +01:00
parent cf02210729
commit 036cca6b56
8 changed files with 155 additions and 17 deletions

View File

@ -48,7 +48,7 @@ OpenGLSPropRenderer::~OpenGLSPropRenderer() {
delete _shader;
}
void OpenGLSPropRenderer::render(const Math::Vector3d position, float direction) {
void OpenGLSPropRenderer::render(const Math::Vector3d &position, float direction, const LightEntryArray &lights) {
if (_modelIsDirty) {
// Update the OpenGL Buffer Objects if required
clearVertices();
@ -62,14 +62,26 @@ void OpenGLSPropRenderer::render(const Math::Vector3d position, float direction)
Math::Matrix4 view = StarkScene->getViewMatrix();
Math::Matrix4 projection = StarkScene->getProjectionMatrix();
Math::Matrix4 mvp = projection * view * model;
mvp.transpose();
Math::Matrix4 modelViewMatrix = view * model;
modelViewMatrix.transpose(); // OpenGL expects matrices transposed when compared to ResidualVM's
Math::Matrix4 projectionMatrix = projection;
projectionMatrix.transpose(); // OpenGL expects matrices transposed when compared to ResidualVM's
Math::Matrix4 normalMatrix = modelViewMatrix;
normalMatrix.invertAffineOrthonormal();
//normalMatrix.transpose(); // OpenGL expects matrices transposed when compared to ResidualVM's
//normalMatrix.transpose(); // No need to transpose twice in a row
_shader->enableVertexAttribute("position", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0);
_shader->enableVertexAttribute("normal", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 12);
_shader->enableVertexAttribute("texcoord", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 24);
_shader->use(true);
_shader->setUniform("mvp", mvp);
_shader->setUniform("modelViewMatrix", modelViewMatrix);
_shader->setUniform("projectionMatrix", projectionMatrix);
_shader->setUniform("normalMatrix", normalMatrix.getRotation());
setLightArrayUniform(lights);
const Common::Array<Face> &faces = _model->getFaces();
const Common::Array<Material> &materials = _model->getMaterials();
@ -126,5 +138,55 @@ GLuint OpenGLSPropRenderer::createFaceEBO(const Face *face) {
return OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices.front());
}
void OpenGLSPropRenderer::setLightArrayUniform(const LightEntryArray &lights) {
static const uint maxLights = 10;
assert(lights.size() >= 1);
assert(lights.size() <= maxLights);
const LightEntry *ambient = lights[0];
assert(ambient->type == LightEntry::kAmbient); // The first light must be the ambient light
_shader->setUniform("ambientColor", ambient->color);
Math::Matrix4 viewMatrix = StarkScene->getViewMatrix();
Math::Matrix3 viewMatrixRot = viewMatrix.getRotation();
for (uint i = 0; i < lights.size() - 1; i++) {
const LightEntry *l = lights[i + 1];
Math::Vector4d worldPosition;
worldPosition.x() = l->position.x();
worldPosition.y() = l->position.y();
worldPosition.z() = l->position.z();
worldPosition.w() = 1.0;
Math::Vector4d eyePosition = viewMatrix * worldPosition;
// The light type is stored in the w coordinate of the position to save an uniform slot
eyePosition.w() = l->type;
Math::Vector3d worldDirection = l->direction;
Math::Vector3d eyeDirection = viewMatrixRot * worldDirection;
eyeDirection.normalize();
_shader->setUniform(Common::String::format("lights[%d].position", i).c_str(), eyePosition);
_shader->setUniform(Common::String::format("lights[%d].direction", i).c_str(), eyeDirection);
_shader->setUniform(Common::String::format("lights[%d].color", i).c_str(), l->color);
Math::Vector4d params;
params.x() = l->falloffNear;
params.y() = l->falloffFar;
params.z() = l->innerConeAngle.getCosine();
params.w() = l->outerConeAngle.getCosine();
_shader->setUniform(Common::String::format("lights[%d].params", i).c_str(), params);
}
for (uint i = lights.size() - 1; i < maxLights; i++) {
// Make sure unused lights are disabled
_shader->setUniform(Common::String::format("lights[%d].position", i).c_str(), Math::Vector4d());
}
}
} // End of namespace Gfx
} // End of namespace Stark

View File

@ -43,10 +43,10 @@ class Driver;
class OpenGLSPropRenderer : public VisualProp {
public:
OpenGLSPropRenderer(Driver *gfx);
virtual ~OpenGLSPropRenderer();
explicit OpenGLSPropRenderer(Driver *gfx);
~OpenGLSPropRenderer() override;
void render(const Math::Vector3d position, float direction) override;
void render(const Math::Vector3d &position, float direction, const LightEntryArray &lights) override;
protected:
typedef Common::HashMap<const Face *, GLuint> FaceBufferMap;
@ -62,6 +62,9 @@ protected:
void uploadVertices();
GLuint createFaceVBO();
GLuint createFaceEBO(const Face *face);
void setLightArrayUniform(const LightEntryArray &lights);
};
} // End of namespace Gfx

View File

@ -65,7 +65,7 @@ void RenderEntry::render(const LightEntryArray &lights) {
VisualProp *prop = _visual->get<VisualProp>();
if (prop) {
prop->render(_position3D, _direction3D);
prop->render(_position3D, _direction3D, lights);
}
VisualSmacker *smacker = _visual->get<VisualSmacker>();

View File

@ -329,7 +329,7 @@ void UserInterface::optionsOpen() {
void UserInterface::saveGameScreenThumbnail() {
freeGameScreenThumbnail();
if (StarkGlobal->getLevel()) {
if (StarkGlobal->getLevel() && StarkGlobal->getCurrent()) {
// Re-render the screen to exclude the cursor
StarkGfx->clearScreen();
_gameScreen->render();

View File

@ -1,4 +1,5 @@
in vec2 Texcoord;
in vec3 Color;
OUTPUT
@ -7,9 +8,11 @@ uniform vec3 color;
uniform sampler2D tex;
void main() {
outColor = vec4(Color, 1.0);
if (textured) {
outColor = texture(tex, Texcoord);
outColor *= texture(tex, Texcoord);
} else {
outColor = vec4(color, 1.0);
outColor *= vec4(color, 1.0);
}
}

View File

@ -3,9 +3,58 @@ in vec3 normal;
in vec3 texcoord;
out vec2 Texcoord;
out vec3 Color;
uniform mat4 mvp;
struct Light {
vec4 position;
vec3 direction;
vec3 color;
vec4 params;
};
const int lightTypePoint = 1;
const int lightTypeDirectional = 2;
const int lightTypeSpot = 4;
const int maxLights = 10;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
uniform bool doubleSided;
uniform vec3 ambientColor;
uniform Light lights[maxLights];
vec4 eyePosition;
vec3 eyeNormal;
vec3 pointLight(vec3 position, vec3 color, float falloffNear, float falloffFar) {
vec3 vertexToLight = position - eyePosition.xyz;
float dist = length(vertexToLight);
float attn = clamp((falloffFar - dist) / max(0.001, falloffFar - falloffNear), 0.0, 1.0);
vertexToLight = normalize(vertexToLight);
float incidence = max(0.0, dot(eyeNormal, vertexToLight));
return color * attn * incidence;
}
vec3 directionalLight(vec3 direction, vec3 color) {
float incidence = max(0.0, dot(eyeNormal, -direction));
return color * incidence;
}
vec3 spotLight(vec3 position, vec3 color, float falloffNear, float falloffFar, vec3 direction, float cosInnerAngle, float cosOuterAngle) {
vec3 vertexToLight = position - eyePosition.xyz;
vertexToLight = normalize(vertexToLight);
float cosAngle = max(0.0, dot(vertexToLight, -direction));
float cone = clamp((cosAngle - cosInnerAngle) / max(0.001, cosOuterAngle - cosInnerAngle), 0.0, 1.0);
return pointLight(position, color, falloffNear, falloffFar) * cone;
}
void main() {
if (doubleSided) {
@ -14,5 +63,25 @@ void main() {
Texcoord = vec2(1.0 - texcoord.x, 1.0 - texcoord.y);
}
gl_Position = mvp * vec4(position.xyz, 1.0);
// Compute the vertex position in screen-space
eyePosition = modelViewMatrix * vec4(position.xyz, 1.0);
eyeNormal = normalMatrix * normal;
eyeNormal = normalize(eyeNormal);
gl_Position = projectionMatrix * eyePosition;
// Shade the vertex color according to the lights
vec3 lightColor = ambientColor;
for (int i = 0; i < maxLights; i++) {
int type = int(lights[i].position.w);
if (type == lightTypePoint) {
lightColor += pointLight(lights[i].position.xyz, lights[i].color, lights[i].params.x, lights[i].params.y);
} else if (type == lightTypeDirectional) {
lightColor += directionalLight(lights[i].direction, lights[i].color);
} else if (type == lightTypeSpot) {
lightColor += spotLight(lights[i].position.xyz, lights[i].color, lights[i].params.x, lights[i].params.y,
lights[i].direction, lights[i].params.z, lights[i].params.w);
}
}
Color = clamp(lightColor, 0.0, 1.0);
}

View File

@ -71,7 +71,7 @@ Math::Matrix4 VisualProp::getModelMatrix(const Math::Vector3d& position, float d
return posMatrix * rot1 * rot2 * modelTransform;
}
bool VisualProp::intersectRay(const Math::Ray &ray, const Math::Vector3d position, float direction) {
bool VisualProp::intersectRay(const Math::Ray &ray, const Math::Vector3d &position, float direction) {
Math::Matrix4 inverseModelMatrix = getModelMatrix(position, direction);
inverseModelMatrix.inverse();

View File

@ -28,6 +28,7 @@
#include "math/vector3d.h"
#include "engines/stark/visual/visual.h"
#include "engines/stark/gfx/renderentry.h"
namespace Stark {
@ -44,13 +45,13 @@ public:
static const VisualType TYPE = Visual::kRendered;
VisualProp();
virtual ~VisualProp();
~VisualProp() override;
void setModel(Formats::BiffMesh *model);
void setTexture(Gfx::TextureSet *texture);
bool intersectRay(const Math::Ray &ray, const Math::Vector3d position, float direction);
virtual void render(const Math::Vector3d position, float direction) = 0;
bool intersectRay(const Math::Ray &ray, const Math::Vector3d &position, float direction);
virtual void render(const Math::Vector3d &position, float direction, const Gfx::LightEntryArray &lights) = 0;
protected:
Formats::BiffMesh *_model;