mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-19 00:15:30 +00:00
STARK: Implement lighting for props 3d models
This commit is contained in:
parent
cf02210729
commit
036cca6b56
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user