├── .classpath ├── .gitignore ├── .project ├── LICENSE ├── README.md ├── data ├── README ├── shaders │ └── pbr │ │ ├── pbr.vert │ │ └── simplepbr.frag └── textures │ ├── flatNoraml1x1.png │ ├── integrateBrdf.png │ └── white1x1.png ├── examples ├── HelloPBR │ └── HelloPBR.pde ├── Lights │ └── Lights.pde ├── Materials │ └── Materials.pde └── data │ ├── models │ ├── platonic.mtl │ └── platonic.obj │ └── textures │ ├── cubemap │ ├── Zion_Sunsetpeek │ │ ├── PREM │ │ │ ├── output_pmrem_negx_0.tga │ │ │ ├── output_pmrem_negx_1.tga │ │ │ ├── output_pmrem_negx_2.tga │ │ │ ├── output_pmrem_negx_3.tga │ │ │ ├── output_pmrem_negx_4.tga │ │ │ ├── output_pmrem_negx_5.tga │ │ │ ├── output_pmrem_negx_6.tga │ │ │ ├── output_pmrem_negy_0.tga │ │ │ ├── output_pmrem_negy_1.tga │ │ │ ├── output_pmrem_negy_2.tga │ │ │ ├── output_pmrem_negy_3.tga │ │ │ ├── output_pmrem_negy_4.tga │ │ │ ├── output_pmrem_negy_5.tga │ │ │ ├── output_pmrem_negy_6.tga │ │ │ ├── output_pmrem_negz_0.tga │ │ │ ├── output_pmrem_negz_1.tga │ │ │ ├── output_pmrem_negz_2.tga │ │ │ ├── output_pmrem_negz_3.tga │ │ │ ├── output_pmrem_negz_4.tga │ │ │ ├── output_pmrem_negz_5.tga │ │ │ ├── output_pmrem_negz_6.tga │ │ │ ├── output_pmrem_posx_0.tga │ │ │ ├── output_pmrem_posx_1.tga │ │ │ ├── output_pmrem_posx_2.tga │ │ │ ├── output_pmrem_posx_3.tga │ │ │ ├── output_pmrem_posx_4.tga │ │ │ ├── output_pmrem_posx_5.tga │ │ │ ├── output_pmrem_posx_6.tga │ │ │ ├── output_pmrem_posy_0.tga │ │ │ ├── output_pmrem_posy_1.tga │ │ │ ├── output_pmrem_posy_2.tga │ │ │ ├── output_pmrem_posy_3.tga │ │ │ ├── output_pmrem_posy_4.tga │ │ │ ├── output_pmrem_posy_5.tga │ │ │ ├── output_pmrem_posy_6.tga │ │ │ ├── output_pmrem_posz_0.tga │ │ │ ├── output_pmrem_posz_1.tga │ │ │ ├── output_pmrem_posz_2.tga │ │ │ ├── output_pmrem_posz_3.tga │ │ │ ├── output_pmrem_posz_4.tga │ │ │ ├── output_pmrem_posz_5.tga │ │ │ └── output_pmrem_posz_6.tga │ │ ├── Zion_Sunsetpeek.ibl │ │ ├── irradiance │ │ │ ├── output_iem.dds │ │ │ ├── output_iem_negx.tga │ │ │ ├── output_iem_negy.tga │ │ │ ├── output_iem_negz.tga │ │ │ ├── output_iem_posx.tga │ │ │ ├── output_iem_posy.tga │ │ │ └── output_iem_posz.tga │ │ └── sh.txt │ └── Zion_Sunsetpeek_LatLong │ │ ├── PREM │ │ ├── output_pmrem_0.tga │ │ ├── output_pmrem_1.tga │ │ ├── output_pmrem_2.tga │ │ ├── output_pmrem_3.tga │ │ ├── output_pmrem_4.tga │ │ ├── output_pmrem_5.tga │ │ └── output_pmrem_6.tga │ │ ├── Zion_Sunsetpeek.ibl │ │ └── sh.txt │ └── material │ ├── Leather_008_SD │ ├── albedo.png │ ├── metalness.png │ ├── normal.png │ └── roughness.png │ ├── Metal10 │ ├── albedo.png │ ├── metalness.png │ ├── normal.png │ └── roughness.png │ └── Metal_Rusted_006 │ ├── albedo.png │ ├── metalness.png │ ├── normal.png │ └── roughness.png ├── linkToVimeo.png ├── resources ├── README.md ├── build.properties ├── build.xml ├── code │ ├── ExampleTaglet.class │ ├── ExampleTaglet.java │ ├── ant-contrib-1.0b3.jar │ └── doc.sh ├── library.properties └── stylesheet.css ├── screenshot.gif ├── src └── estudiolumen │ └── simplepbr │ ├── PBRMat.java │ └── SimplePBR.java └── web ├── index.html └── stylesheet.css /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | tmp 3 | distribution 4 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | processing-library-template 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 nacho cossio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimplePBR 2 | 3 | A Processing library for physically based rendering and materials. Created by [Nacho Cossio](http://nachocossio.com) based on [a shader by Nick Galko](https://gist.github.com/galek/53557375251e1a942dfa) 4 | 5 | [![video](linkToVimeo.png)](https://vimeo.com/315540699) 6 | 7 | ### Installing 8 | Download the latest [release from here](https://github.com/kosowski/SimplePBR/releases/latest/) and unzip the 'SimplePBR' folder into your Processing 'libraries' folder. Done, you can now run any of the provided examples. 9 | 10 | ### About 11 | Physically Based Rendering (PBR) is a method of shading and rendering that provides a more accurate representation of how light interacts with surfaces. A nice introduction on what PBR is and the different lighting terms involved can be found in these article series by the jMonkey Engine team: 12 | https://wiki.jmonkeyengine.org/jme3/advanced/pbr_part1.html 13 | 14 | Two kinds of assets are required for PBR: 15 | - Cubemap, and in this case, several prefiltered versions of it, for the indirect lighting. One set is provided with the library, taken from the [sIBL archive](http://www.hdrlabs.com/sibl/archive.html), under Creative Commons Attribution-Noncommercial-Share Alike 3.0 License. The radiance and irradiance maps were created with [Cmft Studio](https://github.com/dariomanesku/cmftStudio), which is easy to use and very fast. 16 | 17 | - Materials: sets of textures defining the characteristics of a certain substance. SimplePBR uses individual textures for easy of use, although is a better practice to group several of these textures into the RGBA channels of one texture. There are various sites providing free materials, there are three materials included with the examples taken from [3dtextures](https://3dtextures.me/) and [CC0textures](https://cc0textures.com/) There is also a "textureless" material using just numerical constant values. 18 | 19 | ### License 20 | 21 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details 22 | 23 | ### Donate 24 | 25 | If you use this library for commercial work, please consider donating 26 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WK7VJCXZHUD3W) 27 | -------------------------------------------------------------------------------- /data/README: -------------------------------------------------------------------------------- 1 | the data folder: 2 | If your Library is using files like images, sound files, 3 | any data file, etc., put them into the data folder. 4 | When coding your Library you can use processing's internal loading 5 | functions like loadImage(), loadStrings(), etc. to load files 6 | located inside the data folder into your Library. 7 | 8 | -------------------------------------------------------------------------------- /data/shaders/pbr/pbr.vert: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | uniform mat4 transformMatrix; 4 | uniform mat4 modelviewMatrix; 5 | uniform mat3 normalMatrix; 6 | uniform mat4 texMatrix; 7 | uniform vec4 lightPosition[8]; 8 | uniform vec3 lightDiffuse[8]; 9 | uniform float time; 10 | 11 | in vec4 position; 12 | in vec4 color; 13 | in vec3 normal; 14 | in vec2 texCoord; 15 | 16 | 17 | out FragData { 18 | vec4 color; 19 | vec3 ecVertex; 20 | vec3 normal; 21 | vec2 texCoord; 22 | } FragOut; 23 | 24 | 25 | 26 | void main() { 27 | 28 | gl_Position = transformMatrix * position; 29 | vec3 ecp = vec3(modelviewMatrix * position); 30 | FragOut.ecVertex = ecp; 31 | FragOut.normal = normalize(normalMatrix * normal); 32 | FragOut.color = color; 33 | FragOut.texCoord = (texMatrix * vec4(texCoord, 1.0, 1.0)).st; 34 | 35 | } -------------------------------------------------------------------------------- /data/shaders/pbr/simplepbr.frag: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | // GLSL shader by Nick Galko from https://gist.github.com/galek/53557375251e1a942dfa 4 | //Ported to Processing by Nacho Cossio (nachocossio.com, @nacho_cossio) 5 | 6 | #define SAMPLERCUBESUPPORT 7 | 8 | uniform mat4 transformMatrix; 9 | uniform mat4 modelviewMatrix; 10 | uniform mat3 normalMatrix; 11 | uniform mat4 modelviewInv; 12 | 13 | #ifdef SAMPLERCUBESUPPORT 14 | uniform samplerCube envd; // prefiltered env cubemap 15 | #else 16 | uniform sampler2D envd; 17 | #endif 18 | // These two texture are single channel, normally they are combined in one texture 19 | // I have kept it like this for making easier to get materials from different websites 20 | uniform sampler2D roughnessMap; // roughness texture 21 | uniform sampler2D metalnessMap; // metalness texture. 22 | uniform sampler2D normalMap; // normal map 23 | 24 | uniform sampler2D iblbrdf; // IBL BRDF normalization precalculated tex 25 | uniform sampler2D albedoTex; // base texture (albedo) 26 | 27 | uniform int lightCount; 28 | uniform vec4 lightPosition[8]; 29 | uniform vec3 lightNormal[8]; 30 | uniform vec3 lightDiffuse[8]; 31 | uniform vec3 lightFalloff[8]; 32 | uniform vec3 lightAmbient[8]; 33 | uniform int mipLevels; 34 | uniform vec4 material; // x - metallic, y - roughness, w - "rim" lighting 35 | uniform float exposure; 36 | uniform float gamma = 2.2; 37 | uniform float diffuseIndirectAttenuate = 1; 38 | uniform float reflectIndirectAttenuate = 1; 39 | uniform vec3 iblSH[9]; 40 | 41 | const float one_float = 1.0; 42 | 43 | in FragData { 44 | vec4 color; 45 | vec3 ecVertex; 46 | vec3 normal; 47 | vec2 texCoord; 48 | } FragIn; 49 | in vec4 gl_FragCoord; 50 | 51 | out vec4 fragColor; 52 | #define PI 3.1415926 53 | #define COOK 54 | #define COOK_GGX 55 | #define USE_ALBEDO_MAP 56 | #define USE_ROUGHNESS_MAP 57 | #define USE_METALNESS_MAP 58 | 59 | //Taken from Filament https://github.com/google/filament/blob/main/shaders/src/light_indirect.fs 60 | //Have to invert Y axis 61 | vec3 Irradiance_SphericalHarmonics(const vec3 n) { 62 | return max( 63 | iblSH[0] 64 | // #if SPHERICAL_HARMONICS_BANDS >= 2 65 | + iblSH[1] * (-n.y) 66 | + iblSH[2] * (n.z) 67 | + iblSH[3] * (n.x) 68 | // #endif 69 | // #if SPHERICAL_HARMONICS_BANDS >= 3 70 | + iblSH[4] * (-n.y * n.x) 71 | + iblSH[5] * (-n.y * n.z) 72 | + iblSH[6] * (3.0 * n.z * n.z - 1.0) 73 | + iblSH[7] * (n.z * n.x) 74 | + iblSH[8] * (n.x * n.x - n.y * n.y) 75 | // #endif 76 | , 0.0); 77 | } 78 | 79 | float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) { 80 | vec3 lpv = lightPos - vertPos; 81 | vec3 dist = vec3(1); 82 | dist.z = dot(lpv, lpv); 83 | dist.y = sqrt(dist.z); 84 | return 1 / dot(dist, coeff); 85 | } 86 | 87 | // phong (lambertian) diffuse term 88 | float phong_diffuse() 89 | { 90 | return (1.0 / PI); 91 | } 92 | 93 | 94 | // compute fresnel specular factor for given base specular and product 95 | // product could be NdV or VdH depending on used technique 96 | vec3 fresnel_factor(in vec3 f0, in float product) 97 | { 98 | return mix(f0, vec3(1.0), pow(1.01 - product, 5.0)); 99 | } 100 | 101 | 102 | // following functions are copies of UE4 103 | // for computing cook-torrance specular lighting terms 104 | 105 | float D_blinn(in float roughness, in float NdH) 106 | { 107 | float m = roughness * roughness; 108 | float m2 = m * m; 109 | float n = 2.0 / m2 - 2.0; 110 | return (n + 2.0) / (2.0 * PI) * pow(NdH, n); 111 | } 112 | 113 | float D_beckmann(in float roughness, in float NdH) 114 | { 115 | float m = roughness * roughness; 116 | float m2 = m * m; 117 | float NdH2 = NdH * NdH; 118 | return exp((NdH2 - 1.0) / (m2 * NdH2)) / (PI * m2 * NdH2 * NdH2); 119 | } 120 | 121 | float D_GGX(in float roughness, in float NdH) 122 | { 123 | float m = roughness * roughness; 124 | float m2 = m * m; 125 | float d = (NdH * m2 - NdH) * NdH + 1.0; 126 | return m2 / (PI * d * d); 127 | } 128 | 129 | float G_schlick(in float roughness, in float NdV, in float NdL) 130 | { 131 | float k = roughness * roughness * 0.5; 132 | float V = NdV * (1.0 - k) + k; 133 | float L = NdL * (1.0 - k) + k; 134 | return 0.25 / (V * L); 135 | } 136 | 137 | 138 | // simple phong specular calculation with normalization 139 | vec3 phong_specular(in vec3 V, in vec3 L, in vec3 N, in vec3 specular, in float roughness) 140 | { 141 | vec3 R = reflect(-L, N); 142 | float spec = max(0.0, dot(V, R)); 143 | 144 | float k = 1.999 / (roughness * roughness); 145 | 146 | return min(1.0, 3.0 * 0.0398 * k) * pow(spec, min(10000.0, k)) * specular; 147 | } 148 | 149 | // simple blinn specular calculation with normalization 150 | vec3 blinn_specular(in float NdH, in vec3 specular, in float roughness) 151 | { 152 | float k = 1.999 / (roughness * roughness); 153 | 154 | return min(1.0, 3.0 * 0.0398 * k) * pow(NdH, min(10000.0, k)) * specular; 155 | } 156 | 157 | // cook-torrance specular calculation 158 | vec3 cooktorrance_specular(in float NdL, in float NdV, in float NdH, in vec3 specular, in float roughness) 159 | { 160 | #ifdef COOK_BLINN 161 | float D = D_blinn(roughness, NdH); 162 | #endif 163 | 164 | #ifdef COOK_BECKMANN 165 | float D = D_beckmann(roughness, NdH); 166 | #endif 167 | 168 | #ifdef COOK_GGX 169 | float D = D_GGX(roughness, NdH); 170 | #endif 171 | 172 | float G = G_schlick(roughness, NdV, NdL); 173 | 174 | float rim = mix(1.0 - roughness * material.w * 0.9, 1.0, NdV); 175 | 176 | return (1.0 / rim) * specular * G * D; 177 | } 178 | 179 | mat3 computeTangentFrame(vec3 normal, vec3 position, vec2 texCoord) 180 | { 181 | vec3 dpx = dFdx(position); 182 | vec3 dpy = dFdy(position); 183 | vec2 dtx = dFdx(texCoord); 184 | vec2 dty = dFdy(texCoord); 185 | 186 | vec3 tangent = normalize(dpy * dtx.t - dpx * dty.t); 187 | vec3 binormal = cross(tangent, normal); 188 | 189 | return mat3(tangent, binormal, normal); 190 | } 191 | 192 | void main() { 193 | // L, V, H vectors 194 | vec3 V = normalize(-FragIn.ecVertex); 195 | vec3 nn = normalize(FragIn.normal); 196 | vec2 texcoord = FragIn.texCoord ; 197 | //vec3 N = nn; 198 | 199 | // tbn basis 200 | vec3 unpacked = (texture(normalMap, texcoord).xyz * 2.0 - 1.0 ); 201 | vec3 N = computeTangentFrame(nn, FragIn.ecVertex, texcoord) * unpacked; 202 | N = normalize(N); 203 | 204 | // albedo/specular base 205 | #ifdef USE_ALBEDO_MAP 206 | vec3 base = texture(albedoTex, texcoord).xyz * FragIn.color.xyz; 207 | #else 208 | vec3 base = FragIn.color.xyz; 209 | #endif 210 | 211 | // roughness 212 | #ifdef USE_ROUGHNESS_MAP 213 | float roughness = texture(roughnessMap, texcoord).y * material.y; 214 | #else 215 | float roughness = material.y; 216 | #endif 217 | 218 | #ifdef USE_METALNESS_MAP 219 | float metallic = texture(metalnessMap, texcoord).y * material.x; 220 | #else 221 | float metallic = material.x; 222 | #endif 223 | 224 | // mix between metal and non-metal material, for non-metal 225 | // constant base specular factor of 0.04 grey is used 226 | vec3 specular = mix(vec3(0.04), base, metallic); 227 | 228 | //diffuse indirect light using IBL 229 | // diffuse IBL term 230 | // I know that my IBL cubemap has diffuse pre-integrated value in 10th MIP level 231 | // actually level selection should be tweakable or from separate diffuse cubemap 232 | mat3x3 tnrm = transpose(normalMatrix); 233 | vec3 refl = tnrm * N; 234 | // refl = ( vec4(refl,1) * modelviewInv).xyz; 235 | #ifdef SAMPLERCUBESUPPORT 236 | vec3 envdiff = textureLod(envd, -refl, mipLevels).xyz; 237 | #else 238 | vec3 envdiff = Irradiance_SphericalHarmonics(refl); 239 | #endif 240 | 241 | 242 | // specular IBL term 243 | // 11 magic number is total MIP levels in cubemap, this is simplest way for picking 244 | // MIP level from roughness value (but it's not correct, however it looks fine) 245 | refl = tnrm * reflect(-V, N); 246 | // refl = ( vec4(refl,1) * modelviewInv).xyz; 247 | // float mipLevel = roughness * 10.0 - pow(roughness, 6.0) * 1.5; 248 | float mipLevel = sqrt( roughness ) * (mipLevels - 1.0); 249 | #ifdef SAMPLERCUBESUPPORT 250 | vec3 envspec = textureLod( envd, -refl, mipLevel).xyz; 251 | // vec3 envspec = textureLod(envd, tnrm * N, 6).xyz; 252 | #else 253 | // vec2 tc = vec2(atan(refl.z, refl.x) + PI, acos(-refl.y)) / vec2(2.0 * PI, PI); 254 | // vec3 envspec = textureLod( envd, tc, mipLevel).xyz; 255 | float RECIPROCAL_PI2 = 0.15915494; 256 | vec2 uv; 257 | uv.x = atan( -refl.z, -refl.x ) * RECIPROCAL_PI2 + 0.5; 258 | uv.y = refl.y * 0.5 + 0.5; 259 | vec3 envspec = textureLod( envd, uv, mipLevel).xyz; 260 | #endif 261 | 262 | vec3 reflected_light = vec3(0); 263 | vec3 diffuse_light = vec3(0); // initial value == constant ambient light 264 | 265 | float NdL;// = max(0.0, dot(N, L)); 266 | float NdV = max(0.001, dot(N, V)); 267 | float NdH;// = max(0.001, dot(N, H)); 268 | float HdV;// = max(0.001, dot(H, V)); 269 | float LdV;// = max(0.001, dot(L, V)); 270 | // loop though ligt count 271 | for (int i = 0; i < 8; i++) { 272 | if (lightCount == i) break; 273 | bool isDir = lightPosition[i].w < one_float; 274 | float A; 275 | vec3 L; 276 | // point light direction to point in view space 277 | //vec3 local_light_pos = (modelviewMatrix * ( lightPosition[i])).xyz; 278 | vec3 local_light_pos = lightPosition[i].xyz; //It seems that processing send light positions in eye coordinates 279 | 280 | if (isDir) { 281 | A = one_float; 282 | L = -one_float * lightNormal[i]; 283 | } else { 284 | A = falloffFactor(local_light_pos, FragIn.ecVertex, lightFalloff[i]); 285 | L = normalize(local_light_pos - FragIn.ecVertex); 286 | } 287 | 288 | vec3 H = normalize(L + V); 289 | 290 | // compute material reflectance 291 | NdL = max(0.0, dot(N, L)); 292 | // float NdV = max(0.001, dot(N, V)); //equal for all lights 293 | NdH = max(0.001, dot(N, H)); 294 | HdV = max(0.001, dot(H, V)); 295 | LdV = max(0.001, dot(L, V)); 296 | 297 | // fresnel term is common for any, except phong 298 | // so it will be calcuated inside ifdefs 299 | #ifdef PHONG 300 | // specular reflectance with PHONG 301 | vec3 specfresnel = fresnel_factor(specular, NdV); 302 | vec3 specref = phong_specular(V, L, N, specfresnel, roughness); 303 | #endif 304 | 305 | #ifdef BLINN 306 | // specular reflectance with BLINN 307 | vec3 specfresnel = fresnel_factor(specular, HdV); 308 | vec3 specref = blinn_specular(NdH, specfresnel, roughness); 309 | #endif 310 | 311 | #ifdef COOK 312 | // specular reflectance with COOK-TORRANCE 313 | vec3 specfresnel = fresnel_factor(specular, HdV); 314 | vec3 specref = cooktorrance_specular(NdL, NdV, NdH, specfresnel, roughness); 315 | #endif 316 | 317 | specref *= vec3(NdL); 318 | // diffuse is common for any model 319 | vec3 diffref = (vec3(1.0) - specfresnel) * phong_diffuse() * NdL; 320 | // compute lighting 321 | // point light 322 | vec3 light_color = lightDiffuse[i] * A; 323 | reflected_light += specref * light_color; 324 | diffuse_light += diffref * light_color; 325 | } 326 | 327 | // IBL lighting 328 | vec2 brdf = texture(iblbrdf, vec2(roughness, 1.0 - NdV)).xy; 329 | vec3 iblspec = min(vec3(0.99), fresnel_factor(specular, NdV) * brdf.x + brdf.y); 330 | 331 | reflected_light += iblspec * envspec * reflectIndirectAttenuate; 332 | diffuse_light += envdiff * (1.0 / PI) * diffuseIndirectAttenuate ; 333 | 334 | // final result 335 | vec3 result = diffuse_light * mix(base, vec3(0.0), metallic) + 336 | reflected_light ; 337 | 338 | result = pow(result * exposure,vec3(1.0/gamma)); // gamma correction 339 | fragColor = vec4(result , 1.0); 340 | } -------------------------------------------------------------------------------- /data/textures/flatNoraml1x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosowski/SimplePBR/d8efe435589f03405450fd8fd54f3d19703415f2/data/textures/flatNoraml1x1.png -------------------------------------------------------------------------------- /data/textures/integrateBrdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosowski/SimplePBR/d8efe435589f03405450fd8fd54f3d19703415f2/data/textures/integrateBrdf.png -------------------------------------------------------------------------------- /data/textures/white1x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosowski/SimplePBR/d8efe435589f03405450fd8fd54f3d19703415f2/data/textures/white1x1.png -------------------------------------------------------------------------------- /examples/HelloPBR/HelloPBR.pde: -------------------------------------------------------------------------------- 1 | /** 2 | * SimplePBR Material showcase 3 | * 4 | * by Nacho Cossio 2018 5 | * www.nachocossio.com (@nacho_cossio) 6 | * 7 | */ 8 | 9 | import estudiolumen.simplepbr.*; 10 | 11 | PBRMat mat; 12 | 13 | public void setup() { 14 | size(800, 800, P3D); 15 | sphereDetail(20); 16 | 17 | // Path to common data folder 18 | String path = sketchPath("../data/textures/"); 19 | 20 | // Init SimplePBR providing path to folder with cubemap, radiance and irrandiance textures 21 | SimplePBR.init(this, path + "cubemap/Zion_Sunsetpeek"); // init PBR setting processed cubemap 22 | SimplePBR.setExposure(2.6f); // simple exposure control 23 | 24 | // Create PBR material from a set of textures 25 | mat = new PBRMat(path + "material/Metal_Rusted_006/"); 26 | 27 | noStroke(); 28 | } 29 | 30 | public void draw() { 31 | 32 | noLights(); 33 | pushMatrix(); 34 | translate(width/2, height/2,0); 35 | rotateY(PI); 36 | // Additive blend to lighten the background, not really needed 37 | background(40); 38 | blendMode(ADD); 39 | SimplePBR.drawCubemap(g, 800); 40 | blendMode(BLEND); 41 | popMatrix(); 42 | 43 | // Three lights set up 44 | directionalLight(200, 200, 200, 0.8f, 0.8f, -0.6f); 45 | directionalLight(255, 255, 255, 0, -0.2f, 1); 46 | directionalLight(120, 120, 120, -1f, -0.8f, -0.6f); 47 | 48 | fill(255); 49 | 50 | // Draw spheres, gradually increasing the roughness and metallic parameters 51 | int numRows = 8; 52 | float separation = width / numRows; 53 | float inc = 1f / numRows; 54 | 55 | translate(separation/2, height/4, -200); 56 | for(int i=0; i 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ${ant.description} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ${line} 81 | Building the Processing Library ${project.name} ${library.version} 82 | ${line} 83 | src path ${project.src} 84 | bin path ${project.bin} 85 | classpath.local ${classpath.local.location} 86 | sketchbook ${sketchbook.location} 87 | java version ${java.target.version} 88 | ${line} 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | ${exampleDir} 342 | 348 | 349 | 355 | 356 | 357 | 358 | 359 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | ${line} 378 | Name ${project.name} 379 | Version ${library.prettyVersion} (${library.version}) 380 | Compiled ${project.compile} 381 | Sketchbook ${sketchbook.location} 382 | ${line} 383 | done, finished. 384 | ${line} 385 | 386 | 387 | 388 | 389 | 390 | -------------------------------------------------------------------------------- /resources/code/ExampleTaglet.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosowski/SimplePBR/d8efe435589f03405450fd8fd54f3d19703415f2/resources/code/ExampleTaglet.class -------------------------------------------------------------------------------- /resources/code/ExampleTaglet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or 5 | * without modification, are permitted provided that the following 6 | * conditions are met: 7 | * 8 | * -Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * -Redistribution in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * Neither the name of Sun Microsystems, Inc. or the names of 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * This software is provided "AS IS," without a warranty of any 21 | * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 22 | * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 24 | * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY 25 | * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR 26 | * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR 27 | * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE 28 | * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, 29 | * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER 30 | * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF 31 | * THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN 32 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 33 | * 34 | * You acknowledge that Software is not designed, licensed or 35 | * intended for use in the design, construction, operation or 36 | * maintenance of any nuclear facility. 37 | */ 38 | 39 | import com.sun.tools.doclets.Taglet; 40 | import com.sun.javadoc.*; 41 | import java.util.Map; 42 | import java.io.*; 43 | /** 44 | * A sample Taglet representing @example. This tag can be used in any kind of 45 | * {@link com.sun.javadoc.Doc}. It is not an inline tag. The text is displayed 46 | * in yellow to remind the developer to perform a task. For 47 | * example, "@example Hello" would be shown as: 48 | *
49 | *
50 | * To Do: 51 | *
Fix this! 52 | *
53 | *
54 | * 55 | * @author Jamie Ho 56 | * @since 1.4 57 | */ 58 | 59 | public class ExampleTaglet implements Taglet { 60 | 61 | private static final String NAME = "example"; 62 | private static final String HEADER = "example To Do:"; 63 | 64 | /** 65 | * Return the name of this custom tag. 66 | */ 67 | public String getName() { 68 | return NAME; 69 | } 70 | 71 | /** 72 | * Will return true since @example 73 | * can be used in field documentation. 74 | * @return true since @example 75 | * can be used in field documentation and false 76 | * otherwise. 77 | */ 78 | public boolean inField() { 79 | return true; 80 | } 81 | 82 | /** 83 | * Will return true since @example 84 | * can be used in constructor documentation. 85 | * @return true since @example 86 | * can be used in constructor documentation and false 87 | * otherwise. 88 | */ 89 | public boolean inConstructor() { 90 | return true; 91 | } 92 | 93 | /** 94 | * Will return true since @example 95 | * can be used in method documentation. 96 | * @return true since @example 97 | * can be used in method documentation and false 98 | * otherwise. 99 | */ 100 | public boolean inMethod() { 101 | return true; 102 | } 103 | 104 | /** 105 | * Will return true since @example 106 | * can be used in method documentation. 107 | * @return true since @example 108 | * can be used in overview documentation and false 109 | * otherwise. 110 | */ 111 | public boolean inOverview() { 112 | return true; 113 | } 114 | 115 | /** 116 | * Will return true since @example 117 | * can be used in package documentation. 118 | * @return true since @example 119 | * can be used in package documentation and false 120 | * otherwise. 121 | */ 122 | public boolean inPackage() { 123 | return true; 124 | } 125 | 126 | /** 127 | * Will return true since @example 128 | * can be used in type documentation (classes or interfaces). 129 | * @return true since @example 130 | * can be used in type documentation and false 131 | * otherwise. 132 | */ 133 | public boolean inType() { 134 | return true; 135 | } 136 | 137 | /** 138 | * Will return false since @example 139 | * is not an inline tag. 140 | * @return false since @example 141 | * is not an inline tag. 142 | */ 143 | 144 | public boolean isInlineTag() { 145 | return false; 146 | } 147 | 148 | /** 149 | * Register this Taglet. 150 | * @param tagletMap the map to register this tag to. 151 | */ 152 | public static void register(Map tagletMap) { 153 | ExampleTaglet tag = new ExampleTaglet(); 154 | Taglet t = (Taglet) tagletMap.get(tag.getName()); 155 | if (t != null) { 156 | tagletMap.remove(tag.getName()); 157 | } 158 | tagletMap.put(tag.getName(), tag); 159 | } 160 | 161 | /** 162 | * Given the Tag representation of this custom 163 | * tag, return its string representation. 164 | * @param tag the Tag representation of this custom tag. 165 | */ 166 | public String toString(Tag tag) { 167 | return createHTML(readFile(tag.text())); 168 | } 169 | 170 | 171 | /** 172 | * Given an array of Tags representing this custom 173 | * tag, return its string representation. 174 | * @param tags the array of Tags representing of this custom tag. 175 | */ 176 | public String toString(Tag[] tags) { 177 | if (tags.length == 0) { 178 | return null; 179 | } 180 | return createHTML(readFile(tags[0].text())); 181 | } 182 | 183 | 184 | 185 | String createHTML(String theString) { 186 | if(theString!=null) { 187 | String dd = ""; 193 | 194 | return dd+"\n
" + 195 | "
+Example
" + 196 | "
"+theString+"
" + 197 | "
"; 198 | } 199 | return ""; 200 | } 201 | 202 | 203 | /** 204 | * check if the examples directory exists and return the example as given in the tag. 205 | * @param theExample the name of the example 206 | */ 207 | String readFile(String theExample) { 208 | String record = ""; 209 | String myResult = ""; 210 | int recCount = 0; 211 | String myDir = "../examples"; 212 | File file=new File(myDir); 213 | if(file.exists()==false) { 214 | myDir = "./examples"; 215 | } 216 | try { 217 | FileReader fr = new FileReader(myDir+"/"+theExample+"/"+theExample+".pde"); 218 | BufferedReader br = new BufferedReader(fr); 219 | record = new String(); 220 | while ((record = br.readLine()) != null) { 221 | myResult += record+"\n"; 222 | } 223 | } catch (IOException e) { 224 | System.out.println(e); 225 | return null; 226 | } 227 | return myResult; 228 | } 229 | } 230 | 231 | 232 | -------------------------------------------------------------------------------- /resources/code/ant-contrib-1.0b3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosowski/SimplePBR/d8efe435589f03405450fd8fd54f3d19703415f2/resources/code/ant-contrib-1.0b3.jar -------------------------------------------------------------------------------- /resources/code/doc.sh: -------------------------------------------------------------------------------- 1 | # a shell script to create a java documentation 2 | # for a processing Library. 3 | # 4 | # make changes to the variables below so they 5 | # fit the structure of your Library 6 | 7 | # the package name of your Library 8 | package=template; 9 | 10 | # source folder location 11 | src=../src; 12 | 13 | # the destination folder of your documentation 14 | dest=../documentation; 15 | 16 | 17 | # compile the java documentation 18 | javadoc -d $dest -stylesheetfile ./stylesheet.css -sourcepath ${src} ${package} 19 | -------------------------------------------------------------------------------- /resources/library.properties: -------------------------------------------------------------------------------- 1 | # More on this file here: https://github.com/processing/processing/wiki/Library-Basics 2 | # UTF-8 supported. 3 | 4 | # The name of your Library as you want it formatted. 5 | name = ##library.name## 6 | 7 | # List of authors. Links can be provided using the syntax [author name](url). 8 | authors = [##author.name##](##author.url##) 9 | 10 | # A web page for your Library, NOT a direct link to where to download it. 11 | url = ##library.url## 12 | 13 | # The category (or categories) of your Library, must be from the following list: 14 | # "3D" "Animation" "Compilations" "Data" 15 | # "Fabrication" "Geometry" "GUI" "Hardware" 16 | # "I/O" "Language" "Math" "Simulation" 17 | # "Sound" "Utilities" "Typography" "Video & Vision" 18 | # 19 | # If a value other than those listed is used, your Library will listed as 20 | # "Other". Many categories must be comma-separated. 21 | categories = ##library.categories## 22 | 23 | # A short sentence (or fragment) to summarize the Library's function. This will 24 | # be shown from inside the PDE when the Library is being installed. Avoid 25 | # repeating the name of your Library here. Also, avoid saying anything redundant 26 | # like mentioning that it's a Library. This should start with a capitalized 27 | # letter, and end with a period. 28 | sentence = ##library.sentence## 29 | 30 | # Additional information suitable for the Processing website. The value of 31 | # 'sentence' always will be prepended, so you should start by writing the 32 | # second sentence here. If your Library only works on certain operating systems, 33 | # mention it here. 34 | paragraph = ##library.paragraph## 35 | 36 | # Links in the 'sentence' and 'paragraph' attributes can be inserted using the 37 | # same syntax as for authors. 38 | # That is, [here is a link to Processing](http://processing.org/) 39 | 40 | # A version number that increments once with each release. This is used to 41 | # compare different versions of the same Library, and check if an update is 42 | # available. You should think of it as a counter, counting the total number of 43 | # releases you've had. 44 | version = ##library.version## # This must be parsable as an int 45 | 46 | # The version as the user will see it. If blank, the version attribute will be 47 | # used here. This should be a single word, with no spaces. 48 | prettyVersion = ##library.prettyVersion## # This is treated as a String 49 | 50 | # The min and max revision of Processing compatible with your Library. 51 | # Note that these fields use the revision and not the version of Processing, 52 | # parsable as an int. For example, the revision number for 2.2.1 is 227. 53 | # You can find the revision numbers in the change log: https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt 54 | # Only use maxRevision (or minRevision), when your Library is known to 55 | # break in a later (or earlier) release. Otherwise, use the default value 0. 56 | minRevision = ##compatible.minRevision## 57 | maxRevision = ##compatible.maxRevision## 58 | -------------------------------------------------------------------------------- /resources/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | /* 3 | Overall document style 4 | */ 5 | 6 | @import url('resources/fonts/dejavu.css'); 7 | 8 | body { 9 | background-color:#ffffff; 10 | color:#353833; 11 | font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; 12 | font-size:14px; 13 | margin:0; 14 | } 15 | a:link, a:visited { 16 | text-decoration:none; 17 | color:#4A6782; 18 | } 19 | a:hover, a:focus { 20 | text-decoration:none; 21 | color:#bb7a2a; 22 | } 23 | a:active { 24 | text-decoration:none; 25 | color:#4A6782; 26 | } 27 | a[name] { 28 | color:#353833; 29 | } 30 | a[name]:hover { 31 | text-decoration:none; 32 | color:#353833; 33 | } 34 | pre { 35 | font-family:'DejaVu Sans Mono', monospace; 36 | font-size:14px; 37 | } 38 | h1 { 39 | font-size:20px; 40 | } 41 | h2 { 42 | font-size:18px; 43 | } 44 | h3 { 45 | font-size:16px; 46 | font-style:italic; 47 | } 48 | h4 { 49 | font-size:13px; 50 | } 51 | h5 { 52 | font-size:12px; 53 | } 54 | h6 { 55 | font-size:11px; 56 | } 57 | ul { 58 | list-style-type:disc; 59 | } 60 | code, tt { 61 | font-family:'DejaVu Sans Mono', monospace; 62 | font-size:14px; 63 | padding-top:4px; 64 | margin-top:8px; 65 | line-height:1.4em; 66 | } 67 | dt code { 68 | font-family:'DejaVu Sans Mono', monospace; 69 | font-size:14px; 70 | padding-top:4px; 71 | } 72 | table tr td dt code { 73 | font-family:'DejaVu Sans Mono', monospace; 74 | font-size:14px; 75 | vertical-align:top; 76 | padding-top:4px; 77 | } 78 | sup { 79 | font-size:8px; 80 | } 81 | /* 82 | Document title and Copyright styles 83 | */ 84 | .clear { 85 | clear:both; 86 | height:0px; 87 | overflow:hidden; 88 | } 89 | .aboutLanguage { 90 | float:right; 91 | padding:0px 21px; 92 | font-size:11px; 93 | z-index:200; 94 | margin-top:-9px; 95 | } 96 | .legalCopy { 97 | margin-left:.5em; 98 | } 99 | .bar a, .bar a:link, .bar a:visited, .bar a:active { 100 | color:#FFFFFF; 101 | text-decoration:none; 102 | } 103 | .bar a:hover, .bar a:focus { 104 | color:#bb7a2a; 105 | } 106 | .tab { 107 | background-color:#0066FF; 108 | color:#ffffff; 109 | padding:8px; 110 | width:5em; 111 | font-weight:bold; 112 | } 113 | /* 114 | Navigation bar styles 115 | */ 116 | .bar { 117 | background-color:#4D7A97; 118 | color:#FFFFFF; 119 | padding:.8em .5em .4em .8em; 120 | height:auto;/*height:1.8em;*/ 121 | font-size:11px; 122 | margin:0; 123 | } 124 | .topNav { 125 | background-color:#4D7A97; 126 | color:#FFFFFF; 127 | float:left; 128 | padding:0; 129 | width:100%; 130 | clear:right; 131 | height:2.8em; 132 | padding-top:10px; 133 | overflow:hidden; 134 | font-size:12px; 135 | } 136 | .bottomNav { 137 | margin-top:10px; 138 | background-color:#4D7A97; 139 | color:#FFFFFF; 140 | float:left; 141 | padding:0; 142 | width:100%; 143 | clear:right; 144 | height:2.8em; 145 | padding-top:10px; 146 | overflow:hidden; 147 | font-size:12px; 148 | } 149 | .subNav { 150 | background-color:#dee3e9; 151 | float:left; 152 | width:100%; 153 | overflow:hidden; 154 | font-size:12px; 155 | } 156 | .subNav div { 157 | clear:left; 158 | float:left; 159 | padding:0 0 5px 6px; 160 | text-transform:uppercase; 161 | } 162 | ul.navList, ul.subNavList { 163 | float:left; 164 | margin:0 25px 0 0; 165 | padding:0; 166 | } 167 | ul.navList li{ 168 | list-style:none; 169 | float:left; 170 | padding: 5px 6px; 171 | text-transform:uppercase; 172 | } 173 | ul.subNavList li{ 174 | list-style:none; 175 | float:left; 176 | } 177 | .topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { 178 | color:#FFFFFF; 179 | text-decoration:none; 180 | text-transform:uppercase; 181 | } 182 | .topNav a:hover, .bottomNav a:hover { 183 | text-decoration:none; 184 | color:#bb7a2a; 185 | text-transform:uppercase; 186 | } 187 | .navBarCell1Rev { 188 | background-color:#F8981D; 189 | color:#253441; 190 | margin: auto 5px; 191 | } 192 | .skipNav { 193 | position:absolute; 194 | top:auto; 195 | left:-9999px; 196 | overflow:hidden; 197 | } 198 | /* 199 | Page header and footer styles 200 | */ 201 | .header, .footer { 202 | clear:both; 203 | margin:0 20px; 204 | padding:5px 0 0 0; 205 | } 206 | .indexHeader { 207 | margin:10px; 208 | position:relative; 209 | } 210 | .indexHeader span{ 211 | margin-right:15px; 212 | } 213 | .indexHeader h1 { 214 | font-size:13px; 215 | } 216 | .title { 217 | color:#2c4557; 218 | margin:10px 0; 219 | } 220 | .subTitle { 221 | margin:5px 0 0 0; 222 | } 223 | .header ul { 224 | margin:0 0 15px 0; 225 | padding:0; 226 | } 227 | .footer ul { 228 | margin:20px 0 5px 0; 229 | } 230 | .header ul li, .footer ul li { 231 | list-style:none; 232 | font-size:13px; 233 | } 234 | /* 235 | Heading styles 236 | */ 237 | div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { 238 | background-color:#dee3e9; 239 | border:1px solid #d0d9e0; 240 | margin:0 0 6px -8px; 241 | padding:7px 5px; 242 | } 243 | ul.blockList ul.blockList ul.blockList li.blockList h3 { 244 | background-color:#dee3e9; 245 | border:1px solid #d0d9e0; 246 | margin:0 0 6px -8px; 247 | padding:7px 5px; 248 | } 249 | ul.blockList ul.blockList li.blockList h3 { 250 | padding:0; 251 | margin:15px 0; 252 | } 253 | ul.blockList li.blockList h2 { 254 | padding:0px 0 20px 0; 255 | } 256 | /* 257 | Page layout container styles 258 | */ 259 | .contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { 260 | clear:both; 261 | padding:10px 20px; 262 | position:relative; 263 | } 264 | .indexContainer { 265 | margin:10px; 266 | position:relative; 267 | font-size:12px; 268 | } 269 | .indexContainer h2 { 270 | font-size:13px; 271 | padding:0 0 3px 0; 272 | } 273 | .indexContainer ul { 274 | margin:0; 275 | padding:0; 276 | } 277 | .indexContainer ul li { 278 | list-style:none; 279 | padding-top:2px; 280 | } 281 | .contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { 282 | font-size:12px; 283 | font-weight:bold; 284 | margin:10px 0 0 0; 285 | color:#4E4E4E; 286 | } 287 | .contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { 288 | margin:5px 0 10px 0px; 289 | font-size:14px; 290 | font-family:'DejaVu Sans Mono',monospace; 291 | } 292 | .serializedFormContainer dl.nameValue dt { 293 | margin-left:1px; 294 | font-size:1.1em; 295 | display:inline; 296 | font-weight:bold; 297 | } 298 | .serializedFormContainer dl.nameValue dd { 299 | margin:0 0 0 1px; 300 | font-size:1.1em; 301 | display:inline; 302 | } 303 | /* 304 | List styles 305 | */ 306 | ul.horizontal li { 307 | display:inline; 308 | font-size:0.9em; 309 | } 310 | ul.inheritance { 311 | margin:0; 312 | padding:0; 313 | } 314 | ul.inheritance li { 315 | display:inline; 316 | list-style:none; 317 | } 318 | ul.inheritance li ul.inheritance { 319 | margin-left:15px; 320 | padding-left:15px; 321 | padding-top:1px; 322 | } 323 | ul.blockList, ul.blockListLast { 324 | margin:10px 0 10px 0; 325 | padding:0; 326 | } 327 | ul.blockList li.blockList, ul.blockListLast li.blockList { 328 | list-style:none; 329 | margin-bottom:15px; 330 | line-height:1.4; 331 | } 332 | ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { 333 | padding:0px 20px 5px 10px; 334 | border:1px solid #ededed; 335 | background-color:#f8f8f8; 336 | } 337 | ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { 338 | padding:0 0 5px 8px; 339 | background-color:#ffffff; 340 | border:none; 341 | } 342 | ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { 343 | margin-left:0; 344 | padding-left:0; 345 | padding-bottom:15px; 346 | border:none; 347 | } 348 | ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { 349 | list-style:none; 350 | border-bottom:none; 351 | padding-bottom:0; 352 | } 353 | table tr td dl, table tr td dl dt, table tr td dl dd { 354 | margin-top:0; 355 | margin-bottom:1px; 356 | } 357 | /* 358 | Table styles 359 | */ 360 | .overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { 361 | width:100%; 362 | border-left:1px solid #EEE; 363 | border-right:1px solid #EEE; 364 | border-bottom:1px solid #EEE; 365 | } 366 | .overviewSummary, .memberSummary { 367 | padding:0px; 368 | } 369 | .overviewSummary caption, .memberSummary caption, .typeSummary caption, 370 | .useSummary caption, .constantsSummary caption, .deprecatedSummary caption { 371 | position:relative; 372 | text-align:left; 373 | background-repeat:no-repeat; 374 | color:#253441; 375 | font-weight:bold; 376 | clear:none; 377 | overflow:hidden; 378 | padding:0px; 379 | padding-top:10px; 380 | padding-left:1px; 381 | margin:0px; 382 | white-space:pre; 383 | } 384 | .overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, 385 | .useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, 386 | .overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, 387 | .useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, 388 | .overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, 389 | .useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, 390 | .overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, 391 | .useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { 392 | color:#FFFFFF; 393 | } 394 | .overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, 395 | .useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { 396 | white-space:nowrap; 397 | padding-top:5px; 398 | padding-left:12px; 399 | padding-right:12px; 400 | padding-bottom:7px; 401 | display:inline-block; 402 | float:left; 403 | background-color:#F8981D; 404 | border: none; 405 | height:16px; 406 | } 407 | .memberSummary caption span.activeTableTab span { 408 | white-space:nowrap; 409 | padding-top:5px; 410 | padding-left:12px; 411 | padding-right:12px; 412 | margin-right:3px; 413 | display:inline-block; 414 | float:left; 415 | background-color:#F8981D; 416 | height:16px; 417 | } 418 | .memberSummary caption span.tableTab span { 419 | white-space:nowrap; 420 | padding-top:5px; 421 | padding-left:12px; 422 | padding-right:12px; 423 | margin-right:3px; 424 | display:inline-block; 425 | float:left; 426 | background-color:#4D7A97; 427 | height:16px; 428 | } 429 | .memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { 430 | padding-top:0px; 431 | padding-left:0px; 432 | padding-right:0px; 433 | background-image:none; 434 | float:none; 435 | display:inline; 436 | } 437 | .overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, 438 | .useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { 439 | display:none; 440 | width:5px; 441 | position:relative; 442 | float:left; 443 | background-color:#F8981D; 444 | } 445 | .memberSummary .activeTableTab .tabEnd { 446 | display:none; 447 | width:5px; 448 | margin-right:3px; 449 | position:relative; 450 | float:left; 451 | background-color:#F8981D; 452 | } 453 | .memberSummary .tableTab .tabEnd { 454 | display:none; 455 | width:5px; 456 | margin-right:3px; 457 | position:relative; 458 | background-color:#4D7A97; 459 | float:left; 460 | 461 | } 462 | .overviewSummary td, .memberSummary td, .typeSummary td, 463 | .useSummary td, .constantsSummary td, .deprecatedSummary td { 464 | text-align:left; 465 | padding:0px 0px 12px 10px; 466 | } 467 | th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, 468 | td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ 469 | vertical-align:top; 470 | padding-right:0px; 471 | padding-top:8px; 472 | padding-bottom:3px; 473 | } 474 | th.colFirst, th.colLast, th.colOne, .constantsSummary th { 475 | background:#dee3e9; 476 | text-align:left; 477 | padding:8px 3px 3px 7px; 478 | } 479 | td.colFirst, th.colFirst { 480 | white-space:nowrap; 481 | font-size:13px; 482 | } 483 | td.colLast, th.colLast { 484 | font-size:13px; 485 | } 486 | td.colOne, th.colOne { 487 | font-size:13px; 488 | } 489 | .overviewSummary td.colFirst, .overviewSummary th.colFirst, 490 | .useSummary td.colFirst, .useSummary th.colFirst, 491 | .overviewSummary td.colOne, .overviewSummary th.colOne, 492 | .memberSummary td.colFirst, .memberSummary th.colFirst, 493 | .memberSummary td.colOne, .memberSummary th.colOne, 494 | .typeSummary td.colFirst{ 495 | width:25%; 496 | vertical-align:top; 497 | } 498 | td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { 499 | font-weight:bold; 500 | } 501 | .tableSubHeadingColor { 502 | background-color:#EEEEFF; 503 | } 504 | .altColor { 505 | background-color:#FFFFFF; 506 | } 507 | .rowColor { 508 | background-color:#EEEEEF; 509 | } 510 | /* 511 | Content styles 512 | */ 513 | .description pre { 514 | margin-top:0; 515 | } 516 | .deprecatedContent { 517 | margin:0; 518 | padding:10px 0; 519 | } 520 | .docSummary { 521 | padding:0; 522 | } 523 | 524 | ul.blockList ul.blockList ul.blockList li.blockList h3 { 525 | font-style:normal; 526 | } 527 | 528 | div.block { 529 | font-size:14px; 530 | font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; 531 | } 532 | 533 | td.colLast div { 534 | padding-top:0px; 535 | } 536 | 537 | 538 | td.colLast a { 539 | padding-bottom:3px; 540 | } 541 | /* 542 | Formatting effect styles 543 | */ 544 | .sourceLineNo { 545 | color:green; 546 | padding:0 30px 0 0; 547 | } 548 | h1.hidden { 549 | visibility:hidden; 550 | overflow:hidden; 551 | font-size:10px; 552 | } 553 | .block { 554 | display:block; 555 | margin:3px 10px 2px 0px; 556 | color:#474747; 557 | } 558 | .deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, 559 | .overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, 560 | .seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { 561 | font-weight:bold; 562 | } 563 | .deprecationComment, .emphasizedPhrase, .interfaceName { 564 | font-style:italic; 565 | } 566 | 567 | div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, 568 | div.block div.block span.interfaceName { 569 | font-style:normal; 570 | } 571 | 572 | div.contentContainer ul.blockList li.blockList h2{ 573 | padding-bottom:0px; 574 | } -------------------------------------------------------------------------------- /screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosowski/SimplePBR/d8efe435589f03405450fd8fd54f3d19703415f2/screenshot.gif -------------------------------------------------------------------------------- /src/estudiolumen/simplepbr/PBRMat.java: -------------------------------------------------------------------------------- 1 | package estudiolumen.simplepbr; 2 | 3 | import processing.core.PApplet; 4 | import processing.core.PGraphics; 5 | import processing.core.PImage; 6 | import processing.opengl.PShader; 7 | 8 | public class PBRMat { 9 | PShader shader; 10 | PImage albedoTex, metallicTex, roughnessTex, normalTex; 11 | float metallic; 12 | float roughness; 13 | float rim; 14 | 15 | public PBRMat(){ 16 | metallic = 1; 17 | roughness = 1; 18 | rim = 1f; 19 | shader = SimplePBR.getPbrShader(); 20 | albedoTex = SimplePBR.getWhiteTexture(); 21 | metallicTex = SimplePBR.getWhiteTexture(); 22 | roughnessTex = SimplePBR.getWhiteTexture(); 23 | normalTex = SimplePBR.getFlatNormalTexture(); 24 | } 25 | 26 | public PBRMat( String path){ 27 | this(); 28 | PImage img = SimplePBR.getPapplet().loadImage(path+"albedo.png"); if(img != null) albedoTex = img; 29 | PImage m = SimplePBR.getPapplet().loadImage(path+"metalness.png"); if(m != null) metallicTex = m; 30 | PImage r = SimplePBR.getPapplet().loadImage(path+"roughness.png"); if(r!= null) roughnessTex = r; 31 | PImage n = SimplePBR.getPapplet().loadImage(path+"normal.png"); if(n != null) normalTex = n; 32 | } 33 | 34 | public PBRMat(PBRMat copy){ 35 | this(); 36 | metallic = copy.metallic; 37 | roughness = copy.roughness; 38 | rim = copy.rim; 39 | shader = copy.shader; 40 | albedoTex = copy.albedoTex; 41 | metallicTex = copy.metallicTex; 42 | roughnessTex = copy.roughnessTex; 43 | normalTex = copy.roughnessTex; 44 | } 45 | 46 | public void bind(){ 47 | bind(SimplePBR.getPapplet().g); 48 | } 49 | 50 | public void bind(PGraphics pg){ 51 | pg.resetShader(); 52 | shader.set("roughnessMap", roughnessTex); 53 | shader.set("metalnessMap", metallicTex); 54 | shader.set("albedoTex", albedoTex); 55 | shader.set("normalMap", normalTex); 56 | shader.set("material", metallic, roughness,0f, rim); 57 | pg.shader(shader); 58 | } 59 | 60 | 61 | public PShader getShader() { 62 | return shader; 63 | } 64 | 65 | public PBRMat setShader(PShader shader) { 66 | this.shader = shader; 67 | return this; 68 | } 69 | 70 | public float getMetallic() { 71 | return metallic; 72 | } 73 | 74 | public PBRMat setMetallic(float metallic) { 75 | this.metallic = metallic; 76 | return this; 77 | } 78 | 79 | public float getRougness() { 80 | return roughness; 81 | } 82 | 83 | public PBRMat setRougness(float rougness) { 84 | this.roughness = rougness; 85 | return this; 86 | } 87 | 88 | public float getRim() { 89 | return rim; 90 | } 91 | 92 | public PBRMat setRim(float rim) { 93 | this.rim = rim; 94 | return this; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/estudiolumen/simplepbr/SimplePBR.java: -------------------------------------------------------------------------------- 1 | package estudiolumen.simplepbr; 2 | 3 | 4 | import java.nio.IntBuffer; 5 | 6 | import com.jogamp.opengl.GL3; 7 | 8 | import processing.core.*; 9 | import processing.opengl.PGL; 10 | import processing.opengl.PGraphicsOpenGL; 11 | import processing.opengl.PShader; 12 | 13 | /* 14 | * SimplePBR Nacho Cossio - www.nachocossio.com 15 | * https://github.com/kosowski/ 16 | * A Processing library for physically based rendering 17 | */ 18 | 19 | public class SimplePBR { 20 | 21 | 22 | public final static String VERSION = "0.3"; 23 | 24 | private static PApplet papplet; 25 | private static PShader pbrShader; 26 | private static PImage whiteTexture, flatNormalTexture; 27 | private static PImage iblbrdf; 28 | private static PImage[] cubemapTextures; 29 | private static int mipLevels = 7; 30 | private static float exposure = 1f; 31 | private static float[] shCoeficients; 32 | 33 | public static void init(PApplet thePapplet, String iblpath){ 34 | SimplePBR.papplet = thePapplet; 35 | 36 | PApplet.println("\t", PGraphicsOpenGL.OPENGL_VENDOR); 37 | PApplet.println("\t", PGraphicsOpenGL.OPENGL_RENDERER); 38 | PApplet.println("\t", PGraphicsOpenGL.OPENGL_VERSION); 39 | PApplet.println("\t", PGraphicsOpenGL.GLSL_VERSION); 40 | welcome(); 41 | 42 | iblbrdf = thePapplet.loadImage("data/textures/integrateBrdf.png"); 43 | whiteTexture = thePapplet.loadImage("data/textures/white1x1.png"); 44 | flatNormalTexture = thePapplet.loadImage("data/textures/flatNoraml1x1.png"); 45 | 46 | int enviromentmapTextureUnit = PGL.TEXTURE3+2; //minimum number of texture units is 16 47 | 48 | String[] vertSource = thePapplet.loadStrings("data/shaders/pbr/pbr.vert"); 49 | String[] fragSource = thePapplet.loadStrings("data/shaders/pbr/simplepbr.frag"); 50 | pbrShader = new PShader(thePapplet, vertSource, fragSource); 51 | 52 | pbrShader.set("mipLevels", mipLevels); 53 | pbrShader.set("envd", 5); 54 | pbrShader.set("iblbrdf", iblbrdf); 55 | pbrShader.set("exposure", exposure); 56 | 57 | boolean cubemapSupport = true; 58 | try{ 59 | thePapplet.g.shader(pbrShader); 60 | } 61 | catch (Exception e) 62 | { 63 | System.out.println("No support for cubemaps, falling back to equirectangular maps"); 64 | System.out.println("Shader compiling can take a long time on this graphics card (10-20 secs) while showing blank window, please wait"); 65 | cubemapSupport = false; 66 | 67 | // Remove the SAMPLERCUBESUPPORT define 68 | for(int i=0; i< fragSource.length;i++) 69 | if(fragSource[i].matches("#define SAMPLERCUBESUPPORT")) { 70 | fragSource[i] =""; 71 | break; 72 | } 73 | 74 | pbrShader = new PShader(thePapplet, vertSource, fragSource); 75 | 76 | pbrShader.set("envd", 5); 77 | pbrShader.set("mipLevels", mipLevels); 78 | pbrShader.set("iblbrdf", iblbrdf); 79 | pbrShader.set("exposure", exposure); 80 | 81 | loadSHCoeficients(iblpath+"/sh.txt"); 82 | pbrShader.set("iblSH", shCoeficients, 3); 83 | 84 | try { 85 | thePapplet.g.shader(pbrShader); 86 | }catch (Exception e2) { 87 | System.out.println("Ops, that did not work too" ); 88 | e2.printStackTrace(); 89 | } 90 | }finally 91 | { 92 | if(cubemapSupport) 93 | cubemapTextures = loadPrefilteredEnviromentMap(thePapplet, enviromentmapTextureUnit, iblpath+"/PREM", 94 | iblpath+"/irradiance", mipLevels); 95 | else 96 | cubemapTextures = loadPrefilteredEnviromentMapLatLong(thePapplet, enviromentmapTextureUnit, iblpath+"_LatLong"+"/PREM", 97 | iblpath+"/irradiance", mipLevels); 98 | } 99 | thePapplet.g.resetShader(); 100 | } 101 | 102 | public static PApplet getPapplet() { 103 | return papplet; 104 | } 105 | 106 | public static PShader getPbrShader() { 107 | return pbrShader; 108 | } 109 | 110 | public static PImage getWhiteTexture() { 111 | return whiteTexture; 112 | } 113 | 114 | public static PImage getFlatNormalTexture() { 115 | return flatNormalTexture; 116 | } 117 | 118 | public static void setExposure(float _exposure) { 119 | exposure = _exposure; 120 | pbrShader.set("exposure", exposure); 121 | } 122 | 123 | public static void setDiffuseAttenuation(float att) { 124 | pbrShader.set("diffuseIndirectAttenuate", att); 125 | } 126 | 127 | public static void setReflectionAttenuation(float att) { 128 | pbrShader.set("reflectIndirectAttenuate", att); 129 | } 130 | 131 | static void loadSHCoeficients(String path) { 132 | int index = 0; 133 | shCoeficients = new float[27]; //3 x 9 134 | String[] lines = papplet.loadStrings(path); 135 | for(int i=0;i < lines.length;i++) { 136 | String[] line = PApplet.splitTokens( lines[i], "()"); 137 | if(line.length > 0 ) { 138 | String[] values = PApplet.splitTokens( line[0], ", "); 139 | if(values.length >= 3) 140 | for(int j=0; j<3; j++) 141 | shCoeficients[index++] = Float.parseFloat(values[j]); 142 | } 143 | } 144 | } 145 | 146 | static public PImage[] loadPrefilteredEnviromentMap(PApplet p5, int textureID, String texturesPath, String irradianceTexturePath, int minLevel){ 147 | 148 | PImage[] textures = null; 149 | IntBuffer envMapTextureID; 150 | 151 | PGL pgl = p5.beginPGL(); 152 | // GL3 gl = ((PJOGL) pgl).gl.getGL3(); 153 | // create the OpenGL-based cubeMap 154 | envMapTextureID = IntBuffer.allocate(1); 155 | pgl.genTextures(1, envMapTextureID); 156 | pgl.activeTexture(textureID); 157 | pgl.enable(GL3.GL_TEXTURE_CUBE_MAP_SEAMLESS); //without seamlees cube there are artifacts at higher roughness 158 | pgl.enable(PGL.TEXTURE_CUBE_MAP); 159 | pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, envMapTextureID.get(0)); 160 | pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_S, PGL.CLAMP_TO_EDGE); 161 | pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_T, PGL.CLAMP_TO_EDGE); 162 | pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_R, PGL.CLAMP_TO_EDGE); 163 | pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MIN_FILTER, PGL.LINEAR_MIPMAP_LINEAR); //need this for mip maps 164 | pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MAG_FILTER, PGL.LINEAR); 165 | 166 | String[] cubeSideNames = { 167 | "_posx_", "_negx_", "_posy_", "_negy_", "_posz_", "_negz_" 168 | }; 169 | String textureName = "output_pmrem"; 170 | 171 | 172 | for(int k=0; k> 16) | (pixel & 0x0000FF00); 188 | } 189 | // load the image in the required face and mip level 190 | pgl.texImage2D(PGL.TEXTURE_CUBE_MAP_POSITIVE_X + i, k, PGL.RGBA, w, h, 0, PGL.RGBA, PGL.UNSIGNED_BYTE, java.nio.IntBuffer.wrap(rgbaPixels)); 191 | } 192 | } 193 | // irradiancemap after the last mip levevl 194 | String[] irradienceTextureNames = { 195 | "_posx","_negx", "_posy", "_negy", "_posz", "_negz" 196 | }; 197 | textures = new PImage[cubeSideNames.length]; 198 | for (int i=0; i> 16) | (pixel & 0x0000FF00); 213 | } 214 | // load the image in the required face and mip level 215 | pgl.texImage2D(PGL.TEXTURE_CUBE_MAP_POSITIVE_X + i, minLevel, PGL.RGBA, w, h, 0, PGL.RGBA, PGL.UNSIGNED_BYTE, java.nio.IntBuffer.wrap(rgbaPixels)); 216 | } 217 | pgl.generateMipmap(PGL.TEXTURE_CUBE_MAP); //this is requiered for mipmaps 218 | p5.endPGL(); 219 | 220 | return textures; 221 | } 222 | 223 | static public PImage[] loadPrefilteredEnviromentMapLatLong(PApplet p5, int textureID, String texturesPath, String irradianceTexturePath, int minLevel){ 224 | PImage textures = null; 225 | IntBuffer envMapTextureID; 226 | 227 | PGL pgl = p5.beginPGL(); 228 | // GL3 gl = ((PJOGL) pgl).gl.getGL3(); 229 | // create the OpenGL-based cubeMap 230 | envMapTextureID = IntBuffer.allocate(1); 231 | pgl.genTextures(1, envMapTextureID); 232 | pgl.activeTexture(textureID); 233 | pgl.bindTexture(PGL.TEXTURE_2D, envMapTextureID.get(0)); 234 | pgl.texParameteri(PGL.TEXTURE_2D, PGL.TEXTURE_WRAP_S, PGL.CLAMP_TO_EDGE); 235 | pgl.texParameteri(PGL.TEXTURE_2D, PGL.TEXTURE_WRAP_T, PGL.CLAMP_TO_EDGE); 236 | pgl.texParameteri(PGL.TEXTURE_2D, PGL.TEXTURE_WRAP_R, PGL.CLAMP_TO_EDGE); 237 | pgl.texParameteri(PGL.TEXTURE_2D, PGL.TEXTURE_MIN_FILTER, PGL.LINEAR_MIPMAP_LINEAR); //need this for mip maps 238 | pgl.texParameteri(PGL.TEXTURE_2D, PGL.TEXTURE_MAG_FILTER, PGL.LINEAR); 239 | 240 | String textureName = "output_pmrem_"; 241 | 242 | for(int k=0; k> 16) | (pixel & 0x0000FF00); 253 | } 254 | // load the image in the required mip level 255 | pgl.texImage2D(PGL.TEXTURE_2D, k, PGL.RGBA, w, h, 0, PGL.RGBA, PGL.UNSIGNED_BYTE, java.nio.IntBuffer.wrap(rgbaPixels)); 256 | 257 | } 258 | pgl.generateMipmap(PGL.TEXTURE_2D); //this is requiered for mipmaps 259 | p5.endPGL(); 260 | 261 | return null; 262 | } 263 | 264 | static public void drawCubemap(PGraphics renderer, int size) { 265 | if(cubemapTextures == null) 266 | return; 267 | renderer.resetShader(); 268 | renderer.textureMode(PApplet.NORMAL ); 269 | renderer.noStroke(); 270 | renderer.beginShape(PApplet.QUAD); 271 | renderer.texture(cubemapTextures[4]); 272 | // +Z "front" face 273 | renderer.vertex(-1 * size, -1 * size, 1 * size, 0, 0); 274 | renderer.vertex( 1 * size, -1 * size, 1 * size, 1, 0); 275 | renderer.vertex( 1 * size, 1 * size, 1 * size, 1, 1); 276 | renderer.vertex(-1 * size, 1 * size, 1 * size, 0, 1); 277 | renderer.endShape(); 278 | 279 | renderer.beginShape(PApplet.QUAD); 280 | renderer.texture(cubemapTextures[5]); 281 | // -Z "back" face 282 | renderer.vertex( 1 * size, -1 * size, -1 * size, 0, 0); 283 | renderer.vertex(-1 * size, -1 * size, -1 * size, 1, 0); 284 | renderer.vertex(-1 * size, 1 * size, -1 * size, 1, 1); 285 | renderer.vertex( 1 * size, 1 * size, -1 * size, 0, 1); 286 | renderer.endShape(); 287 | 288 | renderer.beginShape(PApplet.QUAD); 289 | renderer.texture(cubemapTextures[3]); 290 | // +Y "bottom" face 291 | renderer.vertex(-1 * size, 1 * size, 1 * size, 0, 0); 292 | renderer.vertex( 1 * size, 1 * size, 1 * size, 1, 0); 293 | renderer.vertex( 1 * size, 1 * size, -1 * size, 1, 1); 294 | renderer.vertex(-1 * size, 1 * size, -1 * size, 0, 1); 295 | renderer.endShape(); 296 | 297 | renderer.beginShape(PApplet.QUAD); 298 | renderer.texture(cubemapTextures[2]); 299 | // -Y "top" face 300 | renderer.vertex(-1 * size, -1 * size, -1 * size, 0, 0); 301 | renderer.vertex( 1 * size, -1 * size, -1 * size, 1, 0); 302 | renderer.vertex( 1 * size, -1 * size, 1 * size, 1, 1); 303 | renderer.vertex(-1 * size, -1 * size, 1 * size, 0, 1); 304 | renderer.endShape(); 305 | 306 | renderer.beginShape(PApplet.QUAD); 307 | renderer.texture(cubemapTextures[0]); 308 | // +X "right" face 309 | renderer.vertex( 1 * size, -1 * size, 1 * size, 0, 0); 310 | renderer.vertex( 1 * size, -1 * size, -1 * size, 1, 0); 311 | renderer.vertex( 1 * size, 1 * size, -1 * size, 1, 1); 312 | renderer.vertex( 1 * size, 1 * size, 1 * size, 0, 1); 313 | renderer.endShape(); 314 | 315 | renderer.beginShape(PApplet.QUAD); 316 | renderer.texture(cubemapTextures[1]); 317 | // -X "left" face 318 | renderer.vertex(-1 * size, -1 * size, -1 * size, 0, 0); 319 | renderer.vertex(-1 * size, -1 * size, 1 * size, 1, 0); 320 | renderer.vertex(-1 * size, 1 * size, 1 * size, 1, 1); 321 | renderer.vertex(-1 * size, 1 * size, -1 * size, 0, 1); 322 | renderer.endShape(); 323 | } 324 | 325 | private static void welcome() { 326 | System.out.println("SimplePBR " 327 | + VERSION 328 | + " " 329 | + "by Nacho Cossio (@nacho_cossio) @ http://nachocossio.com"); 330 | } 331 | 332 | 333 | /** 334 | * return the version of the Library. 335 | * 336 | * @return String 337 | */ 338 | public static String version() { 339 | return VERSION; 340 | } 341 | } 342 | 343 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | ##library.name## 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 25 | 26 | 38 | 39 |
40 | 41 |
42 |

##library.name##

43 |

44 | A Library by ##author.name## for the Processing programming environment.
45 | Last update, ##date##. 46 |

47 |

48 | ##library.sentence##
49 | ##library.paragraph##
50 | Feel free to replace this paragraph with a description of the Library.
51 | Contributed Libraries are developed, documented, and maintained by members of the Processing community. Further directions are included with each Library. For feedback and support, please post to the Discourse. We strongly encourage all Libraries to be open source, but not all of them are. 52 |

53 |
54 | 55 | 56 | 57 |
58 |

Download

59 |

60 | Download ##library.name## version ##library.prettyVersion## (##library.version##) in 61 | .zip format. 62 |

63 |

Installation

64 |

65 | Unzip and put the extracted ##project.name## folder into the libraries folder of your Processing sketches. Reference and examples are included in the ##project.name## folder. 66 |

67 |
68 | 69 | 70 |
71 |

Keywords. ##library.keywords##

72 |

Reference. Have a look at the javadoc reference here. A copy of the reference is included in the .zip as well.

73 |

Source. The source code of ##library.name## is available at ##source.host##, and its repository can be browsed here.

74 |
75 | 76 | 77 |
78 |

Examples

79 |

Find a list of examples in the current distribution of ##library.name##, or have a look at them by following the links below.

80 |
    81 | ##examples## 82 |
83 |
84 | 85 | 86 |
87 |

Tested

88 |

89 | 90 | Platform ##tested.platform## 91 | 92 | 93 |
Processing ##tested.processingVersion## 94 | 95 | 96 |
Dependencies ##library.dependencies## 97 |

98 |
99 | 100 | 101 | 102 | 114 | 115 | 116 | 121 | 122 | 123 | 127 | 128 | 129 |
130 |
131 | 132 | 135 |
136 | 137 | -------------------------------------------------------------------------------- /web/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* processingLibs style by andreas schlegel, sojamo. */ 2 | 3 | 4 | * { 5 | margin:0; 6 | padding:0; 7 | border:0; 8 | } 9 | 10 | 11 | body { 12 | font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; 13 | font-size : 100%; 14 | font-size : 0.70em; 15 | font-weight : normal; 16 | line-height : normal; 17 | } 18 | 19 | 20 | 21 | #container { 22 | margin-left:64px; 23 | background-color:#fff; 24 | } 25 | 26 | #header { 27 | float:left; 28 | padding-top:24px; 29 | padding-bottom:48px; 30 | } 31 | 32 | #menu { 33 | margin-top:16px; 34 | float:left; 35 | margin-bottom:64px; 36 | } 37 | 38 | 39 | #about, 40 | #download, 41 | #examples, 42 | #demos, 43 | #misc { 44 | width:480px; 45 | float:left; 46 | margin-right:24px; 47 | } 48 | 49 | 50 | #resources, #info { 51 | width:320px; 52 | float:left; 53 | } 54 | 55 | 56 | .clear { 57 | clear:both; 58 | } 59 | 60 | #footer { 61 | margin-top:300px; 62 | height:20px; 63 | margin-bottom:32px; 64 | } 65 | 66 | 67 | ul { 68 | list-style:none; 69 | padding:0; 70 | margin:0; 71 | } 72 | 73 | 74 | #menu ul li, #subMenu ul li { 75 | float:left; 76 | padding-right:6px; 77 | } 78 | 79 | 80 | 81 | 82 | 83 | 84 | /* Headings */ 85 | 86 | h1 { 87 | font-size:2em; 88 | font-weight:normal; 89 | } 90 | 91 | 92 | h2, h3, h4, h5, th { 93 | font-size:1.3em; 94 | font-weight:normal; 95 | margin-bottom:4px; 96 | } 97 | 98 | 99 | 100 | p { 101 | font-size:1em; 102 | width:90%; 103 | margin-bottom:32px; 104 | } 105 | 106 | 107 | pre, code { 108 | font-family:"Courier New", Courier, monospace; 109 | font-size:1em; 110 | line-height:normal; 111 | } 112 | 113 | 114 | 115 | 116 | hr { 117 | border:0; 118 | height:1px; 119 | margin-bottom:24px; 120 | } 121 | 122 | 123 | a { 124 | text-decoration: underline; 125 | font-weight: normal; 126 | } 127 | 128 | 129 | a:hover, 130 | a:active { 131 | text-decoration: underline; 132 | font-weight: normal; 133 | } 134 | 135 | 136 | a:visited, 137 | a:link:visited { 138 | text-decoration: underline; 139 | font-weight: normal; 140 | } 141 | 142 | 143 | 144 | img { 145 | border: 0px solid #000000; 146 | } 147 | 148 | 149 | 150 | 151 | 152 | /* COLORS */ 153 | 154 | 155 | body { 156 | color : #333; 157 | background-color :#fff; 158 | } 159 | 160 | 161 | #header { 162 | background-color:#fff; 163 | color:#333; 164 | } 165 | 166 | 167 | 168 | h1, h2, h3, h4, h5, h6 { 169 | color:#666; 170 | } 171 | 172 | 173 | pre, code { 174 | color: #000000; 175 | } 176 | 177 | 178 | a,strong { 179 | color: #333; 180 | } 181 | 182 | 183 | a:hover, 184 | a:active { 185 | color: #333; 186 | } 187 | 188 | 189 | a:visited, 190 | a:link:visited { 191 | color: #333; 192 | } 193 | 194 | 195 | #footer, #menu { 196 | background-color:#fff; 197 | color:#333; 198 | } 199 | 200 | 201 | #footer a, #menu a { 202 | color:#333; 203 | } 204 | --------------------------------------------------------------------------------