void Shader::SetUniform(const string& name, const PointLight& value) { SetUniform(name + ".base", (Light)value); SetUniform(name + ".attenuation", value.GetAttenuation()); SetUniform(name + ".position", value.GetPosition()); }
// Fills a polygon using a texture, gouraud shading and a normal map given 3 points and a color. void Rasterizer::FillPolygonTexturedNormalMapped(Vertex v1, Vertex v2, Vertex v3, Gdiplus::Color color, Model3D& model, std::vector<DirectionalLight*> directionalLights, std::vector<AmbientLight*> ambientLights, std::vector<PointLight*> pointLights) { ScanLine* _scanlines = new ScanLine[_height]; BYTE* texture; Gdiplus::Color* palette; BYTE* normalTexture; Gdiplus::Color* normalPalette; int textureWidth; // Get the texture properties of the model. model.GetTexture(&texture, &palette, &textureWidth); model.GetNormalMapTexture(&normalTexture, &normalPalette, &textureWidth); // Set the scanlines to very high and very low values so // they will be set on the first set of interpolation. for (unsigned int i = 0; i < _height; i++) { _scanlines[i].xStart = 99999; _scanlines[i].xEnd = -99999; } // Interpolates between each of the vertexs of the polygon and sets the start // and end values for each of the scanlines it comes in contact with. InterpolateScanline(_scanlines, v1, v2); InterpolateScanline(_scanlines, v2, v3); InterpolateScanline(_scanlines, v3, v1); // Go through each scanline and each pixel in the scanline and // sets its color. for (unsigned int y = 0; y < _height; y++) { // Work out the color and UV differences between the start and end of the scanline. float redColorDiff = (_scanlines[y].redEnd - _scanlines[y].redStart); float greenColorDiff = (_scanlines[y].greenEnd - _scanlines[y].greenStart); float blueColorDiff = (_scanlines[y].blueEnd - _scanlines[y].blueStart); float uCoordDiff = _scanlines[y].uEnd - _scanlines[y].uStart; float vCoordDiff = _scanlines[y].vEnd - _scanlines[y].vStart; float zCoordDiff = _scanlines[y].zEnd - _scanlines[y].zStart; float xNormalDiff = (_scanlines[y].xNormalEnd - _scanlines[y].xNormalStart); float yNormalDiff = (_scanlines[y].yNormalEnd - _scanlines[y].yNormalStart); float zNormalDiff = (_scanlines[y].zNormalEnd - _scanlines[y].zNormalStart); float xDiff = (_scanlines[y].pixelXEnd - _scanlines[y].pixelXStart); float yDiff = (_scanlines[y].pixelYEnd - _scanlines[y].pixelYStart); float zDiff = (_scanlines[y].pixelZEnd - _scanlines[y].pixelZStart); float diff = (_scanlines[y].xEnd - _scanlines[y].xStart) + 1; for (int x = (int)_scanlines[y].xStart; x <= (int)_scanlines[y].xEnd; x++) { if (x < 0 || x >= (int)_width) continue; int offset = (int)(x - _scanlines[y].xStart); // Work out the UV coordinate of the current pixel. float uCoord = _scanlines[y].uStart + ((uCoordDiff / diff) * offset); float vCoord = _scanlines[y].vStart + ((vCoordDiff / diff) * offset); float zCoord = _scanlines[y].zStart + ((zCoordDiff / diff) * offset); uCoord /= zCoord; vCoord /= zCoord; // Work out the normal of the pixel. float xNormal = _scanlines[y].xNormalStart + ((xNormalDiff / diff) * offset); float yNormal = _scanlines[y].yNormalStart + ((yNormalDiff / diff) * offset); float zNormal = _scanlines[y].zNormalStart + ((zNormalDiff / diff) * offset); // Work out the position of the pixel. float pixelX = _scanlines[y].pixelXStart + ((xDiff / diff) * offset); float pixelY = _scanlines[y].pixelYStart + ((yDiff / diff) * offset); float pixelZ = _scanlines[y].pixelZStart + ((zDiff / diff) * offset); // Work out the lighting colour of the current pixel. //float lightR = (_scanlines[y].redStart + ((redColorDiff / diff) * offset)) / 180.0f; //float lightG = (_scanlines[y].greenStart + ((greenColorDiff / diff) * offset)) / 180.0f; //float lightB = (_scanlines[y].blueStart + ((blueColorDiff / diff) * offset)) / 180.0f; // Using the UV coordinate work out which pixel in the texture to use to draw this pixel. int pixelIndex = (int)vCoord * textureWidth + (int)uCoord; if (pixelIndex >= textureWidth * textureWidth || pixelIndex < 0) { pixelIndex = (textureWidth * textureWidth) - 1; } int paletteOffset = texture[pixelIndex]; if (paletteOffset >= 255) paletteOffset = 255; Gdiplus::Color textureColor = palette[paletteOffset]; // Work out the pixel colour of the normalmap. pixelIndex = (int)vCoord * textureWidth + (int)uCoord; if (pixelIndex >= textureWidth * textureWidth || pixelIndex < 0) { pixelIndex = (textureWidth * textureWidth) - 1; } paletteOffset = normalTexture[pixelIndex]; if (paletteOffset >= 255) paletteOffset = 255; Gdiplus::Color normalTextureColor = normalPalette[paletteOffset]; // Calculate normal lighting for the pixel. Vector3D heightMapVector = Vector3D(normalTextureColor.GetR() / 180.0f, normalTextureColor.GetG() / 180.0f, normalTextureColor.GetB() / 180.0f); heightMapVector = Vector3D((heightMapVector.GetX() - 0.5f) * 2.0f, (heightMapVector.GetY() - 0.5f) * 2.0f, (heightMapVector.GetZ() - 0.5f) * 2.0f); // Work out he pixels normal and position. Vector3D pixelNormal = Vector3D(xNormal, yNormal, zNormal);//;Vector3D(heightMapVector.GetX(), heightMapVector.GetY(), heightMapVector.GetZ()); Vertex pixelPosition = Vertex(pixelX, pixelY, pixelZ, 1, Gdiplus::Color::White, Vector3D(0, 0, 0), 0); heightMapVector = Vector3D((pixelNormal.GetX() * heightMapVector.GetX()) , (pixelNormal.GetY() * heightMapVector.GetY()) , (pixelNormal.GetZ() * heightMapVector.GetZ()) ); // Calculate the sum dot product of all lighting vectors for this pixel and divide by the number // of lights. float lightDot = 0.0f; int count = 0; for (unsigned int j = 0; j < pointLights.size(); j++) { PointLight* light = pointLights[j]; if (light->GetEnabled() == false) continue; // Work out vector to light source. Vector3D lightVector = Vertex::GetVector(pixelPosition, light->GetPosition()); float distance = lightVector.GetLength(); lightVector.Normalize(); // Work out dot product. lightDot += Vector3D::DotProduct(heightMapVector, lightVector); count++; } for (unsigned int j = 0; j < directionalLights.size(); j++) { DirectionalLight* light = directionalLights[j]; if (light->GetEnabled() == false) continue; // Work out vector to light source. Vector3D lightVector = Vertex::GetVector(pixelPosition, light->GetPosition()); float distance = lightVector.GetLength(); lightVector.Normalize(); // Work out dot product. lightDot += Vector3D::DotProduct(heightMapVector, lightVector); count++; } lightDot /= count; // Adjust texture colour based on the lighting dot product. Gdiplus::Color pixelColor = textureColor; //pixelColor = model.CalculateLightingAmbientPerPixel(ambientLights, pixelPosition, pixelNormal, pixelColor); //pixelColor = model.CalculateLightingDirectionalPerPixel(directionalLights, pixelPosition, pixelNormal, pixelColor); //pixelColor = model.CalculateLightingPointPerPixel(pointLights, pixelPosition, pixelNormal, pixelColor); float lightR = (_scanlines[y].redStart + ((redColorDiff / diff) * offset)) / 180.0f; float lightG = (_scanlines[y].greenStart + ((greenColorDiff / diff) * offset)) / 180.0f; float lightB = (_scanlines[y].blueStart + ((blueColorDiff / diff) * offset)) / 180.0f; // Apply the lighting value to the texture colour and use the result to set the colour of the current pixel. int finalR = (int)max(0, min(255, (lightR * textureColor.GetR()) - ((lightR * textureColor.GetR()) * lightDot) )); int finalG = (int)max(0, min(255, (lightG * textureColor.GetG()) - ((lightG * textureColor.GetG()) * lightDot) )); int finalB = (int)max(0, min(255, (lightB * textureColor.GetB()) - ((lightB * textureColor.GetB()) * lightDot) )); WritePixel(x, y, Gdiplus::Color(finalR, finalG, finalB)); } } // Dispose of dynamic objects. delete[] _scanlines; _polygonsRendered++; }
// =================== // Point lights // =================== void World::DoLightingPass(const PointLight& l) { gbuffer.StartLightingPass(); // Disable depth test. glDisable(GL_DEPTH_TEST); // Setup for lighting pass. glStencilFunc(GL_NOTEQUAL, 0, 0xFF); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); // Bind pass 2 shader. Shader* lpassShader = &pointLightShader; Shader::Bind(lpassShader); // Activate gbuffer textures. glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gbuffer.GetColorID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, gbuffer.GetNormalID()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, gbuffer.GetPositionID()); // Matrices Matrix pmat = cam.GetProjectionMatrix(); Matrix vmat = cam.GetViewMatrix(); lpassShader->SetParameter("projectionMatrix", &pmat[0][0]); lpassShader->SetParameter("viewMatrix", &vmat[0][0]); lpassShader->SetParameter("screenSize", WINDOW_WIDTH, WINDOW_HEIGHT); // Set the eye position to the camera position. Vector3 cpos = cam.GetPosition(); lpassShader->SetParameter("eyePosition", cpos.x, cpos.y, cpos.z); lpassShader->SetParameter("farClipDistance", cam.GetFarClippingPlane()); // Texture locations lpassShader->SetParameter("difftex", 0); lpassShader->SetParameter("normtex", 1); lpassShader->SetParameter("postex", 2); // Draw point lights. Matrix lmat = l.GetMatrix(); lpassShader->SetParameter("modelMatrix", &lmat[0][0]); const Vector3& pos = l.GetPosition(); lpassShader->SetParameter("lightPos", pos.x, pos.y, pos.z); // Itensity. lpassShader->SetParameter("ambientIntensity", l.GetAmbientIntensity()); lpassShader->SetParameter("diffuseIntensity", l.GetDiffuseIntensity()); // Attenuation. lpassShader->SetParameter("attenuationConstant", l.GetAttenuationConstant()); lpassShader->SetParameter("attenuationLinear", l.GetAttenuationLinear()); lpassShader->SetParameter("attenuationExponential", l.GetAttenuationExponential()); Color diffuseColor = l.GetColor(); lpassShader->SetParameter("lightColor", diffuseColor.R(), diffuseColor.G(), diffuseColor.B()); pointLightMesh.Draw(); glCullFace(GL_BACK); glDisable(GL_BLEND); }