
Kepler is a open source deferred, pbr based render engine written in Javascript.
Current features are:


#### Surface Normal

![Surface Normal](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/normal.png)

#### Positions

![Positions](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/position.png)

#### Diffuse Maps

![Diffuse Maps](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/diffuse.png)

---

### Screen Space Ambient Occlusion (SSAO)

![SSAO](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/ssao.png)

---

In the final render pass, all G-buffer data is combined and PBR lighting calculations are performed in parallel on the GPU, producing a photorealistic real-time image.

Real-time PBR enables interactive applications such as games and simulations to deliver high-fidelity visuals by leveraging modern GPU computational power.

![PBR lights without Diffuse](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/lightOnly.png)

---

## **Rendering Multiple Lights**

Deferred lighting efficiently renders many lights by processing geometry once into G-buffers, then computing lighting per light in screen space. This avoids redundant geometry rendering and limits lighting calculations to affected screen regions, significantly improving performance.

![Multiple Lights 1](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/4.png) ![Multiple Lights 2](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/3.png)

---


## **PBR Roughness Parameter**

**Roughness** controls the microsurface texture of a material, affecting reflection sharpness. It governs the spread and intensity of specular highlights, crucial for realistic PBR materials.

![PBR Roughness](https://code.kajdijkstra.com/kaj/Kepler/raw/branch/main/media/roughness_blue.png)

---


# Load models:
```javascript
import keplerEngine from './engine/kepler.js';
import sampler2D from './engine/sampler2D.js';
import viewport from './engine/viewport.js';

// Create raprtor engine instance
kepler = new keplerEngine();

// Create viewport to dom element width id keplerEngine
var ViewPort = new viewport("keplerEngine");

// Load 3d model
kepler.assimpLoader.load( "demo.json", ViewPort.scene );

// Add viewport
kepler.addViewport( ViewPort );

// Start application
kepler.application();

```



# Create primitives (Entity's, Materials, textures, samplers):
```javascript
import keplerEngine from './engine/kepler.js';
import entity from './engine/entity.js';
import material from './engine/material.js';
import sampler2D from './engine/sampler2D.js';
import mesh from './engine/mesh.js';
import viewport from './engine/viewport.js';

kepler = new keplerEngine();

// Viewport
var ViewPort = new viewport("keplerEngine");

// Material
var groundMaterial = new material();

// Create Normal Texture and Sampler
var normalTexture = kepler.resources.getTexture("floorTiles_normal.png");
var normalSampler = new sampler2D();
normalSampler.addTexture(normalTexture);

// Create Diffuse Texture and Sampler
var diffuseTexture = kepler.resources.getTexture("floorTiles_diff.png");
var diffuseSampler = new sampler2D();
diffuseSampler.addTexture(diffuseTexture);

// Add Samplers to Material
groundMaterial.addTexture(diffuseSampler);
groundMaterial.addNormal(normalSampler);

// Properties
groundMaterial.diffuseColor = [179.0 / 256.0, 199.0 / 256.0, 217.0 / 256.0];
groundMaterial.alpha = 1.0;
groundMaterial.reflection = 0.2;
groundMaterial.roughness = 0.3;
groundMaterial.metalic = 0.1;
groundMaterial.uvMultiplier = 6.0;

// Create cube mesh
var cubeMesh = ViewPort.primitives.createCube(10);
cubeMesh.addMaterial(groundMaterial);

// Create cube Entity
var cubeEntity = new entity( );
cubeEntity.addMesh( cubeMesh );
cubeEntity.name = "Cube";
cubeEntity.transform.position = [0, 10, 0];
cubeEntity.transform.update();

// Add cube entity to scene
ViewPort.scene.addEntity( cubeEntity );

// Start application
kepler.application();
```

# Renderpass:
```javascript
import defaultRenderPass from '../defaultRenderPass.js';
import sampler2D from '../sampler2D.js';
import shader from '../shader.js';

class tonemap extends defaultRenderPass {

	prepare() {

		var randomTexure = kepler.resources.getTexture("random.png");
		var randomSampler = new sampler2D();
		randomSampler.addTexture(randomTexure);
	
		this.shader = new shader();
		this.shader.createFromFile("shaders/tonemap.shader");
		
		// set uniforms like this
		this.shader.setUniform("exposure", 1.1 ); 
		this.shader.setUniform("exampleVector2", [1,1] );
		this.shader.setUniform("exampleVector3", [1,1,1] );
		this.shader.setUniform("randomSampler", randomSampler );
		
	}
	
}

export {tonemap as default};
```
In rendersytem.js in the method createRenderPasses add:
```javascript
import tonemap from './renderPasses/tonemap.js';

var tonemapPass	= new tonemap();

this.deferredRenderPipeline.addRenderpass( tonemapPass, "uber" );

//tonemapPass.renderToViewport = true; 
tonemapPass.shader.setUniform("colorSampler", uberPass.framebuffer.getSampler() );
```
## tonemap.shader
```glsl
    attribute vec3 position;
    attribute vec2 uv;
	
    uniform mat4 viewProjection;

    varying vec2 v_textureCoord;

    void main(void) {
	
        v_textureCoord = uv;
		gl_Position = viewProjection * vec4(position, 1.0);
		
    }
	
	// #keplerEngine - Split
	
	precision highp float;

	uniform sampler2D colorSampler;

	varying vec2 v_textureCoord;


	void main() {
		
		vec3 color = texture2D( colorSampler, v_textureCoord ).rgb;
	
		gl_FragColor = vec4( tonemap(color), 1.0 );
		
	}
```
