Changed normal of the ground to GL, Now the normal mapping is correct.
118
AGENTS.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# Fundamental Coding Style Rules
|
||||||
|
|
||||||
|
Codex must obey these rules without exception:
|
||||||
|
|
||||||
|
## Imports
|
||||||
|
|
||||||
|
* Each import statement must be separated by exactly **one empty line**.
|
||||||
|
* All `from` tokens must be aligned vertically using **tabs before `from`**.
|
||||||
|
* Use **double quotes** for all string literals.
|
||||||
|
* Use **ES modules** only.
|
||||||
|
* Avoid backticks unless unavoidable for syntax.
|
||||||
|
|
||||||
|
## Function Calls
|
||||||
|
|
||||||
|
* Always write calls like:
|
||||||
|
`myFunction( param )`
|
||||||
|
with spaces **inside** parentheses.
|
||||||
|
|
||||||
|
## Class Structure
|
||||||
|
|
||||||
|
* Exactly **one empty line** between class methods.
|
||||||
|
* No empty line at start or end of class.
|
||||||
|
* Methods must start with a blank line after `{` and end with a blank line before `}`.
|
||||||
|
|
||||||
|
## Method Body Spacing
|
||||||
|
|
||||||
|
Inside every method body:
|
||||||
|
|
||||||
|
* **One empty line between every line of code**.
|
||||||
|
* No inline comments on the same line as code.
|
||||||
|
|
||||||
|
## Callbacks & Functions
|
||||||
|
|
||||||
|
* Never write inline callbacks.
|
||||||
|
* Never write nested callbacks.
|
||||||
|
* Never pass anonymous inline functions to `.map()`, `.filter()`, `.forEach()`, etc.
|
||||||
|
* Never use arrow functions.
|
||||||
|
* Always create a separate class method instead.
|
||||||
|
|
||||||
|
## Promises
|
||||||
|
|
||||||
|
* Never use `.then()`.
|
||||||
|
* Never use `new Promise( resolve => { ... } )`.
|
||||||
|
* Always use `async` / `await`.
|
||||||
|
* Avoid `try-catch` blocks unless mandatory.
|
||||||
|
|
||||||
|
## Arrays
|
||||||
|
|
||||||
|
* Use `new Array()` instead of `[]`, **except** in Angular metadata (`imports: [ ]`, `providers: [ ]` etc.) where `[]` is allowed.
|
||||||
|
|
||||||
|
## Objects
|
||||||
|
|
||||||
|
* Never return an inline object directly.
|
||||||
|
* Always assign the object to a variable first, then return that variable.
|
||||||
|
* Align object literal values vertically using tabs before the values.
|
||||||
|
|
||||||
|
## Conditionals
|
||||||
|
|
||||||
|
* Never use short-form ternary (`? :`).
|
||||||
|
* Always write full `if` statements.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
* Do not use `$()` syntax.
|
||||||
|
* Use simple logs:
|
||||||
|
`console.log( "message", value );`
|
||||||
|
|
||||||
|
## JSON imports
|
||||||
|
|
||||||
|
Always use:
|
||||||
|
|
||||||
|
```
|
||||||
|
import data from "./file.json" with { type: "json" };
|
||||||
|
```
|
||||||
|
|
||||||
|
## Indentation
|
||||||
|
|
||||||
|
* Use **tabs** everywhere (no spaces).
|
||||||
|
* Nested JSON or object structures must use tabs for indentation.
|
||||||
|
|
||||||
|
|
||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## Project Structure & Modules
|
||||||
|
- `engine/`: core rendering engine (WebGL, deferred, PBR).
|
||||||
|
- `shaders/`: GLSL shader sources; `shaders/old/` contains legacy variants.
|
||||||
|
- `plugins/`: optional features and extensions (for example `plugins/ocean`).
|
||||||
|
- `demos/`, `start.html`, `index.html`: example entrypoints for running the engine.
|
||||||
|
- `media/`: textures, models, fonts, and screenshots used by demos.
|
||||||
|
- `server.js`: minimal static HTTP server for local development.
|
||||||
|
|
||||||
|
## Build, Run, and Development
|
||||||
|
- No build step is required; files are served as static assets.
|
||||||
|
- Run `node server.js` from the repo root to start the dev server on `http://localhost:4000`.
|
||||||
|
- Open `/start.html` or files under `/demos/` in your browser to exercise changes.
|
||||||
|
- Use ES modules (`type: "module"` in `package.json`) for new JavaScript files.
|
||||||
|
|
||||||
|
## Coding Style & Naming
|
||||||
|
- JavaScript only, using ES modules and `class` syntax where appropriate.
|
||||||
|
- Use camelCase for variables and functions, PascalCase for classes and render passes.
|
||||||
|
- Match existing indentation (tabs) and brace style in the surrounding file.
|
||||||
|
- Keep core engine logic in `engine/`, shaders in `shaders/`, and optional logic in `plugins/`.
|
||||||
|
|
||||||
|
## Testing & Validation
|
||||||
|
- There is no automated test runner yet; validate behavior through demos.
|
||||||
|
- Prefer creating small, focused demo pages under `demos/` (for example `demos/rough.htm`) for new features.
|
||||||
|
- Keep demos self-contained, quick to load, and clearly named after the feature they showcase.
|
||||||
|
|
||||||
|
## Commit & Pull Request Guidelines
|
||||||
|
- Write short, descriptive commit messages (for example `Fix SSAO sampling` or `Update README images`).
|
||||||
|
- Aim for one logical change per commit when practical.
|
||||||
|
- PRs should include a concise description, a list of affected areas, and screenshots or GIFs for visual or lighting changes.
|
||||||
|
- Link to any related issues and mention relevant demo URLs (such as `/demos/new.htm`) that reviewers can open.
|
||||||
|
|
||||||
|
## Agent-Specific Notes
|
||||||
|
- When changing rendering behavior, prefer adding or adjusting render passes under `engine/renderPasses/` instead of large monolithic edits.
|
||||||
|
- Avoid deleting existing demos or media assets; add new examples alongside current ones to preserve reference behavior.
|
||||||
|
|
||||||
@@ -5,21 +5,21 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import scene from './scene.js';
|
import scene from "./scene.js";
|
||||||
|
|
||||||
import shader from './shader.js';
|
import shader from "./shader.js";
|
||||||
|
|
||||||
import mesh from './mesh.js';
|
import mesh from "./mesh.js";
|
||||||
|
|
||||||
import material from './material.js';
|
import material from "./material.js";
|
||||||
|
|
||||||
import sampler2D from './sampler2D.js';
|
import sampler2D from "./sampler2D.js";
|
||||||
|
|
||||||
import entity from './entity.js';
|
import entity from "./entity.js";
|
||||||
|
|
||||||
import {matrix3, matrix4} from './math.js';
|
import {matrix3, matrix4} from "./math.js";
|
||||||
|
|
||||||
import boundingBox from './boundingBox.js';
|
import boundingBox from "./boundingBox.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Player object
|
* Player object
|
||||||
@@ -153,6 +153,14 @@ class assimp
|
|||||||
|
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
||||||
|
this.currentModelFile = jsonFilename;
|
||||||
|
|
||||||
|
if( typeof kepler !== "undefined" && kepler && kepler.resources ) {
|
||||||
|
|
||||||
|
kepler.resources.updateFilePreloaderProgress( this.name, 0, 0, false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
var data = this.loadTextFileSynchronous( this.baseUrl + this.modelPath + jsonFilename );
|
var data = this.loadTextFileSynchronous( this.baseUrl + this.modelPath + jsonFilename );
|
||||||
|
|
||||||
this.processFiles(data);
|
this.processFiles(data);
|
||||||
@@ -218,9 +226,13 @@ class assimp
|
|||||||
|
|
||||||
request.onprogress = callback = function (evt) {
|
request.onprogress = callback = function (evt) {
|
||||||
|
|
||||||
console.log("onupdate", evt);
|
if( typeof kepler !== "undefined" && kepler && kepler.resources && evt && evt.target && evt.target.assimp ) {
|
||||||
|
|
||||||
//kepler.loader.update( evt.target.responseURL, evt.loaded, evt.total );
|
var label = evt.target.assimp.name;
|
||||||
|
|
||||||
|
kepler.resources.updateFilePreloaderProgress( label, evt.loaded, evt.total, false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -232,6 +244,22 @@ class assimp
|
|||||||
this.assimp.filesToLoad.push({data: request.responseText, filename: request.responseURL });
|
this.assimp.filesToLoad.push({data: request.responseText, filename: request.responseURL });
|
||||||
//'this.assimp.filesToLoad.push(evt.responseText);
|
//'this.assimp.filesToLoad.push(evt.responseText);
|
||||||
|
|
||||||
|
if( typeof kepler !== "undefined" && kepler && kepler.resources && this.assimp ) {
|
||||||
|
|
||||||
|
var label = this.assimp.name;
|
||||||
|
|
||||||
|
var totalBytes = 0;
|
||||||
|
|
||||||
|
if( request.responseText ) {
|
||||||
|
|
||||||
|
totalBytes = request.responseText.length;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
kepler.resources.updateFilePreloaderProgress( label, totalBytes, totalBytes, true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,8 @@
|
|||||||
|
|
||||||
this.assimpLoader = new assimp();
|
this.assimpLoader = new assimp();
|
||||||
|
|
||||||
|
this.preloaderCleared = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addViewport(viewport){
|
addViewport(viewport){
|
||||||
@@ -142,9 +144,18 @@
|
|||||||
*/
|
*/
|
||||||
tick() {
|
tick() {
|
||||||
|
|
||||||
|
if( this.preloaderCleared === false && this.resources ) {
|
||||||
|
|
||||||
|
this.resources.hidePreloader( );
|
||||||
|
|
||||||
|
this.preloaderCleared = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
requestAnimFrame( this.tick.bind( this ) );
|
requestAnimFrame( this.tick.bind( this ) );
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,8 +8,9 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
import programInfo from './programInfo.js';
|
import programInfo from "./programInfo.js";
|
||||||
import {vector2, vector3} from './math.js';
|
|
||||||
|
import {vector2, vector3} from "./math.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,26 +20,51 @@ import {vector2, vector3} from './math.js';
|
|||||||
class resourceManager{
|
class resourceManager{
|
||||||
|
|
||||||
constructor( engine ) {
|
constructor( engine ) {
|
||||||
|
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
|
||||||
this.gl = engine.gl;
|
this.gl = engine.gl;
|
||||||
|
|
||||||
this.baseUrl = "";
|
this.baseUrl = "";
|
||||||
|
|
||||||
this.directory = "media/textures/";
|
this.directory = "media/textures/";
|
||||||
|
|
||||||
|
|
||||||
this.numberOfModels = 0;
|
this.numberOfModels = 0;
|
||||||
|
|
||||||
this.numberOfTextures = 0;
|
this.numberOfTextures = 0;
|
||||||
|
|
||||||
this.textureTotal = 0;
|
this.textureTotal = 0;
|
||||||
|
|
||||||
this.textures = [];
|
this.textures = new Array();
|
||||||
this.models = [];
|
|
||||||
this.shaders = [];
|
|
||||||
|
|
||||||
this.finishCallback;
|
this.models = new Array();
|
||||||
this.loadingList = [];
|
|
||||||
|
this.shaders = new Array();
|
||||||
|
|
||||||
|
this.finishCallback = null;
|
||||||
|
|
||||||
|
this.loadingList = new Array();
|
||||||
|
|
||||||
|
this.fileCache = new Array();
|
||||||
|
|
||||||
|
this.programCashe = new Array();
|
||||||
|
|
||||||
|
this.preloaderElement = null;
|
||||||
|
|
||||||
|
this.preloaderTextElement = null;
|
||||||
|
|
||||||
|
this.preloaderBarElement = null;
|
||||||
|
|
||||||
|
this.preloaderVisible = false;
|
||||||
|
|
||||||
|
this.fileLoading = false;
|
||||||
|
|
||||||
|
this.fileLoadedBytes = 0;
|
||||||
|
|
||||||
|
this.fileTotalBytes = 0;
|
||||||
|
|
||||||
|
this.fileLabel = "";
|
||||||
|
|
||||||
this.fileCache = [];
|
|
||||||
this.programCashe = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -320,6 +346,294 @@ import {vector2, vector3} from './math.js';
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
formatBytesToMegabytes( bytes ) {
|
||||||
|
|
||||||
|
if( bytes <= 0 ) {
|
||||||
|
|
||||||
|
return "0.00 MB";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var megabytes = bytes / ( 1024 * 1024 );
|
||||||
|
|
||||||
|
var rounded = Math.round( megabytes * 100 ) / 100;
|
||||||
|
|
||||||
|
var text = rounded.toFixed( 2 ) + " MB";
|
||||||
|
|
||||||
|
return text;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createPreloaderElements( ) {
|
||||||
|
|
||||||
|
if( this.preloaderElement !== null ) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var canvasElement = document.getElementById( "keplerEngine" );
|
||||||
|
|
||||||
|
var holder = document.createElement( "div" );
|
||||||
|
|
||||||
|
holder.className = "kepler-preloader-holder";
|
||||||
|
|
||||||
|
holder.style.position = "absolute";
|
||||||
|
|
||||||
|
holder.style.left = "0";
|
||||||
|
|
||||||
|
holder.style.top = "0";
|
||||||
|
|
||||||
|
holder.style.right = "0";
|
||||||
|
|
||||||
|
holder.style.bottom = "0";
|
||||||
|
|
||||||
|
holder.style.display = "flex";
|
||||||
|
|
||||||
|
holder.style.alignItems = "center";
|
||||||
|
|
||||||
|
holder.style.justifyContent = "center";
|
||||||
|
|
||||||
|
holder.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
||||||
|
|
||||||
|
var inner = document.createElement( "div" );
|
||||||
|
|
||||||
|
inner.className = "kepler-preloader-inner";
|
||||||
|
|
||||||
|
inner.style.minWidth = "200px";
|
||||||
|
|
||||||
|
inner.style.maxWidth = "400px";
|
||||||
|
|
||||||
|
inner.style.width = "60%";
|
||||||
|
|
||||||
|
inner.style.backgroundColor = "#202020";
|
||||||
|
|
||||||
|
inner.style.padding = "16px";
|
||||||
|
|
||||||
|
inner.style.boxSizing = "border-box";
|
||||||
|
|
||||||
|
inner.style.borderRadius = "4px";
|
||||||
|
|
||||||
|
var textElement = document.createElement( "div" );
|
||||||
|
|
||||||
|
textElement.className = "kepler-preloader-text";
|
||||||
|
|
||||||
|
textElement.style.color = "#ffffff";
|
||||||
|
|
||||||
|
textElement.style.fontFamily = "sans-serif";
|
||||||
|
|
||||||
|
textElement.style.fontSize = "14px";
|
||||||
|
|
||||||
|
textElement.style.marginBottom = "8px";
|
||||||
|
|
||||||
|
textElement.textContent = "Loading textures...";
|
||||||
|
|
||||||
|
var barOuter = document.createElement( "div" );
|
||||||
|
|
||||||
|
barOuter.className = "kepler-preloader-bar";
|
||||||
|
|
||||||
|
barOuter.style.width = "100%";
|
||||||
|
|
||||||
|
barOuter.style.height = "6px";
|
||||||
|
|
||||||
|
barOuter.style.backgroundColor = "#444444";
|
||||||
|
|
||||||
|
barOuter.style.overflow = "hidden";
|
||||||
|
|
||||||
|
var barInner = document.createElement( "div" );
|
||||||
|
|
||||||
|
barInner.className = "kepler-preloader-bar-inner";
|
||||||
|
|
||||||
|
barInner.style.width = "0%";
|
||||||
|
|
||||||
|
barInner.style.height = "100%";
|
||||||
|
|
||||||
|
barInner.style.backgroundColor = "#66ccff";
|
||||||
|
|
||||||
|
barOuter.appendChild( barInner );
|
||||||
|
|
||||||
|
inner.appendChild( textElement );
|
||||||
|
|
||||||
|
inner.appendChild( barOuter );
|
||||||
|
|
||||||
|
holder.appendChild( inner );
|
||||||
|
|
||||||
|
this.preloaderElement = holder;
|
||||||
|
|
||||||
|
this.preloaderTextElement = textElement;
|
||||||
|
|
||||||
|
this.preloaderBarElement = barInner;
|
||||||
|
|
||||||
|
if( canvasElement !== null && canvasElement.parentNode !== null ) {
|
||||||
|
|
||||||
|
canvasElement.parentNode.style.position = "relative";
|
||||||
|
|
||||||
|
canvasElement.parentNode.appendChild( holder );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
document.body.appendChild( holder );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
showPreloaderIfNeeded( ) {
|
||||||
|
|
||||||
|
if( this.preloaderVisible ) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.createPreloaderElements( );
|
||||||
|
|
||||||
|
if( this.preloaderElement !== null ) {
|
||||||
|
|
||||||
|
this.preloaderElement.style.display = "flex";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preloaderVisible = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updatePreloaderProgress( ) {
|
||||||
|
|
||||||
|
if( this.preloaderElement === null ) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this.textureTotal <= 0 ) {
|
||||||
|
|
||||||
|
if( this.fileTotalBytes <= 0 ) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var loaded = this.textureTotal - this.numberOfTextures;
|
||||||
|
|
||||||
|
if( loaded < 0 ) {
|
||||||
|
|
||||||
|
loaded = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( loaded > this.textureTotal ) {
|
||||||
|
|
||||||
|
loaded = this.textureTotal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var ratio = 0;
|
||||||
|
|
||||||
|
if( this.textureTotal > 0 ) {
|
||||||
|
|
||||||
|
ratio = loaded / this.textureTotal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var percentage = Math.round( ratio * 100 );
|
||||||
|
|
||||||
|
if( this.preloaderTextElement !== null ) {
|
||||||
|
|
||||||
|
var text = "Loading textures " + loaded + " / " + this.textureTotal;
|
||||||
|
|
||||||
|
if( this.fileLoading && this.fileTotalBytes > 0 ) {
|
||||||
|
|
||||||
|
var label = this.fileLabel;
|
||||||
|
|
||||||
|
if( label === "" ) {
|
||||||
|
|
||||||
|
label = "model";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadedText = this.formatBytesToMegabytes( this.fileLoadedBytes );
|
||||||
|
|
||||||
|
var totalText = this.formatBytesToMegabytes( this.fileTotalBytes );
|
||||||
|
|
||||||
|
text = "Loading model " + label + " " + loadedText + " / " + totalText + " | " + text;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preloaderTextElement.textContent = text;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this.preloaderBarElement !== null ) {
|
||||||
|
|
||||||
|
this.preloaderBarElement.style.width = percentage + "%";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hidePreloader( ) {
|
||||||
|
|
||||||
|
if( this.preloaderElement === null ) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preloaderElement.style.display = "none";
|
||||||
|
|
||||||
|
this.preloaderVisible = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateFilePreloaderProgress( label, loadedBytes, totalBytes, done ) {
|
||||||
|
|
||||||
|
if( done ) {
|
||||||
|
|
||||||
|
this.fileLoading = false;
|
||||||
|
|
||||||
|
this.fileLabel = "";
|
||||||
|
|
||||||
|
this.fileLoadedBytes = 0;
|
||||||
|
|
||||||
|
this.fileTotalBytes = 0;
|
||||||
|
|
||||||
|
if( this.textureTotal <= 0 ) {
|
||||||
|
|
||||||
|
this.hidePreloader( );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.updatePreloaderProgress( );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.fileLoading = true;
|
||||||
|
|
||||||
|
this.fileLabel = label;
|
||||||
|
|
||||||
|
this.fileLoadedBytes = loadedBytes;
|
||||||
|
|
||||||
|
this.fileTotalBytes = totalBytes;
|
||||||
|
|
||||||
|
this.showPreloaderIfNeeded( );
|
||||||
|
|
||||||
|
this.updatePreloaderProgress( );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Texture
|
* Add Texture
|
||||||
* @param {string} address
|
* @param {string} address
|
||||||
@@ -329,18 +643,29 @@ import {vector2, vector3} from './math.js';
|
|||||||
addTexture(adress, name, direct) {
|
addTexture(adress, name, direct) {
|
||||||
|
|
||||||
this.numberOfTextures++;
|
this.numberOfTextures++;
|
||||||
|
|
||||||
this.textureTotal++;
|
this.textureTotal++;
|
||||||
|
|
||||||
|
this.showPreloaderIfNeeded( );
|
||||||
|
|
||||||
|
this.updatePreloaderProgress( );
|
||||||
|
|
||||||
var texture = {};
|
var texture = {};
|
||||||
|
|
||||||
texture.adress = adress;
|
texture.adress = adress;
|
||||||
|
|
||||||
texture.name = name;
|
texture.name = name;
|
||||||
|
|
||||||
texture.loaded = false;
|
texture.loaded = false;
|
||||||
|
|
||||||
this.loadingList.push(texture);
|
this.loadingList.push( texture );
|
||||||
|
|
||||||
|
if( direct ) {
|
||||||
|
|
||||||
|
this.loadNextTexture( adress, name );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if(direct)
|
|
||||||
this.loadNextTexture(adress, name);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -420,6 +745,13 @@ import {vector2, vector3} from './math.js';
|
|||||||
image.onerror = function (a) {
|
image.onerror = function (a) {
|
||||||
|
|
||||||
this.engine.resources.loadNextTexture();
|
this.engine.resources.loadNextTexture();
|
||||||
|
|
||||||
|
if( this.engine.resources.textureTotal > 0 ) {
|
||||||
|
|
||||||
|
this.engine.resources.textureTotal--;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
this.engine.resources.CheckIfAllObjectsTexturesLoaded();
|
this.engine.resources.CheckIfAllObjectsTexturesLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,23 +782,43 @@ import {vector2, vector3} from './math.js';
|
|||||||
*/
|
*/
|
||||||
getTexture( name ) {
|
getTexture( name ) {
|
||||||
|
|
||||||
if(this.hasExtension(name)) {
|
var index;
|
||||||
|
|
||||||
|
for( index = 0; index < this.textures.length; index++ ) {
|
||||||
|
|
||||||
|
if( this.textures[ index ].name === name ) {
|
||||||
|
|
||||||
|
return this.textures[ index ];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for( index = 0; index < this.loadingList.length; index++ ) {
|
||||||
|
|
||||||
|
if( this.loadingList[ index ].name === name ) {
|
||||||
|
|
||||||
|
return this.loadingList[ index ];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this.hasExtension( name ) ) {
|
||||||
|
|
||||||
var url = name;
|
var url = name;
|
||||||
|
|
||||||
this.addTexture(this.directory + url, name);
|
this.addTexture( this.directory + url, name );
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for(var c = 0;c<this.loadingList.length; c++) {
|
|
||||||
if(this.loadingList[c].name == name){
|
|
||||||
|
|
||||||
return this.loadingList[c];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( index = 0; index < this.loadingList.length; index++ ) {
|
||||||
|
|
||||||
|
if( this.loadingList[ index ].name === name ) {
|
||||||
|
|
||||||
|
return this.loadingList[ index ];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,10 +851,17 @@ import {vector2, vector3} from './math.js';
|
|||||||
* Check if all objects are loaded
|
* Check if all objects are loaded
|
||||||
*/
|
*/
|
||||||
CheckIfAllObjectsTexturesLoaded() {
|
CheckIfAllObjectsTexturesLoaded() {
|
||||||
|
|
||||||
this.numberOfTextures--;
|
this.numberOfTextures--;
|
||||||
|
|
||||||
if( this.numberOfTextures == 0 ) {
|
this.updatePreloaderProgress( );
|
||||||
|
|
||||||
|
if( this.numberOfTextures === 0 ) {
|
||||||
|
|
||||||
|
this.hidePreloader( );
|
||||||
|
|
||||||
this.finishCallback();
|
this.finishCallback();
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -735,4 +1094,3 @@ var randomImage2 = new Uint8Array ( [149,123,253,255, 126,3,96,255, 164,246,
|
|||||||
52,83,220,255, 1,142,142,255, 32,57,79,255, 48,159,32,255,
|
52,83,220,255, 1,142,142,255, 32,57,79,255, 48,159,32,255,
|
||||||
56,232,114,255, 177,216,203,255, 69,196,217,255, 240,165,81,255,
|
56,232,114,255, 177,216,203,255, 69,196,217,255, 240,165,81,255,
|
||||||
224,56,85,255, 232,89,189,255, 143,25,202,255, 117,73,12,255] );
|
224,56,85,255, 232,89,189,255, 143,25,202,255, 117,73,12,255] );
|
||||||
|
|
||||||
|
|||||||
@@ -5,36 +5,38 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import texture from "./texture.js";
|
||||||
import texture from './texture.js';
|
import { math } from "./math.js";
|
||||||
import {math} from './math.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sampler2D
|
* Sampler2D
|
||||||
**/
|
**/
|
||||||
class sampler2D{
|
class sampler2D {
|
||||||
|
|
||||||
constructor( ){
|
constructor ( ) {
|
||||||
|
|
||||||
this.texture;
|
this.texture = null;
|
||||||
|
|
||||||
this.id = ++kepler.samplerId;
|
this.id = ++kepler.samplerId;
|
||||||
|
|
||||||
this.alpha = 1.0;
|
this.alpha = 1.0;
|
||||||
|
|
||||||
this.binded = false;
|
this.binded = false;
|
||||||
|
|
||||||
this.anisotropic = false;
|
this.anisotropic = false;
|
||||||
|
|
||||||
|
// If true, do not generate mipmaps (reduces normal-map shimmer)
|
||||||
|
this.isNormalMap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setViewport( viewport ){
|
setViewport ( viewport ) {
|
||||||
|
|
||||||
this.viewport = viewport;
|
this.viewport = viewport;
|
||||||
this.gl = viewport.gl;
|
this.gl = viewport.gl;
|
||||||
|
|
||||||
this.FLIP_Y = true;
|
this.FLIP_Y = true;
|
||||||
this.filter = this.gl.NEAREST;
|
|
||||||
this.filter = this.gl.LINEAR;
|
this.filter = this.gl.LINEAR;
|
||||||
|
|
||||||
this.MIN_FILTER = this.gl.LINEAR;
|
this.MIN_FILTER = this.gl.LINEAR;
|
||||||
@@ -50,11 +52,9 @@ class sampler2D{
|
|||||||
this.target = this.gl.TEXTURE_2D;
|
this.target = this.gl.TEXTURE_2D;
|
||||||
|
|
||||||
this.type = this.gl.FLOAT;
|
this.type = this.gl.FLOAT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTarget( viewport ) {
|
setTarget ( viewport ) {
|
||||||
|
|
||||||
|
|
||||||
var textureObject = new texture();
|
var textureObject = new texture();
|
||||||
|
|
||||||
@@ -63,128 +63,244 @@ class sampler2D{
|
|||||||
this.addTexture( textureObject );
|
this.addTexture( textureObject );
|
||||||
}
|
}
|
||||||
|
|
||||||
getTexture( face ) {
|
getTexture ( face ) {
|
||||||
|
|
||||||
return this.texture;
|
return this.texture;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTextures( ) {
|
getTextures ( ) {
|
||||||
return [this.texture];
|
|
||||||
|
return [ this.texture ];
|
||||||
}
|
}
|
||||||
|
|
||||||
addTexture( textureObject ) {
|
addTexture ( textureObject ) {
|
||||||
|
|
||||||
this.texture = textureObject;
|
this.texture = textureObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
setType(type) {
|
setType ( type ) {
|
||||||
|
|
||||||
//this.texture.type = "type";
|
|
||||||
|
|
||||||
|
// this.texture.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAsNormalMap ( ) {
|
||||||
|
|
||||||
|
this.isNormalMap = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bind sampler to shader
|
* bind sampler to shader
|
||||||
* @param {(shader)} shader
|
* @param {(shader)} shader
|
||||||
**/
|
**/
|
||||||
bind(shader) {
|
bind ( shader ) {
|
||||||
|
|
||||||
var txt = this.texture;
|
var txt = this.texture;
|
||||||
var data = this.texture.data;
|
var data = this.texture.data;
|
||||||
var type = txt.dataType;
|
var type = txt.dataType;
|
||||||
var gl = this.gl;
|
var gl = this.gl;
|
||||||
//this.type = type;
|
|
||||||
|
|
||||||
|
if ( type == "framebuffer" ) {
|
||||||
|
|
||||||
|
// Preserve your original behaviour:
|
||||||
if (type == "framebuffer" ) {
|
// framebuffer "data" is already a GL texture handle
|
||||||
|
|
||||||
this.texture.glTexture = this.texture.data;
|
this.texture.glTexture = this.texture.data;
|
||||||
type = txt.type;
|
|
||||||
|
// Continue as if it is a normal GL texture object (no texImage2D)
|
||||||
|
// NOTE: do NOT change filtering/mips logic here beyond safe defaults.
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var mips = [];
|
|
||||||
var width = txt.width;
|
var width = txt.width;
|
||||||
var height = txt.height;
|
var height = txt.height;
|
||||||
|
|
||||||
//if(!this.binded)
|
// Always assign sampler slot like you did
|
||||||
this.id = 1 + shader.samplerId++;
|
this.id = 1 + shader.samplerId++;
|
||||||
|
|
||||||
|
gl.activeTexture( gl.TEXTURE0 + this.id );
|
||||||
|
|
||||||
gl.activeTexture(gl.TEXTURE0 + this.id);
|
gl.enable( this.gl.BLEND );
|
||||||
|
gl.bindTexture( gl.TEXTURE_2D, txt.glTexture );
|
||||||
|
gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, this.FLIP_Y );
|
||||||
|
|
||||||
gl.enable ( this.gl.BLEND ) ;
|
// serialize txt data type
|
||||||
gl.bindTexture(gl.TEXTURE_2D, txt.glTexture );
|
switch ( type ) {
|
||||||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.FLIP_Y);
|
|
||||||
|
|
||||||
//serialize txt data type
|
|
||||||
switch( type ) {
|
|
||||||
case "float":
|
case "float":
|
||||||
|
{
|
||||||
this.type = this.gl.FLOAT;
|
this.type = this.gl.FLOAT;
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, kepler.extensions.EXT_sRGB , width, height, 0, this.internalFormat, this.type, data);
|
|
||||||
break;
|
|
||||||
case "int":
|
|
||||||
this.type = this.gl.UNSIGNED_BYTE;
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.internalFormat, this.type, data);
|
|
||||||
break;
|
|
||||||
case "depth":
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, width, height, 0, this.gl.DEPTH_COMPONENT, this.gl.UNSIGNED_SHORT, null);
|
|
||||||
break;
|
|
||||||
case "image":
|
|
||||||
this.type = this.gl.UNSIGNED_BYTE;
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.internalFormat,this.type, data);
|
|
||||||
break;
|
|
||||||
case "canvas":
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.internalFormat, this.UNSIGNED_BYTE, data);
|
|
||||||
break;
|
|
||||||
case "COMPRESSED_RGBA":
|
|
||||||
|
|
||||||
//var textureCompression = kepler.extensions.textureCompression;
|
// WebGL2 prefers sized internal formats for float textures.
|
||||||
|
// Keep fallback to gl.RGBA for compatibility if RGBA32F is not present.
|
||||||
|
var internal = gl.RGBA32F ? gl.RGBA32F : gl.RGBA;
|
||||||
|
|
||||||
|
gl.texImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
internal,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
this.internalFormat,
|
||||||
|
this.type,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "int":
|
||||||
|
{
|
||||||
|
this.type = this.gl.UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
gl.texImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
this.format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
this.internalFormat,
|
||||||
|
this.type,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "depth":
|
||||||
|
{
|
||||||
|
gl.texImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
this.gl.DEPTH_COMPONENT,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
this.gl.DEPTH_COMPONENT,
|
||||||
|
this.gl.UNSIGNED_SHORT,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "image":
|
||||||
|
{
|
||||||
|
this.type = this.gl.UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
// Keep your original call shape (works because format == internalFormat == RGBA)
|
||||||
|
gl.texImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
this.format,
|
||||||
|
this.internalFormat,
|
||||||
|
this.type,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "canvas":
|
||||||
|
{
|
||||||
|
gl.texImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
this.format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
this.internalFormat,
|
||||||
|
this.UNSIGNED_BYTE,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "COMPRESSED_RGBA":
|
||||||
|
{
|
||||||
var mipmaps = txt.mipmaps;
|
var mipmaps = txt.mipmaps;
|
||||||
|
|
||||||
var width = mipmaps[0].width;
|
for ( var i = 0; i < mipmaps.length; i++ ) {
|
||||||
var height = mipmaps[0].height;
|
|
||||||
|
|
||||||
for(var i = 0; i < mipmaps.length; i++) {
|
|
||||||
var mipmap = mipmaps[i];
|
var mipmap = mipmaps[i];
|
||||||
|
|
||||||
gl.compressedTexImage2D(gl.TEXTURE_2D, i, mipmap.internalFormat, mipmap.width, mipmap.height, 0, mipmap.byteArray);
|
gl.compressedTexImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
i,
|
||||||
|
mipmap.internalFormat,
|
||||||
|
mipmap.width,
|
||||||
|
mipmap.height,
|
||||||
|
0,
|
||||||
|
mipmap.byteArray
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Anisotropy kept as in your original (disabled)
|
||||||
|
if ( this.anisotropic ) {
|
||||||
|
|
||||||
if(this.anisotropic) {
|
// var extension = kepler.extensions.anisotropic;
|
||||||
|
// gl.texParameteri( this.gl.TEXTURE_2D, extension.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic );
|
||||||
//var extension = kepler.extensions.anisotropic;
|
|
||||||
//gl.texParameteri( this.gl.TEXTURE_2D, extension.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POT logic (this is where we apply the safe normal-map fix)
|
||||||
|
if ( math.isPowerOfTwo( width ) && math.isPowerOfTwo( height ) ) {
|
||||||
|
|
||||||
if (math.isPowerOfTwo(width) && math.isPowerOfTwo(height) ) {
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR );
|
||||||
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
if ( this.isNormalMap ) {
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);// mipmaps > 1 ? this.gl.LINEAR_MIPMAP_LINEAR : this.gl.LINEAR
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.WRAP_S);
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.WRAP_T);
|
|
||||||
|
|
||||||
if(this.type != this.gl.FLOAT)
|
// Safe fix: do not use mipmaps for normal maps
|
||||||
gl.generateMipmap(gl.TEXTURE_2D);
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR );
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR );
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
|
if ( this.type != this.gl.FLOAT ) {
|
||||||
|
|
||||||
|
gl.generateMipmap( gl.TEXTURE_2D );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.WRAP_S );
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.WRAP_T );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR );
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE );
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE );
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.bindTexture( gl.TEXTURE_2D, null );
|
||||||
|
|
||||||
|
this.binded = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// framebuffer path: bind the already-created GL texture handle
|
||||||
|
// and apply basic sampling state without re-upload.
|
||||||
|
{
|
||||||
|
var width_fb = txt.width;
|
||||||
|
var height_fb = txt.height;
|
||||||
|
|
||||||
|
this.id = 1 + shader.samplerId++;
|
||||||
|
|
||||||
|
gl.activeTexture( gl.TEXTURE0 + this.id );
|
||||||
|
gl.bindTexture( gl.TEXTURE_2D, txt.glTexture );
|
||||||
|
|
||||||
|
// Clamp + linear for attachments (safe default)
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
|
||||||
|
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
|
||||||
|
|
||||||
|
gl.bindTexture( gl.TEXTURE_2D, null );
|
||||||
|
|
||||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
||||||
this.binded = true;
|
this.binded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export {sampler2D as default};
|
|
||||||
|
export { sampler2D as default };
|
||||||
|
|||||||
@@ -147,11 +147,13 @@
|
|||||||
var groundMaterial = new material();
|
var groundMaterial = new material();
|
||||||
|
|
||||||
// Samplers
|
// Samplers
|
||||||
var normalTexture = kepler.resources.getTexture("0_floorTiles_ddn.png");
|
var normalTexture = kepler.resources.getTexture("pbr-512/pavingStones/PavingStones046_2K-JPG_NormalGL.jpg");
|
||||||
var normalSampler = new sampler2D();
|
var normalSampler = new sampler2D();
|
||||||
normalSampler.addTexture(normalTexture);
|
normalSampler.addTexture(normalTexture);
|
||||||
|
normalSampler.setAsNormalMap();
|
||||||
|
|
||||||
var diffuseTexture = kepler.resources.getTexture("0_floorTiles_diff.png");
|
|
||||||
|
var diffuseTexture = kepler.resources.getTexture("pbr-512/pavingStones/PavingStones046_2K-JPG_Color.jpg");
|
||||||
var diffuseSampler = new sampler2D();
|
var diffuseSampler = new sampler2D();
|
||||||
diffuseSampler.addTexture(diffuseTexture);
|
diffuseSampler.addTexture(diffuseTexture);
|
||||||
|
|
||||||
|
|||||||
BIN
media/textures/pbr-512/pavingStones/PavingStones046.png
Normal file
|
After Width: | Height: | Size: 380 KiB |
BIN
media/textures/pbr-512/pavingStones/PavingStones046_2K-JPG.blend
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<materialx version="1.39" fileprefix="./">
|
||||||
|
<open_pbr_surface type="surfaceshader" ypos="-1.879310" name="PavingStones046_2K_JPG_OpenPbrSurface" xpos="6.159420">
|
||||||
|
<input type="color3" name="base_color" nodename="PavingStones046_2K_JPG_Color" />
|
||||||
|
<input type="vector3" name="geometry_normal" nodename="NormalMap" />
|
||||||
|
<input type="float" name="specular_roughness" nodename="PavingStones046_2K_JPG_Roughness" />
|
||||||
|
</open_pbr_surface>
|
||||||
|
<surfacematerial type="material" ypos="0.000000" name="PavingStones046_2K_JPG" xpos="8.695652">
|
||||||
|
<input type="surfaceshader" name="surfaceshader" nodename="PavingStones046_2K_JPG_OpenPbrSurface" />
|
||||||
|
<input type="displacementshader" name="displacementshader" nodename="displacement" />
|
||||||
|
</surfacematerial>
|
||||||
|
<tiledimage type="color3" ypos="-3.103448" name="PavingStones046_2K_JPG_Color" xpos="3.623188">
|
||||||
|
<input type="filename" name="file" colorspace="srgb_texture" value="PavingStones046_2K-JPG_Color.jpg" />
|
||||||
|
<input type="vector2" name="uvtiling" value="1.0, 1.0" />
|
||||||
|
</tiledimage>
|
||||||
|
<tiledimage type="float" ypos="5.163793" name="PavingStones046_2K_JPG_Displacement" xpos="3.623188">
|
||||||
|
<input type="filename" name="file" value="PavingStones046_2K-JPG_Displacement.jpg" />
|
||||||
|
<input type="vector2" name="uvtiling" value="1.0, 1.0" />
|
||||||
|
</tiledimage>
|
||||||
|
<displacement type="displacementshader" ypos="1.879310" name="displacement" xpos="6.159420">
|
||||||
|
<input type="float" name="displacement" nodename="PavingStones046_2K_JPG_Displacement" />
|
||||||
|
<input type="float" name="scale" value="1.0" />
|
||||||
|
</displacement>
|
||||||
|
<tiledimage type="vector3" ypos="0.879310" name="PavingStones046_2K_JPG_NormalGL" xpos="1.086957">
|
||||||
|
<input type="filename" name="file" value="PavingStones046_2K-JPG_NormalGL.jpg" />
|
||||||
|
<input type="vector2" name="uvtiling" value="1.0, 1.0" />
|
||||||
|
</tiledimage>
|
||||||
|
<normalmap type="vector3" ypos="3.586207" name="NormalMap" xpos="3.623188">
|
||||||
|
<input type="vector3" name="in" nodename="PavingStones046_2K_JPG_NormalGL" />
|
||||||
|
<input type="float" name="scale" value="1.0" />
|
||||||
|
</normalmap>
|
||||||
|
<tiledimage type="float" ypos="-0.413793" name="PavingStones046_2K_JPG_Roughness" xpos="3.623188">
|
||||||
|
<input type="filename" name="file" value="PavingStones046_2K-JPG_Roughness.jpg" />
|
||||||
|
<input type="vector2" name="uvtiling" value="1.0, 1.0" />
|
||||||
|
</tiledimage>
|
||||||
|
</materialx>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="StandardMaterial3D" load_steps=6 format=3 uid="acg_0wl6yudb"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://acg_qwdu613c" id="Color" path="./PavingStones046_2K-JPG_Color.jpg"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://acg_l5d9bi73" id="AmbientOcclusion" path="./PavingStones046_2K-JPG_AmbientOcclusion.jpg"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://acg_ad0vlmbp" id="Displacement" path="./PavingStones046_2K-JPG_Displacement.jpg"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://acg_iu7w0s8l" id="Roughness" path="./PavingStones046_2K-JPG_Roughness.jpg"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://acg_nby48io6" id="NormalGL" path="./PavingStones046_2K-JPG_NormalGL.jpg"]
|
||||||
|
[resource]
|
||||||
|
albedo_texture = ExtResource("Color")
|
||||||
|
ao_enabled = true
|
||||||
|
ao_texture = ExtResource("AmbientOcclusion")
|
||||||
|
ao_texture_channel = 4
|
||||||
|
roughness_texture = ExtResource("Roughness")
|
||||||
|
roughness_texture_channel = 4
|
||||||
|
normal_texture = ExtResource("NormalGL")
|
||||||
|
normal_enabled = true
|
||||||
|
heightmap_texture = ExtResource("Displacement")
|
||||||
|
heightmap_scale = 1.0
|
||||||
|
heightmap_enabled = true
|
||||||
BIN
media/textures/pbr-512/pavingStones/PavingStones046_2K-JPG.usdc
Normal file
BIN
media/textures/pbr-512/pavingStones/PavingStones046_2K-JPG.zip
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 8.7 MiB |
|
After Width: | Height: | Size: 8.7 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
@@ -455,14 +455,45 @@
|
|||||||
#if NORMAL_MAP == 1
|
#if NORMAL_MAP == 1
|
||||||
|
|
||||||
vec4 normalMap = texture(normalSampler, textureCoordinate * uvMultiplier) * 2.0 - 1.0;
|
vec4 normalMap = texture(normalSampler, textureCoordinate * uvMultiplier) * 2.0 - 1.0;
|
||||||
normal = normalize((v_tangent.xyz * normalMap.x) + (v_binormal.xyz * normalMap.y) + (v_normal.xyz * normalMap.z));
|
//normal = normalize((v_tangent.xyz * normalMap.x) + (v_binormal.xyz * normalMap.y) + (v_normal.xyz * normalMap.z));
|
||||||
|
|
||||||
mat3 tangentToWorld = transpose(mat3( v_tangent.xyz ,
|
mat3 tangentToWorld = transpose(mat3( v_tangent.xyz ,
|
||||||
v_binormal.xyz ,
|
v_binormal.xyz ,
|
||||||
v_normal.xyz));
|
v_normal.xyz));
|
||||||
|
|
||||||
|
|
||||||
normal = normalMap.xyz * tangentToWorld;
|
//normal = normalMap.xyz * tangentToWorld;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec2 uv = textureCoordinate * uvMultiplier;
|
||||||
|
|
||||||
|
vec2 dUVdx = dFdx(uv);
|
||||||
|
vec2 dUVdy = dFdy(uv);
|
||||||
|
|
||||||
|
vec3 nm = textureGrad(normalSampler, uv, dUVdx, dUVdy).xyz * 2.0 - 1.0;
|
||||||
|
nm = normalize(nm);
|
||||||
|
|
||||||
|
nm = normalize(nm);
|
||||||
|
|
||||||
|
vec3 N = normalize(v_normal.xyz);
|
||||||
|
vec3 T = normalize(v_tangent.xyz);
|
||||||
|
T = normalize(T - N * dot(N, T));
|
||||||
|
vec3 B = normalize(cross(N, T));
|
||||||
|
|
||||||
|
mat3 TBN = mat3(T, B, N);
|
||||||
|
normal = normalize(TBN * nm);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
normal = v_normal.xyz;
|
normal = v_normal.xyz;
|
||||||
@@ -543,7 +574,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
float gamma = 1.4;
|
float gamma = 2.2;
|
||||||
|
|
||||||
vec3 baseColor;
|
vec3 baseColor;
|
||||||
vec4 diffuseMap;
|
vec4 diffuseMap;
|
||||||
@@ -570,6 +601,24 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if NORMAL_MAP == 1
|
||||||
|
|
||||||
|
// Screen-space normal variation (specular AA)
|
||||||
|
vec3 n_dx = dFdx(normal);
|
||||||
|
vec3 n_dy = dFdy(normal);
|
||||||
|
|
||||||
|
float variance = max(dot(n_dx, n_dx), dot(n_dy, n_dy));
|
||||||
|
|
||||||
|
// UE-style mapping: converts variance to roughness increase
|
||||||
|
float kernelRoughness = clamp(variance * 0.25, 0.0, 1.0);
|
||||||
|
|
||||||
|
// Combine with material roughness
|
||||||
|
f_roughness = sqrt(clamp(f_roughness * f_roughness + kernelRoughness, 0.0, 1.0));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
vec3 diffuse = baseColor ;
|
vec3 diffuse = baseColor ;
|
||||||
//
|
//
|
||||||
|
|
||||||
@@ -579,7 +628,7 @@
|
|||||||
float reflectance = v_reflectance / 2.0;
|
float reflectance = v_reflectance / 2.0;
|
||||||
|
|
||||||
|
|
||||||
vec3 viewDir = (cameraPosition - v_worldposition.xyz);
|
vec3 viewDir = normalize(cameraPosition - v_worldposition.xyz);
|
||||||
vec3 reflectionVector = reflect(-viewDir.xyz, normalize(normal.xyz));
|
vec3 reflectionVector = reflect(-viewDir.xyz, normalize(normal.xyz));
|
||||||
vec3 reflectionSample = sampleReflection( reflectionVector );
|
vec3 reflectionSample = sampleReflection( reflectionVector );
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ vec3 fixCubemapLookup(vec3 v, float lod) {
|
|||||||
|
|
||||||
|
|
||||||
vec3 evaluateSpecularIBL(vec3 r, float roughness) {
|
vec3 evaluateSpecularIBL(vec3 r, float roughness) {
|
||||||
float lod = 5.0 * roughness;
|
float lod = clamp(5.0 * roughness, 0.0, 8.0);
|
||||||
|
|
||||||
r = fixCubemapLookup(r, lod);
|
r = fixCubemapLookup(r, lod);
|
||||||
|
|
||||||
@@ -165,91 +165,81 @@ vec3 getSpecularDominantDirection(vec3 n, vec3 r, float roughness) {
|
|||||||
float s = 1.0 - roughness;
|
float s = 1.0 - roughness;
|
||||||
return mix(n, r, s * (sqrt(s) + roughness));
|
return mix(n, r, s * (sqrt(s) + roughness));
|
||||||
}
|
}
|
||||||
|
vec3 indirectLight( deferredMaterialData materialData ) {
|
||||||
|
|
||||||
vec3 indirectLight( deferredMaterialData materialData ) { //, deferredLightData materialData
|
|
||||||
|
|
||||||
vec3 normal = materialData.normal;
|
vec3 normal = materialData.normal;
|
||||||
vec3 vertex = materialData.vertex;
|
vec3 vertex = materialData.vertex;
|
||||||
|
|
||||||
|
float roughness = clamp( materialData.roughness, 0.0, 1.0 );
|
||||||
|
|
||||||
float roughness = materialData.roughness;
|
float NoV = max( dot( normal, vertex ), 0.0 );
|
||||||
|
|
||||||
float NoV = max( dot(normal, vertex), 0.0 );
|
|
||||||
|
|
||||||
#if ANISOTROPY == 1
|
#if ANISOTROPY == 1
|
||||||
vec3 t = normalize( materialData.tangent );
|
vec3 t = normalize( materialData.tangent );
|
||||||
vec3 b = normalize( cross(t, normal));
|
vec3 b = normalize( cross( t, normal ) );
|
||||||
|
|
||||||
vec3 anisotropicTangent = cross(-vertex, b);
|
vec3 anisotropicTangent = cross( -vertex, b );
|
||||||
vec3 anisotropicNormal = cross(anisotropicTangent, b);
|
vec3 anisotropicNormal = cross( anisotropicTangent, b );
|
||||||
vec3 bentNormal = normalize(mix(normal, anisotropicNormal, anisotropy));
|
vec3 bentNormal = normalize( mix( normal, anisotropicNormal, anisotropy ) );
|
||||||
|
|
||||||
vec3 r = reflect( vertex, bentNormal );
|
vec3 r = reflect( vertex, bentNormal );
|
||||||
#else
|
#else
|
||||||
vec3 r = reflect( -vertex, normal );
|
vec3 r = reflect( -vertex, normal );
|
||||||
r = getSpecularDominantDirection(normal, r, roughness * roughness);
|
|
||||||
|
// Use perceptual roughness here (not squared)
|
||||||
|
r = getSpecularDominantDirection( normal, r, roughness );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float NoR = max( dot(r, normal), 0.0);
|
float NoR = max( dot( r, normal ), 0.0 );
|
||||||
|
|
||||||
// specular indirect
|
// Specular indirect (USE r, not reflect(-vertex, normal) again)
|
||||||
vec3 indirectSpecular = evaluateSpecularIBL( reflect(vertex, normal), roughness);
|
vec3 indirectSpecular = evaluateSpecularIBL( r, roughness );
|
||||||
|
|
||||||
// horizon occlusion, can be removed for performance
|
// Optional but usually helps reduce “edge glitter” on grazing angles
|
||||||
//float horizon = min(1.0 + NoR, 1.0);
|
indirectSpecular *= clamp( 1.0 + NoR, 0.0, 1.0 );
|
||||||
//indirectSpecular *= horizon * horizon;
|
|
||||||
|
|
||||||
vec2 env = prefilteredDFGKaris( NoV, materialData.roughness );
|
vec2 env = prefilteredDFGKaris( NoV, roughness );
|
||||||
// we should multiply env.y by f90 for more accurate results
|
|
||||||
vec3 specularColor = materialData.specularReflectance * env.x + env.y * (1.0 - materialData.clearCoat) *
|
vec3 specularColor =
|
||||||
clamp(dot(materialData.specularReflectance, vec3(50.0 * 0.33)), 0.0, 1.0);
|
materialData.specularReflectance * env.x +
|
||||||
|
env.y * ( 1.0 - materialData.clearCoat ) *
|
||||||
|
clamp( dot( materialData.specularReflectance, vec3( 50.0 * 0.33 ) ), 0.0, 1.0 );
|
||||||
|
|
||||||
|
vec3 indirectDiffuse = max( irradianceSH( normal ), 0.0 ) * Fd_Lambert();
|
||||||
|
|
||||||
|
float ambientOcclusionFade = clamp( dot( normalize( normal ), vertex ), 0.0, 1.0 );
|
||||||
|
float ambientOcclusion = mix( 1.0, materialData.ambientOcclusion, ambientOcclusionFade );
|
||||||
|
|
||||||
// diffuse indirect
|
|
||||||
vec3 indirectDiffuse = max(irradianceSH(normal), 0.0) * Fd_Lambert();
|
|
||||||
// ambient occlusion
|
|
||||||
float ambientOcclusionFade = clamp(dot(normalize(normal), vertex), 0.0, 1.0);
|
|
||||||
float ambientOcclusion = mix(1.0, materialData.ambientOcclusion, ambientOcclusionFade);
|
|
||||||
indirectDiffuse *= ambientOcclusion;
|
indirectDiffuse *= ambientOcclusion;
|
||||||
//indirectDiffuse *= 4.0;
|
|
||||||
// TODO: Not really useful without SSambientOcclusion/HBambientOcclusion/etc.
|
|
||||||
indirectSpecular *= computeSpecularambientOcclusion(NoV, ambientOcclusion, materialData.roughness);
|
|
||||||
|
|
||||||
// clear coat
|
indirectSpecular *= computeSpecularambientOcclusion( NoV, ambientOcclusion, roughness );
|
||||||
float Fcc = F_Schlick_Scalar(NoV, 0.04, 1.0) * 0.2;
|
|
||||||
#if ANISOTROPY == 1
|
|
||||||
// We used the bent normal for the base layer
|
|
||||||
r = reflect(-vertex, normal);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
float Fcc = F_Schlick_Scalar( NoV, 0.04, 1.0 ) * 0.2;
|
||||||
|
|
||||||
vec3 indirectClearCoatSpecular = evaluateSpecularIBL(reflect(vertex, normal), materialData.clearCoatRoughness);
|
vec3 indirectClearCoatSpecular =
|
||||||
|
evaluateSpecularIBL( reflect( vertex, normal ), clamp( materialData.clearCoatRoughness, 0.0, 1.0 ) );
|
||||||
|
|
||||||
|
vec3 clearCoatAbsorption = mix(
|
||||||
|
vec3( 1.0 ),
|
||||||
|
beerLambert(
|
||||||
|
materialData.refracted_NoV,
|
||||||
|
materialData.refracted_NoV,
|
||||||
|
materialData.clearCoatColor,
|
||||||
|
materialData.clearCoatThickness
|
||||||
|
),
|
||||||
|
materialData.clearCoat
|
||||||
|
);
|
||||||
|
|
||||||
vec3 clearCoatAbsorption = mix(vec3(1.0),
|
|
||||||
beerLambert(materialData.refracted_NoV, materialData.refracted_NoV, materialData.clearCoatColor, materialData.clearCoatThickness),
|
|
||||||
materialData.clearCoat);
|
|
||||||
|
|
||||||
// indirect contribution (clear coat)
|
|
||||||
vec3 color =
|
vec3 color =
|
||||||
(materialData.diffuse * indirectDiffuse + indirectSpecular * specularColor)//kaj materialData.diffuse * indirectDiffuse
|
( materialData.diffuse * indirectDiffuse + indirectSpecular * specularColor ) *
|
||||||
* (1.0 - Fcc) * clearCoatAbsorption +
|
( 1.0 - Fcc ) * clearCoatAbsorption +
|
||||||
indirectClearCoatSpecular * Fcc;
|
indirectClearCoatSpecular * Fcc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if TRANSLUCENT_MATERIAL == 1
|
|
||||||
indirectDiffuse = max(irradianceSH(-vertex), 0.0) * Fd_Lambert();
|
|
||||||
vec3 tL = -vertex + normal * translucencyDistortion;
|
|
||||||
float tD = pow(clamp(dot(vertex, -tL), 0.0, 1.0), translucencyPower) * translucencyScale;
|
|
||||||
vec3 tT = (tD + translucencyAmbient) * texture(translucencyThicknessMap, outUV).r;
|
|
||||||
color.rgb += materialData.diffuse * indirectDiffuse * tT;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec3 getNormal(vec3 n) {
|
vec3 getNormal(vec3 n) {
|
||||||
|
|
||||||
return normalize(n);
|
return normalize(n);
|
||||||
@@ -271,6 +261,9 @@ vec3 directLight( deferredMaterialData materialData, deferredLightData lightData
|
|||||||
vec3 lightDir = normalize(lightData.direction);
|
vec3 lightDir = normalize(lightData.direction);
|
||||||
float linearRoughness = materialData.roughness * materialData.roughness;
|
float linearRoughness = materialData.roughness * materialData.roughness;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec3 r = reflect(-v, n);
|
vec3 r = reflect(-v, n);
|
||||||
|
|
||||||
if (lightType == 1.0) {
|
if (lightType == 1.0) {
|
||||||
@@ -327,6 +320,7 @@ vec3 directLight( deferredMaterialData materialData, deferredLightData lightData
|
|||||||
float D = D_GGX(NoH, linearRoughness);
|
float D = D_GGX(NoH, linearRoughness);
|
||||||
#endif
|
#endif
|
||||||
vec3 F = F_Schlick(LoH, materialData.specularReflectance, clamp(dot(materialData.specularReflectance, vec3(50.0 * 0.33)), 0.0, 1.0));
|
vec3 F = F_Schlick(LoH, materialData.specularReflectance, clamp(dot(materialData.specularReflectance, vec3(50.0 * 0.33)), 0.0, 1.0));
|
||||||
|
|
||||||
float V = V_SmithGGXCorrelated(NoV, NoL, linearRoughness);
|
float V = V_SmithGGXCorrelated(NoV, NoL, linearRoughness);
|
||||||
vec3 Fr = (D * V) * F;
|
vec3 Fr = (D * V) * F;
|
||||||
|
|
||||||
|
|||||||