File indexing completed on 2024-05-26 04:33:10
0001 /* 0002 * SPDX-FileCopyrightText: 2010-2012 José Luis Vergara <pentalis@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "phong_pixel_processor.h" 0008 #include <cmath> 0009 #include <iostream> 0010 #include <KoChannelInfo.h> 0011 0012 PhongPixelProcessor::PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfigurationSP config) 0013 { 0014 m_pixelArea = pixelArea; 0015 initialize(config); 0016 } 0017 0018 void PhongPixelProcessor::initialize(const KisPropertiesConfigurationSP config) 0019 { 0020 // Basic, fundamental 0021 normal_vector = QVector3D(0, 0, 1); 0022 vision_vector = QVector3D(0, 0, 1); 0023 x_vector = QVector3D(1, 0, 0); 0024 y_vector = QVector3D(0, 1, 0); 0025 0026 // Mutable 0027 light_vector = QVector3D(0, 0, 0); 0028 reflection_vector = QVector3D(0, 0, 0); 0029 0030 //setLightVector(QVector3D(-8, 8, 2)); 0031 0032 Illuminant light[PHONG_TOTAL_ILLUMINANTS]; 0033 QVariant guiLight[PHONG_TOTAL_ILLUMINANTS]; 0034 0035 qint32 azimuth; 0036 qint32 inclination; 0037 0038 for (int i = 0; i < PHONG_TOTAL_ILLUMINANTS; i++) { 0039 if (config->getBool(PHONG_ILLUMINANT_IS_ENABLED[i])) { 0040 if (config->getProperty(PHONG_ILLUMINANT_COLOR[i], guiLight[i])) { 0041 light[i].RGBvalue << guiLight[i].value<QColor>().redF(); 0042 light[i].RGBvalue << guiLight[i].value<QColor>().greenF(); 0043 light[i].RGBvalue << guiLight[i].value<QColor>().blueF(); 0044 0045 azimuth = config->getInt(PHONG_ILLUMINANT_AZIMUTH[i]) - 90; 0046 inclination = config->getInt(PHONG_ILLUMINANT_INCLINATION[i]); 0047 0048 qreal m; //2D vector magnitude 0049 light[i].lightVector.setZ( sin( inclination * M_PI / 180 ) ); 0050 m = cos( inclination * M_PI / 180); 0051 0052 light[i].lightVector.setX( cos( azimuth * M_PI / 180 ) * m ); 0053 light[i].lightVector.setY( sin( azimuth * M_PI / 180 ) * m ); 0054 //Pay close attention to this, indexes will move in this line 0055 lightSources.append(light[i]); 0056 } 0057 } 0058 } 0059 0060 size = lightSources.size(); 0061 0062 //Code that exists only to swiftly switch to the other algorithm (reallyFastIlluminatePixel) to test 0063 if (size > 0) { 0064 fastLight = light[0]; 0065 fastLight2 = light[0]; 0066 } 0067 0068 //Ka, Kd and Ks must be between 0 and 1 or grave errors will happen 0069 Ka = config->getDouble(PHONG_AMBIENT_REFLECTIVITY); 0070 Kd = config->getDouble(PHONG_DIFFUSE_REFLECTIVITY); 0071 Ks = config->getDouble(PHONG_SPECULAR_REFLECTIVITY); 0072 shiny_exp = config->getInt(PHONG_SHINYNESS_EXPONENT); 0073 0074 Ia = Id = Is = 0; 0075 0076 diffuseLightIsEnabled = config->getBool(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED); 0077 specularLightIsEnabled = config->getBool(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED); 0078 0079 realheightmap = QVector<double>(m_pixelArea, 0); 0080 } 0081 0082 0083 PhongPixelProcessor::~PhongPixelProcessor() 0084 { 0085 0086 } 0087 0088 0089 void PhongPixelProcessor::setLightVector(QVector3D lightVector) 0090 { 0091 lightVector.normalize(); 0092 light_vector = lightVector; 0093 } 0094 0095 QVector<quint16> PhongPixelProcessor::IlluminatePixelFromHeightmap(quint32 posup, quint32 posdown, quint32 posleft, quint32 posright) 0096 { 0097 QVector<quint16> finalPixel(4, 0xFFFF); 0098 0099 if (lightSources.size() == 0) 0100 return finalPixel; 0101 0102 // Algorithm begins, Phong Illumination Model 0103 normal_vector.setX(- realheightmap[posright] + realheightmap[posleft]); 0104 normal_vector.setY(- realheightmap[posup] + realheightmap[posdown]); 0105 normal_vector.setZ(8); 0106 normal_vector.normalize(); 0107 0108 // PREPARE ALGORITHM HERE 0109 0110 finalPixel = IlluminatePixel(); 0111 0112 return finalPixel; 0113 } 0114 0115 QVector<quint16> PhongPixelProcessor::IlluminatePixel() 0116 { 0117 qreal temp; 0118 quint8 channel = 0; 0119 const quint8 totalChannels = 3; // The 4th is alpha and we'll fill it with a nice 0xFFFF 0120 qreal computation[] = {0, 0, 0}; 0121 QVector<quint16> finalPixel(4, 0xFFFF); 0122 0123 if (lightSources.size() == 0) 0124 return finalPixel; 0125 0126 // PREPARE ALGORITHM HERE 0127 0128 for (int i = 0; i < size; i++) { 0129 light_vector = lightSources.at(i).lightVector; 0130 0131 for (channel = 0; channel < totalChannels; channel++) { 0132 Ia = lightSources.at(i).RGBvalue.at(channel) * Ka; 0133 computation[channel] += Ia; 0134 } 0135 if (diffuseLightIsEnabled) { 0136 temp = Kd * QVector3D::dotProduct(normal_vector, light_vector); 0137 for (channel = 0; channel < totalChannels; channel++) { 0138 Id = lightSources.at(i).RGBvalue.at(channel) * temp; 0139 if (Id < 0) Id = 0; 0140 if (Id > 1) Id = 1; 0141 computation[channel] += Id; 0142 } 0143 } 0144 0145 if (specularLightIsEnabled) { 0146 reflection_vector = (2 * pow(QVector3D::dotProduct(normal_vector, light_vector), shiny_exp)) * normal_vector - light_vector; 0147 temp = Ks * QVector3D::dotProduct(vision_vector, reflection_vector); 0148 for (channel = 0; channel < totalChannels; channel++) { 0149 Is = lightSources.at(i).RGBvalue.at(channel) * temp; 0150 if (Is < 0) Is = 0; 0151 if (Is > 1) Is = 1; 0152 computation[channel] += Is; 0153 } 0154 } 0155 } 0156 0157 for (channel = 0; channel < totalChannels; channel++) { 0158 if (computation[channel] > 1) 0159 computation[channel] = 1; 0160 if (computation[channel] < 0) 0161 computation[channel] = 0; 0162 } 0163 0164 //RGBA actually uses the BGRA order of channels, hence the disorder 0165 finalPixel[2] = quint16(computation[0] * 0xFFFF); 0166 finalPixel[1] = quint16(computation[1] * 0xFFFF); 0167 finalPixel[0] = quint16(computation[2] * 0xFFFF); 0168 0169 return finalPixel; 0170 } 0171 0172 QVector<quint16> PhongPixelProcessor::IlluminatePixelFromNormalmap(qreal r, qreal g, qreal b) 0173 { 0174 QVector<quint16> finalPixel(4, 0xFFFF); 0175 0176 if (lightSources.size() == 0) 0177 return finalPixel; 0178 0179 // if () 0180 // Algorithm begins, Phong Illumination Model 0181 normal_vector.setX(r*2-1.0); 0182 normal_vector.setY(-(g*2-1.0)); 0183 normal_vector.setZ(b*2-1.0); 0184 //normal_vector.normalize(); 0185 0186 // PREPARE ALGORITHM HERE 0187 0188 finalPixel = IlluminatePixel(); 0189 0190 return finalPixel; 0191 }