Initial vertex lighting support.
This commit is contained in:
parent
67a0650cdb
commit
a51afb0631
@ -11,6 +11,7 @@ Scene@ testScene;
|
||||
Node@ cameraNode;
|
||||
Camera@ camera;
|
||||
Node@ cameraLightNode;
|
||||
Light@ cameraLight;
|
||||
float yaw = 0.0;
|
||||
float pitch = 0.0;
|
||||
float objectangle = 0.0;
|
||||
@ -303,7 +304,7 @@ void CreateCamera()
|
||||
cameraNode.position = Vector3(-50, 2, -50);
|
||||
|
||||
cameraLightNode = cameraNode.CreateChild("CameraLight");
|
||||
Light@ cameraLight = cameraLightNode.CreateComponent("Light");
|
||||
cameraLight = cameraLightNode.CreateComponent("Light");
|
||||
cameraLight.lightType = LIGHT_SPOT;
|
||||
cameraLight.range = 50;
|
||||
cameraLight.color = Color(2, 2, 2);
|
||||
@ -416,6 +417,9 @@ void HandleUpdate(StringHash eventType, VariantMap& eventData)
|
||||
cameraLightNode.parent = testScene;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.keyPress['V'])
|
||||
cameraLight.perVertex = !cameraLight.perVertex;
|
||||
|
||||
if (input.keyPress['C'])
|
||||
camera.orthographic = !camera.orthographic;
|
||||
|
@ -1664,6 +1664,7 @@ Properties:<br>
|
||||
- uint maxLights
|
||||
- BoundingBox& worldBoundingBox (readonly)
|
||||
- LightType lightType
|
||||
- bool perVertex
|
||||
- Color& color
|
||||
- float specularIntensity
|
||||
- float range
|
||||
|
@ -467,6 +467,8 @@ static void RegisterLight(asIScriptEngine* engine)
|
||||
RegisterDrawable<Light>(engine, "Light");
|
||||
engine->RegisterObjectMethod("Light", "void set_lightType(LightType)", asMETHOD(Light, SetLightType), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Light", "LightType get_lightType() const", asMETHOD(Light, GetLightType), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Light", "void set_perVertex(bool)", asMETHOD(Light, SetPerVertex), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Light", "bool get_perVertex() const", asMETHOD(Light, GetPerVertex), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Light", "void set_color(const Color&in)", asMETHOD(Light, SetColor), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Light", "const Color& get_color() const", asMETHOD(Light, GetColor), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Light", "void set_specularIntensity(float)", asMETHOD(Light, SetSpecularIntensity), asCALL_THISCALL);
|
||||
|
@ -172,7 +172,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
|
||||
if (graphics->NeedParameterUpdate(PSP_AMBIENTSTARTCOLOR, zone_))
|
||||
graphics->SetShaderParameter(PSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor().ToVector4());
|
||||
if (graphics->NeedParameterUpdate(PSP_AMBIENTENDCOLOR, zone_))
|
||||
graphics->SetShaderParameter(PSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4());
|
||||
graphics->SetShaderParameter(PSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
|
||||
|
||||
// If the pass is additive, override fog color to black so that shaders do not need a separate additive path
|
||||
BlendMode blend = pass_->GetBlendMode();
|
||||
@ -246,6 +246,56 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
|
||||
graphics->SetShaderParameter(VSP_SPOTPROJ, texAdjust * spotProj * spotView.Inverse());
|
||||
}
|
||||
|
||||
if (graphics->NeedParameterUpdate(VSP_VERTEXLIGHTS, lightQueue_))
|
||||
{
|
||||
Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
|
||||
const PODVector<Light*>& lights = lightQueue_->vertexLights_;
|
||||
|
||||
for (unsigned i = 0; i < lights.Size(); ++i)
|
||||
{
|
||||
Light* vertexLight = lights[i];
|
||||
LightType type = vertexLight->GetLightType();
|
||||
|
||||
// Attenuation
|
||||
float invRange, cutoff, invCutoff;
|
||||
if (type == LIGHT_DIRECTIONAL)
|
||||
invRange = 0.0f;
|
||||
else
|
||||
invRange = 1.0f / max(vertexLight->GetRange(), M_EPSILON);
|
||||
if (type == LIGHT_SPOT)
|
||||
{
|
||||
cutoff = cosf(vertexLight->GetFov() * 0.5f * M_DEGTORAD);
|
||||
invCutoff = 1.0f / (1.0f - cutoff);
|
||||
}
|
||||
else
|
||||
{
|
||||
cutoff = -1.0f;
|
||||
invCutoff = 1.0f;
|
||||
}
|
||||
|
||||
// Color
|
||||
float fade = 1.0f;
|
||||
float fadeEnd = vertexLight->GetDrawDistance();
|
||||
float fadeStart = vertexLight->GetFadeDistance();
|
||||
|
||||
// Do fade calculation for light if both fade & draw distance defined
|
||||
if (vertexLight->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
|
||||
fade = Min(1.0f - (vertexLight->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
|
||||
|
||||
Color color = vertexLight->GetColor() * fade;
|
||||
vertexLights[i * 3] = Vector4(color.r_, color.g_, color.b_, invRange);
|
||||
|
||||
// Direction
|
||||
vertexLights[i * 3 + 1] = Vector4(-(vertexLight->GetNode()->GetWorldDirection()), cutoff);
|
||||
|
||||
// Position
|
||||
vertexLights[i * 3 + 2] = Vector4(vertexLight->GetWorldPosition(), invCutoff);
|
||||
}
|
||||
|
||||
if (lights.Size())
|
||||
graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].GetData(), lights.Size() * 3 * 4);
|
||||
}
|
||||
|
||||
if (graphics->NeedParameterUpdate(PSP_LIGHTCOLOR, light))
|
||||
{
|
||||
float fade = 1.0f;
|
||||
|
@ -290,7 +290,7 @@ struct ShadowBatchQueue
|
||||
/// Queue for light related draw calls
|
||||
struct LightBatchQueue
|
||||
{
|
||||
/// Light drawable.
|
||||
/// Per-pixel light.
|
||||
Light* light_;
|
||||
/// Lit geometry draw calls.
|
||||
BatchQueue litBatches_;
|
||||
@ -298,4 +298,6 @@ struct LightBatchQueue
|
||||
Texture2D* shadowMap_;
|
||||
/// Shadow map split queues.
|
||||
Vector<ShadowBatchQueue> shadowSplits_;
|
||||
/// Per-vertex lights.
|
||||
PODVector<Light*> vertexLights_;
|
||||
};
|
||||
|
@ -40,6 +40,9 @@ OBJECTTYPESTATIC(Drawable);
|
||||
Drawable::Drawable(Context* context) :
|
||||
Component(context),
|
||||
octant_(0),
|
||||
viewFrame_(0),
|
||||
viewCamera_(0),
|
||||
firstLight_(0),
|
||||
drawDistance_(0.0f),
|
||||
shadowDistance_(0.0f),
|
||||
lodBias_(1.0f),
|
||||
@ -52,9 +55,6 @@ Drawable::Drawable(Context* context) :
|
||||
lodDistance_(0.0f),
|
||||
sortValue_(0.0f),
|
||||
viewFrameNumber_(0),
|
||||
viewFrame_(0),
|
||||
viewCamera_(0),
|
||||
firstLight_(0),
|
||||
drawableFlags_(0),
|
||||
visible_(true),
|
||||
castShadows_(false),
|
||||
@ -219,6 +219,7 @@ void Drawable::ClearLights()
|
||||
basePassFlags_[i] = 0;
|
||||
firstLight_ = 0;
|
||||
lights_.Clear();
|
||||
vertexLights_.Clear();
|
||||
}
|
||||
|
||||
void Drawable::AddLight(Light* light)
|
||||
@ -228,6 +229,11 @@ void Drawable::AddLight(Light* light)
|
||||
lights_.Push(light);
|
||||
}
|
||||
|
||||
void Drawable::AddVertexLight(Light* light)
|
||||
{
|
||||
vertexLights_.Push(light);
|
||||
}
|
||||
|
||||
void Drawable::LimitLights()
|
||||
{
|
||||
// Maximum lights value 0 means unlimited
|
||||
@ -244,6 +250,17 @@ void Drawable::LimitLights()
|
||||
lights_.Resize(maxLights_);
|
||||
}
|
||||
|
||||
void Drawable::LimitVertexLights()
|
||||
{
|
||||
for (unsigned i = 0; i < vertexLights_.Size(); ++i)
|
||||
vertexLights_[i]->SetIntensitySortValue(GetWorldBoundingBox());
|
||||
|
||||
Sort(vertexLights_.Begin(), vertexLights_.End(), CompareDrawables);
|
||||
|
||||
if (vertexLights_.Size() > MAX_VERTEX_LIGHTS)
|
||||
vertexLights_.Resize(MAX_VERTEX_LIGHTS);
|
||||
}
|
||||
|
||||
void Drawable::SetBasePass(unsigned batchIndex)
|
||||
{
|
||||
unsigned index = batchIndex >> 5;
|
||||
|
@ -37,6 +37,7 @@ static const unsigned DEFAULT_LIGHTMASK = M_MAX_UNSIGNED;
|
||||
static const unsigned DEFAULT_SHADOWMASK = M_MAX_UNSIGNED;
|
||||
static const unsigned DEFAULT_ZONEMASK = M_MAX_UNSIGNED;
|
||||
static const int DRAWABLES_PER_WORK_ITEM = 16;
|
||||
static const int MAX_VERTEX_LIGHTS = 4;
|
||||
|
||||
struct Batch;
|
||||
class Camera;
|
||||
@ -170,10 +171,14 @@ public:
|
||||
void MarkInView(const FrameInfo& frame, bool mainView = true);
|
||||
/// Clear lights and base pass flags for a new frame.
|
||||
void ClearLights();
|
||||
/// Add a light.
|
||||
/// Add a per-pixel light.
|
||||
void AddLight(Light* light);
|
||||
/// Sort and limit lights to maximum allowed.
|
||||
/// Add a per-vertex light.
|
||||
void AddVertexLight(Light* light);
|
||||
/// Sort and limit per-pixel lights to maximum allowed.
|
||||
void LimitLights();
|
||||
/// Sort and limit per-vertex lights to maximum allowed.
|
||||
void LimitVertexLights();
|
||||
/// %Set base pass flag for a batch.
|
||||
void SetBasePass(unsigned batchIndex);
|
||||
/// Return octree octant.
|
||||
@ -194,9 +199,11 @@ public:
|
||||
bool IsInView(const FrameInfo& frame, bool mainView = true) const { return viewFrameNumber_ == frame.frameNumber_ && viewFrame_ == &frame && (!mainView || viewCamera_ == frame.camera_); }
|
||||
/// Return whether has a base pass.
|
||||
bool HasBasePass(unsigned batchIndex) const;
|
||||
/// Return lights.
|
||||
/// Return per-pixel lights.
|
||||
const PODVector<Light*>& GetLights() const { return lights_; }
|
||||
/// Return the first added light.
|
||||
/// Return per-vertex lights.
|
||||
const PODVector<Light*>& GetVertexLights() const { return vertexLights_; }
|
||||
/// Return the first added per-pixel light.
|
||||
Light* GetFirstLight() const { return firstLight_; }
|
||||
|
||||
protected:
|
||||
@ -217,6 +224,22 @@ protected:
|
||||
Octant* octant_;
|
||||
/// World bounding box.
|
||||
BoundingBox worldBoundingBox_;
|
||||
/// Base pass flags per batch index.
|
||||
PODVector<unsigned> basePassFlags_;
|
||||
/// Last view's frameinfo. Not safe to dereference.
|
||||
const FrameInfo* viewFrame_;
|
||||
/// Last view's camera. Not safe to dereference.
|
||||
Camera* viewCamera_;
|
||||
/// Per-pixel lights affecting this drawable.
|
||||
PODVector<Light*> lights_;
|
||||
/// Per-vertex lights affecting this drawable.
|
||||
PODVector<Light*> vertexLights_;
|
||||
/// First per-pixel light added this frame.
|
||||
Light* firstLight_;
|
||||
/// Current zone.
|
||||
WeakPtr<Zone> zone_;
|
||||
/// Previous zone.
|
||||
WeakPtr<Zone> lastZone_;
|
||||
/// Draw distance.
|
||||
float drawDistance_;
|
||||
/// Shadow distance.
|
||||
@ -241,20 +264,6 @@ protected:
|
||||
float sortValue_;
|
||||
/// Last visible frame number.
|
||||
unsigned viewFrameNumber_;
|
||||
/// Base pass flags per batch index.
|
||||
PODVector<unsigned> basePassFlags_;
|
||||
/// Last view's frameinfo. Not safe to dereference.
|
||||
const FrameInfo* viewFrame_;
|
||||
/// Last view's camera. Not safe to dereference.
|
||||
Camera* viewCamera_;
|
||||
/// Lights affecting this drawable.
|
||||
PODVector<Light*> lights_;
|
||||
/// First light added this frame.
|
||||
Light* firstLight_;
|
||||
/// Current zone.
|
||||
WeakPtr<Zone> zone_;
|
||||
/// Previous zone.
|
||||
WeakPtr<Zone> lastZone_;
|
||||
/// Drawable flags.
|
||||
unsigned char drawableFlags_;
|
||||
/// Visible flag.
|
||||
|
@ -43,6 +43,7 @@ StringHash VSP_VIEWRIGHTVECTOR("ViewRightVector");
|
||||
StringHash VSP_VIEWUPVECTOR("ViewUpVector");
|
||||
StringHash VSP_ZONE("Zone");
|
||||
StringHash VSP_SKINMATRICES("SkinMatrices");
|
||||
StringHash VSP_VERTEXLIGHTS("VertexLights");
|
||||
StringHash PSP_AMBIENTSTARTCOLOR("AmbientStartColor");
|
||||
StringHash PSP_AMBIENTENDCOLOR("AmbientEndColor");
|
||||
StringHash PSP_FOGCOLOR("FogColor");
|
||||
|
@ -211,6 +211,7 @@ extern StringHash VSP_VIEWRIGHTVECTOR;
|
||||
extern StringHash VSP_VIEWUPVECTOR;
|
||||
extern StringHash VSP_ZONE;
|
||||
extern StringHash VSP_SKINMATRICES;
|
||||
extern StringHash VSP_VERTEXLIGHTS;
|
||||
extern StringHash PSP_AMBIENTSTARTCOLOR;
|
||||
extern StringHash PSP_AMBIENTENDCOLOR;
|
||||
extern StringHash PSP_FOGCOLOR;
|
||||
|
@ -82,6 +82,7 @@ OBJECTTYPESTATIC(Light);
|
||||
Light::Light(Context* context) :
|
||||
Drawable(context),
|
||||
lightType_(DEFAULT_LIGHTTYPE),
|
||||
perVertex_(false),
|
||||
specularIntensity_(0.0f),
|
||||
range_(DEFAULT_RANGE),
|
||||
fov_(DEFAULT_FOV),
|
||||
@ -115,6 +116,7 @@ void Light::RegisterObject(Context* context)
|
||||
ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Attenuation Texture", GetRampTextureAttr, SetRampTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
|
||||
ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Light Shape Texture", GetShapeTextureAttr, SetShapeTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
|
||||
ATTRIBUTE(Light, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
|
||||
ATTRIBUTE(Light, VAR_BOOL, "Per Vertex", perVertex_, false, AM_DEFAULT);
|
||||
ATTRIBUTE(Light, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
|
||||
ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
|
||||
ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Fade Distance", GetFadeDistance, SetFadeDistance, float, 0.0f, AM_DEFAULT);
|
||||
@ -261,6 +263,11 @@ void Light::SetLightType(LightType type)
|
||||
OnMarkedDirty(node_);
|
||||
}
|
||||
|
||||
void Light::SetPerVertex(bool enable)
|
||||
{
|
||||
perVertex_ = enable;
|
||||
}
|
||||
|
||||
void Light::SetColor(const Color& color)
|
||||
{
|
||||
color_ = color;
|
||||
@ -426,6 +433,10 @@ void Light::SetIntensitySortValue(float distance)
|
||||
sortValue_ = Max(distance, M_MIN_NEARCLIP) / (color_.Intensity() + M_EPSILON);
|
||||
else
|
||||
sortValue_ = M_EPSILON / (color_.Intensity() + M_EPSILON);
|
||||
|
||||
// Additionally, give priority to vertex lights so that vertex light base passes can be determined before per pixel lights
|
||||
if (perVertex_)
|
||||
sortValue_ -= M_LARGE_VALUE;
|
||||
}
|
||||
|
||||
void Light::SetIntensitySortValue(const BoundingBox& box)
|
||||
|
@ -167,6 +167,8 @@ public:
|
||||
|
||||
/// %Set light type.
|
||||
void SetLightType(LightType type);
|
||||
/// %Set vertex lighting mode.
|
||||
void SetPerVertex(bool enable);
|
||||
/// %Set color.
|
||||
void SetColor(const Color& color);
|
||||
/// %Set specular intensity.
|
||||
@ -200,6 +202,8 @@ public:
|
||||
|
||||
/// Return light type.
|
||||
LightType GetLightType() const { return lightType_; }
|
||||
/// Return vertex lighting mode.
|
||||
bool GetPerVertex() const { return perVertex_; }
|
||||
/// Return color.
|
||||
const Color& GetColor() const { return color_; }
|
||||
/// Return specular intensity.
|
||||
@ -212,7 +216,7 @@ public:
|
||||
float GetAspectRatio() const { return aspectRatio_; }
|
||||
/// Return fade start distance.
|
||||
float GetFadeDistance() const { return fadeDistance_; }
|
||||
/// Return shadow fade start distance.
|
||||
/// Return shadow fade start distance.
|
||||
float GetShadowFadeDistance() const { return shadowFadeDistance_; }
|
||||
/// Return shadow depth bias parameters.
|
||||
const BiasParameters& GetShadowBias() const { return shadowBias_; }
|
||||
@ -256,6 +260,8 @@ protected:
|
||||
private:
|
||||
/// Light type.
|
||||
LightType lightType_;
|
||||
/// Per-vertex lighting flag.
|
||||
bool perVertex_;
|
||||
/// Color.
|
||||
Color color_;
|
||||
/// Specular intensity.
|
||||
|
@ -87,7 +87,13 @@ bool ShaderVariation::Create()
|
||||
// Prepend the defines to the shader code
|
||||
String shaderCode;
|
||||
for (unsigned i = 0; i < defines_.Size(); ++i)
|
||||
shaderCode += "#define " + defines_[i] + "\n";
|
||||
{
|
||||
Vector<String> nameAndValue = defines_[i].Split('=');
|
||||
if (nameAndValue.Size() < 2)
|
||||
shaderCode += "#define " + defines_[i] + "\n";
|
||||
else
|
||||
shaderCode += "#define " + nameAndValue[0] + " " + nameAndValue[1] + "\n";
|
||||
}
|
||||
if (!defines_.Empty())
|
||||
shaderCode += "\n";
|
||||
shaderCode += String(sourceCode_.Get(), sourceCodeLength_);
|
||||
|
@ -201,6 +201,15 @@ static const String lightVSVariations[] =
|
||||
"PointSpecShadow"
|
||||
};
|
||||
|
||||
static const String vertexLightVSVariations[] =
|
||||
{
|
||||
"",
|
||||
"1VL",
|
||||
"2VL",
|
||||
"3VL",
|
||||
"4VL"
|
||||
};
|
||||
|
||||
static const String lightPSVariations[] =
|
||||
{
|
||||
"Dir",
|
||||
@ -980,8 +989,27 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, b
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned vsi = geomType;
|
||||
batch.vertexShader_ = vertexShaders[vsi];
|
||||
if (type == PASS_BASE)
|
||||
{
|
||||
unsigned numVertexLights = 0;
|
||||
if (batch.lightQueue_)
|
||||
numVertexLights = batch.lightQueue_->vertexLights_.Size();
|
||||
|
||||
unsigned vsi = geomType * MAX_VERTEXLIGHT_VS_VARIATIONS + numVertexLights;
|
||||
batch.vertexShader_ = vertexShaders[vsi];
|
||||
// If vertex lights variations do not exist, try without them
|
||||
if (!batch.vertexShader_)
|
||||
{
|
||||
unsigned vsi = geomType * MAX_VERTEXLIGHT_VS_VARIATIONS;
|
||||
batch.vertexShader_ = vertexShaders[vsi];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned vsi = geomType;
|
||||
batch.vertexShader_ = vertexShaders[vsi];
|
||||
}
|
||||
|
||||
batch.pixelShader_ = pixelShaders[0];
|
||||
}
|
||||
}
|
||||
@ -1184,10 +1212,24 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexShaders.Resize(MAX_GEOMETRYTYPES);
|
||||
if (type == PASS_BASE)
|
||||
{
|
||||
vertexShaders.Resize(MAX_VERTEXLIGHT_VS_VARIATIONS * MAX_GEOMETRYTYPES);
|
||||
for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_VERTEXLIGHT_VS_VARIATIONS; ++j)
|
||||
{
|
||||
unsigned g = j / MAX_VERTEXLIGHT_VS_VARIATIONS;
|
||||
unsigned l = j % MAX_VERTEXLIGHT_VS_VARIATIONS;
|
||||
vertexShaders[j] = GetVertexShader(vertexShaderName + vertexLightVSVariations[l] + geometryVSVariations[g], g != 0 || l != 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexShaders.Resize(MAX_GEOMETRYTYPES);
|
||||
for (unsigned j = 0; j < MAX_GEOMETRYTYPES; ++j)
|
||||
vertexShaders[j] = GetVertexShader(vertexShaderName + geometryVSVariations[j], j != 0);
|
||||
}
|
||||
|
||||
pixelShaders.Resize(1);
|
||||
for (unsigned j = 0; j < MAX_GEOMETRYTYPES; ++j)
|
||||
vertexShaders[j] = GetVertexShader(vertexShaderName + geometryVSVariations[j], j != 0);
|
||||
pixelShaders[0] = GetPixelShader(pixelShaderName);
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,17 @@ enum LightVSVariation
|
||||
MAX_LIGHT_VS_VARIATIONS
|
||||
};
|
||||
|
||||
/// Per-vertex light vertex shader variations.
|
||||
enum VertexLightVSVariation
|
||||
{
|
||||
VLVS_NOLIGHTS = 0,
|
||||
VLVS_1LIGHT,
|
||||
VLVS_2LIGHTS,
|
||||
VLVS_3LIGHTS,
|
||||
VLVS_4LIGHTS,
|
||||
MAX_VERTEXLIGHT_VS_VARIATIONS
|
||||
};
|
||||
|
||||
/// Light pixel shader variations.
|
||||
enum LightPSVariation
|
||||
{
|
||||
|
@ -242,6 +242,7 @@ void View::Update(const FrameInfo& frame)
|
||||
alphaQueue_.Clear();
|
||||
postAlphaQueue_.Clear();
|
||||
lightQueues_.Clear();
|
||||
vertexLightQueues_.Clear();
|
||||
|
||||
// Do not update if camera projection is illegal
|
||||
// (there is a possibility of crash if occlusion is used and it can not clip properly)
|
||||
@ -520,93 +521,108 @@ void View::GetBatches()
|
||||
PROFILE(GetLightBatches);
|
||||
|
||||
Light* light = query.light_;
|
||||
unsigned shadowSplits = query.numSplits_;
|
||||
|
||||
// Initialize light queue. Store light-to-queue mapping so that the queue can be found later
|
||||
lightQueues_.Resize(lightQueues_.Size() + 1);
|
||||
LightBatchQueue& lightQueue = lightQueues_.Back();
|
||||
lightQueueMapping_[light] = &lightQueue;
|
||||
lightQueue.light_ = light;
|
||||
lightQueue.litBatches_.Clear();
|
||||
|
||||
// Allocate shadow map now
|
||||
lightQueue.shadowMap_ = 0;
|
||||
if (shadowSplits > 0)
|
||||
// Per-pixel light
|
||||
if (!light->GetPerVertex())
|
||||
{
|
||||
lightQueue.shadowMap_ = renderer_->GetShadowMap(light, camera_, width_, height_);
|
||||
// If did not manage to get a shadow map, convert the light to unshadowed
|
||||
if (!lightQueue.shadowMap_)
|
||||
shadowSplits = 0;
|
||||
}
|
||||
|
||||
// Setup shadow batch queues
|
||||
lightQueue.shadowSplits_.Resize(shadowSplits);
|
||||
for (unsigned j = 0; j < shadowSplits; ++j)
|
||||
{
|
||||
ShadowBatchQueue& shadowQueue = lightQueue.shadowSplits_[j];
|
||||
Camera* shadowCamera = query.shadowCameras_[j];
|
||||
shadowQueue.shadowCamera_ = shadowCamera;
|
||||
shadowQueue.nearSplit_ = query.shadowNearSplits_[j];
|
||||
shadowQueue.farSplit_ = query.shadowFarSplits_[j];
|
||||
unsigned shadowSplits = query.numSplits_;
|
||||
|
||||
// Setup the shadow split viewport and finalize shadow camera parameters
|
||||
shadowQueue.shadowViewport_ = GetShadowMapViewport(light, j, lightQueue.shadowMap_);
|
||||
FinalizeShadowCamera(shadowCamera, light, shadowQueue.shadowViewport_, query.shadowCasterBox_[j]);
|
||||
// Initialize light queue. Store light-to-queue mapping so that the queue can be found later
|
||||
lightQueues_.Resize(lightQueues_.Size() + 1);
|
||||
LightBatchQueue& lightQueue = lightQueues_.Back();
|
||||
lightQueueMapping_[light] = &lightQueue;
|
||||
lightQueue.light_ = light;
|
||||
lightQueue.litBatches_.Clear();
|
||||
|
||||
// Loop through shadow casters
|
||||
for (PODVector<Drawable*>::ConstIterator k = query.shadowCasters_.Begin() + query.shadowCasterBegin_[j];
|
||||
k < query.shadowCasters_.Begin() + query.shadowCasterEnd_[j]; ++k)
|
||||
// Allocate shadow map now
|
||||
lightQueue.shadowMap_ = 0;
|
||||
if (shadowSplits > 0)
|
||||
{
|
||||
Drawable* drawable = *k;
|
||||
if (!drawable->IsInView(frame_, false))
|
||||
{
|
||||
drawable->MarkInView(frame_, false);
|
||||
allGeometries_.Push(drawable);
|
||||
}
|
||||
lightQueue.shadowMap_ = renderer_->GetShadowMap(light, camera_, width_, height_);
|
||||
// If did not manage to get a shadow map, convert the light to unshadowed
|
||||
if (!lightQueue.shadowMap_)
|
||||
shadowSplits = 0;
|
||||
}
|
||||
|
||||
// Setup shadow batch queues
|
||||
lightQueue.shadowSplits_.Resize(shadowSplits);
|
||||
for (unsigned j = 0; j < shadowSplits; ++j)
|
||||
{
|
||||
ShadowBatchQueue& shadowQueue = lightQueue.shadowSplits_[j];
|
||||
Camera* shadowCamera = query.shadowCameras_[j];
|
||||
shadowQueue.shadowCamera_ = shadowCamera;
|
||||
shadowQueue.nearSplit_ = query.shadowNearSplits_[j];
|
||||
shadowQueue.farSplit_ = query.shadowFarSplits_[j];
|
||||
|
||||
unsigned numBatches = drawable->GetNumBatches();
|
||||
// Setup the shadow split viewport and finalize shadow camera parameters
|
||||
shadowQueue.shadowViewport_ = GetShadowMapViewport(light, j, lightQueue.shadowMap_);
|
||||
FinalizeShadowCamera(shadowCamera, light, shadowQueue.shadowViewport_, query.shadowCasterBox_[j]);
|
||||
|
||||
for (unsigned l = 0; l < numBatches; ++l)
|
||||
// Loop through shadow casters
|
||||
for (PODVector<Drawable*>::ConstIterator k = query.shadowCasters_.Begin() + query.shadowCasterBegin_[j];
|
||||
k < query.shadowCasters_.Begin() + query.shadowCasterEnd_[j]; ++k)
|
||||
{
|
||||
Batch shadowBatch;
|
||||
drawable->GetBatch(shadowBatch, frame_, l);
|
||||
Drawable* drawable = *k;
|
||||
if (!drawable->IsInView(frame_, false))
|
||||
{
|
||||
drawable->MarkInView(frame_, false);
|
||||
allGeometries_.Push(drawable);
|
||||
}
|
||||
|
||||
Technique* tech = GetTechnique(drawable, shadowBatch.material_);
|
||||
if (!shadowBatch.geometry_ || !tech)
|
||||
continue;
|
||||
unsigned numBatches = drawable->GetNumBatches();
|
||||
|
||||
Pass* pass = tech->GetPass(PASS_SHADOW);
|
||||
// Skip if material has no shadow pass
|
||||
if (!pass)
|
||||
continue;
|
||||
|
||||
// Fill the rest of the batch
|
||||
shadowBatch.camera_ = shadowCamera;
|
||||
shadowBatch.zone_ = GetZone(drawable);
|
||||
shadowBatch.lightQueue_ = &lightQueue;
|
||||
|
||||
FinalizeBatch(shadowBatch, tech, pass);
|
||||
shadowQueue.shadowBatches_.AddBatch(shadowBatch);
|
||||
for (unsigned l = 0; l < numBatches; ++l)
|
||||
{
|
||||
Batch shadowBatch;
|
||||
drawable->GetBatch(shadowBatch, frame_, l);
|
||||
|
||||
Technique* tech = GetTechnique(drawable, shadowBatch.material_);
|
||||
if (!shadowBatch.geometry_ || !tech)
|
||||
continue;
|
||||
|
||||
Pass* pass = tech->GetPass(PASS_SHADOW);
|
||||
// Skip if material has no shadow pass
|
||||
if (!pass)
|
||||
continue;
|
||||
|
||||
// Fill the rest of the batch
|
||||
shadowBatch.camera_ = shadowCamera;
|
||||
shadowBatch.zone_ = GetZone(drawable);
|
||||
shadowBatch.lightQueue_ = &lightQueue;
|
||||
|
||||
FinalizeBatch(shadowBatch, tech, pass);
|
||||
shadowQueue.shadowBatches_.AddBatch(shadowBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through lit geometries
|
||||
for (PODVector<Drawable*>::ConstIterator j = query.litGeometries_.Begin(); j != query.litGeometries_.End(); ++j)
|
||||
{
|
||||
Drawable* drawable = *j;
|
||||
drawable->AddLight(light);
|
||||
|
||||
// If drawable limits maximum lights, only record the light, and check maximum count / build batches later
|
||||
if (!drawable->GetMaxLights())
|
||||
GetLitBatches(drawable, lightQueue);
|
||||
else
|
||||
maxLightsDrawables_.Insert(drawable);
|
||||
// Loop through lit geometries
|
||||
for (PODVector<Drawable*>::ConstIterator j = query.litGeometries_.Begin(); j != query.litGeometries_.End(); ++j)
|
||||
{
|
||||
Drawable* drawable = *j;
|
||||
drawable->AddLight(light);
|
||||
|
||||
// If drawable limits maximum lights, only record the light, and check maximum count / build batches later
|
||||
if (!drawable->GetMaxLights())
|
||||
GetLitBatches(drawable, lightQueue);
|
||||
else
|
||||
maxLightsDrawables_.Insert(drawable);
|
||||
}
|
||||
}
|
||||
// Per-vertex light
|
||||
else
|
||||
{
|
||||
// Loop through lit geometries
|
||||
for (PODVector<Drawable*>::ConstIterator j = query.litGeometries_.Begin(); j != query.litGeometries_.End(); ++j)
|
||||
{
|
||||
Drawable* drawable = *j;
|
||||
drawable->AddVertexLight(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process drawables with limited light count
|
||||
// Process drawables with limited per-pixel light count
|
||||
if (maxLightsDrawables_.Size())
|
||||
{
|
||||
PROFILE(GetMaxLightsBatches);
|
||||
@ -650,7 +666,7 @@ void View::GetBatches()
|
||||
if (!renderTarget_ && baseBatch.material_ && baseBatch.material_->GetAuxViewFrameNumber() != frame_.frameNumber_)
|
||||
CheckMaterialForAuxView(baseBatch.material_);
|
||||
|
||||
// If object already has a lit base pass, can skip the unlit base pass
|
||||
// If object already has a pixel lit base pass, can skip the unlit / vertex lit base pass
|
||||
if (drawable->HasBasePass(j))
|
||||
continue;
|
||||
|
||||
@ -661,10 +677,28 @@ void View::GetBatches()
|
||||
|
||||
Pass* pass = 0;
|
||||
|
||||
// Check for unlit base pass
|
||||
// Check for unlit or vertex lit base pass
|
||||
pass = tech->GetPass(PASS_BASE);
|
||||
if (pass)
|
||||
{
|
||||
// Check for vertex lights now
|
||||
const PODVector<Light*>& vertexLights = drawable->GetVertexLights();
|
||||
if (!vertexLights.Empty())
|
||||
{
|
||||
drawable->LimitVertexLights();
|
||||
|
||||
// Find a vertex light queue. If not found, create new
|
||||
unsigned hash = GetVertexLightQueueHash(vertexLights);
|
||||
HashMap<unsigned, LightBatchQueue>::Iterator i = vertexLightQueues_.Find(hash);
|
||||
if (i == vertexLightQueues_.End())
|
||||
{
|
||||
vertexLightQueues_[hash].vertexLights_ = vertexLights;
|
||||
i = vertexLightQueues_.Find(hash);
|
||||
}
|
||||
|
||||
baseBatch.lightQueue_ = &(i->second_);
|
||||
}
|
||||
|
||||
if (pass->GetBlendMode() == BLEND_REPLACE)
|
||||
{
|
||||
FinalizeBatch(baseBatch, tech, pass);
|
||||
@ -795,7 +829,7 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
|
||||
Pass* pass = 0;
|
||||
|
||||
// Check for lit base pass. Because it uses the replace blend mode, it must be ensured to be the first light
|
||||
if (light == firstLight && !drawable->HasBasePass(i))
|
||||
if (light == firstLight && drawable->GetVertexLights().Empty() && !drawable->HasBasePass(i))
|
||||
{
|
||||
pass = tech->GetPass(PASS_LITBASE);
|
||||
if (pass)
|
||||
@ -991,7 +1025,7 @@ void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
|
||||
LightType type = light->GetLightType();
|
||||
|
||||
// Check if light should be shadowed
|
||||
bool isShadowed = drawShadows_ && light->GetCastShadows() && light->GetShadowIntensity() < 1.0f;
|
||||
bool isShadowed = drawShadows_ && light->GetCastShadows() && !light->GetPerVertex() && light->GetShadowIntensity() < 1.0f;
|
||||
// If shadow distance non-zero, check it
|
||||
if (isShadowed && light->GetShadowDistance() > 0.0f && light->GetDistance() > light->GetShadowDistance())
|
||||
isShadowed = false;
|
||||
@ -1644,6 +1678,14 @@ unsigned View::GetShadowMask(Drawable* drawable)
|
||||
return drawable->GetShadowMask() & GetZone(drawable)->GetShadowMask();
|
||||
}
|
||||
|
||||
unsigned View::GetVertexLightQueueHash(const PODVector<Light*>& vertexLights)
|
||||
{
|
||||
unsigned hash = 0;
|
||||
for (PODVector<Light*>::ConstIterator i = vertexLights.Begin(); i != vertexLights.End(); ++i)
|
||||
hash += (unsigned)(*i);
|
||||
return hash;
|
||||
}
|
||||
|
||||
Technique* View::GetTechnique(Drawable* drawable, Material*& material)
|
||||
{
|
||||
if (!material)
|
||||
|
@ -121,7 +121,7 @@ private:
|
||||
void GetBatches();
|
||||
/// Update geometries and sort batches.
|
||||
void UpdateGeometries();
|
||||
/// Get lit batches for a certain light and drawable.
|
||||
/// Get pixel lit batches for a certain light and drawable.
|
||||
void GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue);
|
||||
/// Render batches.
|
||||
void RenderBatches();
|
||||
@ -161,6 +161,8 @@ private:
|
||||
unsigned GetLightMask(Drawable* drawable);
|
||||
/// Return the drawable's shadow mask, considering also its zone.
|
||||
unsigned GetShadowMask(Drawable* drawable);
|
||||
/// Return hash code for a vertex light queue.
|
||||
unsigned GetVertexLightQueueHash(const PODVector<Light*>& vertexLights);
|
||||
/// Return material technique, considering the drawable's LOD distance.
|
||||
Technique* GetTechnique(Drawable* drawable, Material*& material);
|
||||
/// Check if material should render an auxiliary view (if it has a camera attached.)
|
||||
@ -256,8 +258,10 @@ private:
|
||||
BatchQueue postAlphaQueue_;
|
||||
/// Intermediate light processing results.
|
||||
Vector<LightQueryResult> lightQueryResults_;
|
||||
/// Light queues.
|
||||
/// Per-pixel light queues.
|
||||
List<LightBatchQueue> lightQueues_;
|
||||
/// Per-vertex light queues.
|
||||
HashMap<unsigned, LightBatchQueue> vertexLightQueues_;
|
||||
/// Current stencil value for light optimization.
|
||||
unsigned char lightStencilValue_;
|
||||
/// Camera zone's override flag.
|
||||
|
@ -3,16 +3,16 @@
|
||||
#include "Fog.frag"
|
||||
#include "Lighting.frag"
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
varying vec4 vTexCoord;
|
||||
#ifdef VERTEXCOLOR
|
||||
varying vec4 vColor;
|
||||
#endif
|
||||
varying vec2 vZonePosDepth;
|
||||
varying vec3 vVertexLighting;
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef DIFFMAP
|
||||
vec4 diffColor = cMatDiffColor * texture2D(sDiffMap, vTexCoord);
|
||||
vec4 diffColor = cMatDiffColor * texture2D(sDiffMap, vTexCoord.xy);
|
||||
#else
|
||||
vec4 diffColor = cMatDiffColor;
|
||||
#endif
|
||||
@ -21,5 +21,7 @@ void main()
|
||||
diffColor *= vColor;
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(GetFog(GetAmbient(vZonePosDepth.x) * diffColor.rgb, vZonePosDepth.y), diffColor.a);
|
||||
vec3 finalColor = (GetAmbient(vTexCoord.z) + vVertexLighting) * diffColor.rgb;
|
||||
|
||||
gl_FragColor = vec4(GetFog(finalColor, vTexCoord.w), diffColor.a);
|
||||
}
|
||||
|
@ -1,19 +1,26 @@
|
||||
#include "Uniforms.vert"
|
||||
#include "Transform.vert"
|
||||
#include "Lighting.vert"
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
varying vec4 vTexCoord;
|
||||
#ifdef VERTEXCOLOR
|
||||
varying vec4 vColor;
|
||||
#endif
|
||||
varying vec2 vZonePosDepth;
|
||||
varying vec3 vVertexLighting;
|
||||
|
||||
void main()
|
||||
{
|
||||
mat4 modelMatrix = iModelMatrix;
|
||||
vec3 worldPos = GetWorldPos(modelMatrix);
|
||||
gl_Position = GetClipPos(worldPos);
|
||||
vTexCoord = GetTexCoord(iTexCoord);
|
||||
vZonePosDepth = vec2(GetZonePos(worldPos), GetDepth(gl_Position));
|
||||
vTexCoord = vec4(GetTexCoord(iTexCoord), GetZonePos(worldPos), GetDepth(gl_Position));
|
||||
|
||||
vVertexLighting = vec3(0.0, 0.0, 0.0);
|
||||
#ifdef NUMVERTEXLIGHTS
|
||||
vec3 normal = GetWorldNormal(modelMatrix);
|
||||
for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
|
||||
vVertexLighting += GetVertexLight(i, worldPos, normal) * cVertexLights[i * 3].rgb;
|
||||
#endif
|
||||
|
||||
#ifdef VERTEXCOLOR
|
||||
vColor = iColor;
|
||||
|
@ -2,8 +2,14 @@
|
||||
<shader name="Ambient" type="vs">
|
||||
<option name="VCol" define="VERTEXCOLOR" />
|
||||
<variation name="" />
|
||||
<variation name="1VL" define="NUMVERTEXLIGHTS=1" />
|
||||
<variation name="2VL" define="NUMVERTEXLIGHTS=2" />
|
||||
<variation name="3VL" define="NUMVERTEXLIGHTS=3" />
|
||||
<variation name="4VL" define="NUMVERTEXLIGHTS=4" />
|
||||
<option name="" /> <!-- Dummy option to separate the two variation groups -->
|
||||
<variation name="" />
|
||||
<variation name="Skinned" define="SKINNED" />
|
||||
<variation name="Instanced" define="INSTANCED" />
|
||||
<variation name="Instanced" define="INSTANCED" require="SM3" />
|
||||
<variation name="Billboard" define="BILLBOARD" />
|
||||
</shader>
|
||||
<shader name="Ambient" type="ps">
|
||||
|
@ -29,7 +29,7 @@ float GetSpecular(vec3 normal, vec3 eyeVec, vec3 lightDir, float specularPower)
|
||||
|
||||
vec3 GetAmbient(float zonePos)
|
||||
{
|
||||
return mix(cAmbientStartColor, cAmbientEndColor, zonePos);
|
||||
return cAmbientStartColor + zonePos * cAmbientEndColor;
|
||||
}
|
||||
|
||||
float GetShadow(vec4 shadowPos)
|
||||
|
27
SourceAssets/GLSLShaders/Lighting.vert
Normal file
27
SourceAssets/GLSLShaders/Lighting.vert
Normal file
@ -0,0 +1,27 @@
|
||||
float GetVertexLight(int index, vec3 worldPos, vec3 normal)
|
||||
{
|
||||
vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
|
||||
vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
|
||||
float invRange = cVertexLights[index * 3].w;
|
||||
float cutoff = cVertexLights[index * 3 + 1].w;
|
||||
float invCutoff = cVertexLights[index * 3 + 2].w;
|
||||
|
||||
// Directional light
|
||||
if (invRange == 0.0)
|
||||
{
|
||||
float NdotL = max(dot(normal, lightDir), 0.0);
|
||||
return NdotL;
|
||||
}
|
||||
// Point/spot light
|
||||
else
|
||||
{
|
||||
vec3 lightVec = (lightPos - worldPos) * invRange;
|
||||
float lightDist = length(lightVec);
|
||||
vec3 localDir = lightVec / lightDist;
|
||||
float NdotL = max(dot(normal, localDir), 0.0);
|
||||
float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
|
||||
float spotEffect = dot(localDir, lightDir);
|
||||
float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
|
||||
return NdotL * atten * spotAtten;
|
||||
}
|
||||
}
|
@ -15,3 +15,4 @@ uniform vec3 cViewUpVector;
|
||||
uniform mat4 cZone;
|
||||
uniform mat4 cShadowProj[4];
|
||||
uniform vec4 cSkinMatrices[64*3];
|
||||
uniform vec4 cVertexLights[12];
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include "Fog.hlsl"
|
||||
|
||||
void VS(float4 iPos : POSITION,
|
||||
#ifdef NUMVERTEXLIGHTS
|
||||
float3 iNormal : NORMAL,
|
||||
#endif
|
||||
float2 iTexCoord : TEXCOORD0,
|
||||
#ifdef VERTEXCOLOR
|
||||
float4 iColor : COLOR0,
|
||||
@ -19,8 +22,8 @@ void VS(float4 iPos : POSITION,
|
||||
#ifdef BILLBOARD
|
||||
float2 iSize : TEXCOORD1,
|
||||
#endif
|
||||
out float2 oTexCoord : TEXCOORD0,
|
||||
out float2 oZonePosDepth : TEXCOORD1,
|
||||
out float4 oTexCoord : TEXCOORD0,
|
||||
out float3 oVertexLighting : TEXCOORD1,
|
||||
#ifdef VERTEXCOLOR
|
||||
out float4 oColor : COLOR0,
|
||||
#endif
|
||||
@ -29,23 +32,29 @@ void VS(float4 iPos : POSITION,
|
||||
float4x3 modelMatrix = iModelMatrix;
|
||||
float3 worldPos = GetWorldPos(modelMatrix);
|
||||
oPos = GetClipPos(worldPos);
|
||||
oTexCoord = GetTexCoord(iTexCoord);
|
||||
oZonePosDepth = float2(GetZonePos(worldPos), GetDepth(oPos));
|
||||
oTexCoord = float4(GetTexCoord(iTexCoord), GetZonePos(worldPos), GetDepth(oPos));
|
||||
|
||||
oVertexLighting = 0.0;
|
||||
#ifdef NUMVERTEXLIGHTS
|
||||
float3 normal = GetWorldNormal(modelMatrix);
|
||||
for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
|
||||
oVertexLighting += GetVertexLight(i, worldPos, normal) * cVertexLights[i * 3].rgb;
|
||||
#endif
|
||||
|
||||
#ifdef VERTEXCOLOR
|
||||
oColor = iColor;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PS(float2 iTexCoord : TEXCOORD0,
|
||||
float2 iZonePosDepth : TEXCOORD1,
|
||||
void PS(float4 iTexCoord : TEXCOORD0,
|
||||
float3 iVertexLighting : TEXCOORD1,
|
||||
#ifdef VERTEXCOLOR
|
||||
float4 iColor : COLOR0,
|
||||
#endif
|
||||
out float4 oColor : COLOR0)
|
||||
{
|
||||
#ifdef DIFFMAP
|
||||
float4 diffColor = cMatDiffColor * tex2D(sDiffMap, iTexCoord);
|
||||
float4 diffColor = cMatDiffColor * tex2D(sDiffMap, iTexCoord.xy);
|
||||
#else
|
||||
float4 diffColor = cMatDiffColor;
|
||||
#endif
|
||||
@ -54,5 +63,7 @@ void PS(float2 iTexCoord : TEXCOORD0,
|
||||
diffColor *= iColor;
|
||||
#endif
|
||||
|
||||
oColor = float4(GetFog(GetAmbient(iZonePosDepth.x) * diffColor.rgb, iZonePosDepth.y), diffColor.a);
|
||||
float3 finalColor = (GetAmbient(iTexCoord.z) + iVertexLighting) * diffColor.rgb;
|
||||
|
||||
oColor = float4(GetFog(finalColor, iTexCoord.w), diffColor.a);
|
||||
}
|
||||
|
@ -2,6 +2,12 @@
|
||||
<shader name="Ambient" type="vs">
|
||||
<option name="VCol" define="VERTEXCOLOR" />
|
||||
<variation name="" />
|
||||
<variation name="1VL" define="NUMVERTEXLIGHTS=1" />
|
||||
<variation name="2VL" define="NUMVERTEXLIGHTS=2" />
|
||||
<variation name="3VL" define="NUMVERTEXLIGHTS=3" />
|
||||
<variation name="4VL" define="NUMVERTEXLIGHTS=4" />
|
||||
<option name="" /> <!-- Dummy option to separate the two variation groups -->
|
||||
<variation name="" />
|
||||
<variation name="Skinned" define="SKINNED" />
|
||||
<variation name="Instanced" define="INSTANCED" require="SM3" />
|
||||
<variation name="Billboard" define="BILLBOARD" />
|
||||
|
@ -146,11 +146,9 @@ void PS(float4 iTexCoord : TEXCOORD0,
|
||||
float4 diffColor = cMatDiffColor;
|
||||
#endif
|
||||
|
||||
/*
|
||||
#ifdef VERTEXCOLOR
|
||||
diffColor *= iColor;
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifdef NORMALMAP
|
||||
float3 normal = DecodeNormal(tex2D(sNormalMap, iTexCoord.xy));
|
||||
|
@ -29,9 +29,37 @@ float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularP
|
||||
return pow(dot(normal, halfVec), specularPower);
|
||||
}
|
||||
|
||||
float GetVertexLight(int index, float3 worldPos, float3 normal)
|
||||
{
|
||||
float3 lightDir = cVertexLights[index * 3 + 1].xyz;
|
||||
float3 lightPos = cVertexLights[index * 3 + 2].xyz;
|
||||
float invRange = cVertexLights[index * 3].w;
|
||||
float cutoff = cVertexLights[index * 3 + 1].w;
|
||||
float invCutoff = cVertexLights[index * 3 + 2].w;
|
||||
|
||||
// Directional light
|
||||
if (invRange == 0.0)
|
||||
{
|
||||
float NdotL = max(dot(normal, lightDir), 0.0);
|
||||
return NdotL;
|
||||
}
|
||||
// Point/spot light
|
||||
else
|
||||
{
|
||||
float3 lightVec = (lightPos - worldPos) * invRange;
|
||||
float lightDist = length(lightVec);
|
||||
float3 localDir = lightVec / lightDist;
|
||||
float NdotL = max(dot(normal, localDir), 0.0);
|
||||
float atten = saturate(1.0 - lightDist * lightDist);
|
||||
float spotEffect = dot(localDir, lightDir);
|
||||
float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
|
||||
return NdotL * atten * spotAtten;
|
||||
}
|
||||
}
|
||||
|
||||
float3 GetAmbient(float zonePos)
|
||||
{
|
||||
return lerp(cAmbientStartColor, cAmbientEndColor, zonePos);
|
||||
return cAmbientStartColor + zonePos * cAmbientEndColor;
|
||||
}
|
||||
|
||||
float GetShadow(float4 shadowPos)
|
||||
|
@ -16,6 +16,7 @@ uniform float3 cViewUpVector : register(C25);
|
||||
uniform float4x3 cZone : register(C26);
|
||||
uniform float4x4 cShadowProj[4] : register(C29);
|
||||
uniform float4x3 cSkinMatrices[64] : register(C45);
|
||||
uniform float4 cVertexLights[12] : register(C237);
|
||||
|
||||
// Pixel shader parameters
|
||||
uniform float3 cAmbientStartColor : register(C0);
|
||||
|
@ -103,6 +103,7 @@ struct Variation
|
||||
|
||||
String name_;
|
||||
Vector<String> defines_;
|
||||
Vector<String> defineValues_;
|
||||
Vector<String> excludes_;
|
||||
Vector<String> includes_;
|
||||
Vector<String> requires_;
|
||||
@ -114,6 +115,7 @@ struct CompiledVariation
|
||||
ShaderType type_;
|
||||
String name_;
|
||||
Vector<String> defines_;
|
||||
Vector<String> defineValues_;
|
||||
PODVector<unsigned char> byteCode_;
|
||||
unsigned byteCodeOffset_;
|
||||
Set<Parameter> constants_;
|
||||
@ -141,6 +143,7 @@ String inDir_;
|
||||
String inFile_;
|
||||
String outDir_;
|
||||
Vector<String> defines_;
|
||||
Vector<String> defineValues_;
|
||||
bool useSM3_ = false;
|
||||
volatile bool compileFailed_ = false;
|
||||
|
||||
@ -171,10 +174,6 @@ public:
|
||||
{
|
||||
workItem = workList_.Front();
|
||||
workList_.Erase(workList_.Begin());
|
||||
if (!workItem->name_.Empty())
|
||||
PrintLine("Compiling shader variation " + workItem->name_);
|
||||
else
|
||||
PrintLine("Compiling base shader variation");
|
||||
}
|
||||
}
|
||||
if (!workItem)
|
||||
@ -263,7 +262,17 @@ void Run(const Vector<String>& arguments)
|
||||
else if (arg == "SM2")
|
||||
useSM3_ = false;
|
||||
|
||||
defines_.Push(arg);
|
||||
Vector<String> nameAndValue = arg.Split('=');
|
||||
if (nameAndValue.Size() == 2)
|
||||
{
|
||||
defines_.Push(nameAndValue[0]);
|
||||
defineValues_.Push(nameAndValue[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
defines_.Push(arg);
|
||||
defineValues_.Push("1");
|
||||
}
|
||||
}
|
||||
|
||||
XMLFile doc(context_);
|
||||
@ -304,8 +313,20 @@ void Run(const Vector<String>& arguments)
|
||||
|
||||
String simpleDefine = variation.GetString("define");
|
||||
if (!simpleDefine.Empty())
|
||||
newVar.defines_.Push(simpleDefine);
|
||||
|
||||
{
|
||||
Vector<String> nameAndValue = simpleDefine.Split('=');
|
||||
if (nameAndValue.Size() == 2)
|
||||
{
|
||||
newVar.defines_.Push(nameAndValue[0]);
|
||||
newVar.defineValues_.Push(nameAndValue[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
newVar.defines_.Push(simpleDefine);
|
||||
newVar.defineValues_.Push("1");
|
||||
}
|
||||
}
|
||||
|
||||
String simpleExclude = variation.GetString("exclude");
|
||||
if (!simpleExclude.Empty())
|
||||
newVar.excludes_.Push(simpleExclude);
|
||||
@ -321,7 +342,18 @@ void Run(const Vector<String>& arguments)
|
||||
XMLElement define = variation.GetChild("define");
|
||||
while (define)
|
||||
{
|
||||
newVar.defines_.Push(define.GetString("name"));
|
||||
String defineName = define.GetString("name");
|
||||
Vector<String> nameAndValue = defineName.Split('=');
|
||||
if (nameAndValue.Size() == 2)
|
||||
{
|
||||
newVar.defines_.Push(nameAndValue[0]);
|
||||
newVar.defineValues_.Push(nameAndValue[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
newVar.defines_.Push(defineName);
|
||||
newVar.defineValues_.Push("1");
|
||||
}
|
||||
define = define.GetNext("define");
|
||||
}
|
||||
|
||||
@ -499,9 +531,10 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
|
||||
if (usedCombinations.Contains(active))
|
||||
continue;
|
||||
|
||||
// Build shader variation name & defines active variations
|
||||
// Build shader variation name & defines for active variations
|
||||
String outName;
|
||||
Vector<String> defines;
|
||||
Vector<String> defineValues;
|
||||
for (unsigned j = 0; j < variations.Size(); ++j)
|
||||
{
|
||||
if (active & (1 << j))
|
||||
@ -509,7 +542,10 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
|
||||
if (variations[j].name_.Length())
|
||||
outName += variations[j].name_;
|
||||
for (unsigned k = 0; k < variations[j].defines_.Size(); ++k)
|
||||
{
|
||||
defines.Push(variations[j].defines_[k]);
|
||||
defineValues.Push(variations[j].defineValues_[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,6 +553,7 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
|
||||
compile.type_ = baseShader.type_;
|
||||
compile.name_ = outName;
|
||||
compile.defines_ = defines;
|
||||
compile.defineValues_ = defineValues;
|
||||
|
||||
compiledVariations.Push(compile);
|
||||
usedCombinations.Insert(active);
|
||||
@ -609,14 +646,14 @@ void Compile(CompiledVariation* variation)
|
||||
{
|
||||
D3DXMACRO macro;
|
||||
macro.Name = variation->defines_[i].CString();
|
||||
macro.Definition = "1";
|
||||
macro.Definition = variation->defineValues_[i].CString();
|
||||
macros.Push(macro);
|
||||
}
|
||||
for (unsigned i = 0; i < defines_.Size(); ++i)
|
||||
{
|
||||
D3DXMACRO macro;
|
||||
macro.Name = defines_[i].CString();
|
||||
macro.Definition = "1";
|
||||
macro.Definition = defineValues_[i].CString();
|
||||
macros.Push(macro);
|
||||
}
|
||||
|
||||
@ -664,15 +701,20 @@ void Compile(CompiledVariation* variation)
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyStrippedCode(variation->byteCode_, shaderCode->GetBufferPointer(), shaderCode->GetBufferSize());
|
||||
|
||||
if (!variation->name_.Empty())
|
||||
PrintLine("Compiled shader variation " + variation->name_ + ", code size " + String(variation->byteCode_.Size()));
|
||||
else
|
||||
PrintLine("Compiled base shader variation, code size " + String(variation->byteCode_.Size()));
|
||||
|
||||
// Print warnings if any
|
||||
if (errorMsgs && errorMsgs->GetBufferSize())
|
||||
{
|
||||
String warning((const char*)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize());
|
||||
printf("WARNING: %s\n", warning.CString());
|
||||
PrintLine("WARNING: " + warning);
|
||||
}
|
||||
|
||||
CopyStrippedCode(variation->byteCode_, shaderCode->GetBufferPointer(), shaderCode->GetBufferSize());
|
||||
|
||||
// Parse the constant table for constants and texture units
|
||||
D3DXCONSTANTTABLE_DESC desc;
|
||||
constantTable->GetDesc(&desc);
|
||||
|
Loading…
Reference in New Issue
Block a user