diff --git a/dist/reve/Makefile b/dist/reve/Makefile index 6c25db6..2e91eef 100644 --- a/dist/reve/Makefile +++ b/dist/reve/Makefile @@ -5,7 +5,7 @@ default: @echo No default target, please specify dist or clean. dist: REveRenderCore-min.mjs shaders - tar cf RenderCore.tar REveRenderCore-min.mjs shaders/ + tar cf RenderCore.tar ../../LICENSE REveRenderCore-min.mjs shaders/ gzip -9 RenderCore.tar sha256sum -b RenderCore.tar.gz @echo Now move the tarball to ROOT source and put the checksum into ROOT source tree diff --git a/dist/reve/program_names.json b/dist/reve/program_names.json index aca6d14..10a2ef1 100644 --- a/dist/reve/program_names.json +++ b/dist/reve/program_names.json @@ -9,6 +9,7 @@ "phong", "basic", "basic_zsprite", + "basic_zshape", "basic_stripes", "custom_GBufferMini_stripes", "custom_picker_TRIANGLES", diff --git a/examples/outlineExample/main-ZSprite.js b/examples/outlineExample/main-ZSprite.js index 653e2de..607f7de 100644 --- a/examples/outlineExample/main-ZSprite.js +++ b/examples/outlineExample/main-ZSprite.js @@ -126,6 +126,39 @@ const CoreControl = { ); this.tex_insta_pos.flipy = false; + + // AMT ZShape pos + // Instancing, passing position for each instance in RGBA32F texture, A not used. + let sna = 2; + let SN = sna * sna * sna; + let sarr = new Float32Array(SN * 4); + { + let off = 0; + for (let i = 0; i < sna; ++i) { + for (let j = 0; j < sna; ++j) { + for (let k = 0; k < sna; ++k) { + //console.log("off", off); + // console.log(i, j, k); + sarr[off] = 0.3 * i; + sarr[off + 1] = 0.3 * j; + sarr[off + 2] = 0.3 * k; + sarr[off + 3] = 0; + off = off + 4; + } + } + } + } + + this.tex_insta_num_shape = SN; + this.tex_insta_pos_shape = new RC.Texture(sarr, + RC.Texture.WRAPPING.ClampToEdgeWrapping, + RC.Texture.WRAPPING.ClampToEdgeWrapping, + RC.Texture.FILTER.NearestFilter, + RC.Texture.FILTER.NearestFilter, + RC.Texture.FORMAT.RGBA32F, RC.Texture.FORMAT.RGBA, RC.Texture.TYPE.FLOAT, + sna * sna, sna); + // AMT end + // Testing creation of texture from JS array, simple checker pattern. let at = new Uint8Array(2 * 2 * 2); at[0] = at[6] = 255; // luminance @@ -353,6 +386,25 @@ const CoreControl = { sprite4.drawOutline = true; scene.add(sprite4); + // AMT begin + let shm = new RC.ZShapeBasicMaterial({ + ShapeSize: [0.1, 0.1, 0.02], + color: new RC.Color(1, 0, 0), + emissive: new RC.Color(0.07, 0.07, 0.06), + diffuse: new RC.Color(0, 0.6, 0.7), + alpha: 0.5 + }); + shm.addInstanceData(this.tex_insta_pos_shape); + let zshape = new RC.ZShape(null, shm); + zshape.position.set(7, 7, 0); + zshape.instanced = true; + zshape.instanceCount = this.tex_insta_num_shape; + zshape.drawOutline = true; + zshape.outlineMaterial.outline_instances_setup([ 4, 6]); + scene.add(zshape); + // AMT end + + let lm1 = new RC.ZSpriteBasicMaterial( { SpriteMode: RC.SPRITE_SPACE_WORLD, SpriteSize: [8, 8], color: new RC.Color(1, 0, 0), diff --git a/src/RenderCore.js b/src/RenderCore.js index ebff3e3..3cde0d9 100644 --- a/src/RenderCore.js +++ b/src/RenderCore.js @@ -137,6 +137,8 @@ export {Grid} from './objects/Grid.js'; // Instanced, instance-pickable, outline-supporting materials and objects export {ZSpriteBasicMaterial} from './materials/ZSpriteBasicMaterial.js'; export {ZSprite} from './objects/ZSprite.js'; +export {ZShapeBasicMaterial} from './materials/ZShapeBasicMaterial.js'; +export {ZShape} from './objects/ZShape.js'; // Program Management export {MaterialProgramTemplate} from './program_management/MaterialProgramTemplate.js'; @@ -171,4 +173,4 @@ export {DoFFX} from './renderers/FX/DoFFX.js'; // Controls (Input) export {KeyboardInput} from './controls/KeyboardInput.js'; export {MouseInput} from './controls/MouseInput.js'; -export {GamepadInput} from './controls/GamepadInput.js'; \ No newline at end of file +export {GamepadInput} from './controls/GamepadInput.js'; diff --git a/src/contrib/REveCameraControls.js b/src/contrib/REveCameraControls.js index ade9fe5..9c546a3 100644 --- a/src/contrib/REveCameraControls.js +++ b/src/contrib/REveCameraControls.js @@ -149,6 +149,8 @@ export class REveCameraControls extends EventDispatcher { else { let dollyDefault = 1.25*0.5*Math.sqrt(3)*bb_R; camTrans.moveLF(1, dollyDefault); + scope.object._near = 0.05 * dollyDefault; + scope.object._far = 2 * dollyDefault; scope.object.updateProjectionMatrix(); } }; diff --git a/src/contrib/REveRenderCore.js b/src/contrib/REveRenderCore.js index 5fc21e9..21ae295 100644 --- a/src/contrib/REveRenderCore.js +++ b/src/contrib/REveRenderCore.js @@ -137,6 +137,8 @@ export {Grid} from '../objects/Grid.js'; // Instanced, instance-pickable, outline-supporting materials and objects export {ZSpriteBasicMaterial} from '../materials/ZSpriteBasicMaterial.js'; export {ZSprite} from '../objects/ZSprite.js'; +export {ZShapeBasicMaterial} from '../materials/ZShapeBasicMaterial.js'; +export {ZShape} from '../objects/ZShape.js'; // Program Management export {MaterialProgramTemplate} from '../program_management/MaterialProgramTemplate.js'; diff --git a/src/materials/CustomShaderMaterial.js b/src/materials/CustomShaderMaterial.js index 8005e0d..f41ff7f 100644 --- a/src/materials/CustomShaderMaterial.js +++ b/src/materials/CustomShaderMaterial.js @@ -42,6 +42,12 @@ export class CustomShaderMaterial extends Material { } } + hasSBFlag(flag) { + const index = this._flagsSB.indexOf(flag); + + return (index > -1); + } + clearSBFlags() { this._flagsSB.clear(); } diff --git a/src/materials/ZShapeBasicMaterial.js b/src/materials/ZShapeBasicMaterial.js new file mode 100644 index 0000000..1803ee9 --- /dev/null +++ b/src/materials/ZShapeBasicMaterial.js @@ -0,0 +1,165 @@ +import {CustomShaderMaterial} from './CustomShaderMaterial.js'; +import {Color} from "../math/Color.js"; +import {FRONT_AND_BACK_SIDE} from '../constants.js'; +import {Int32Attribute} from "../core/BufferAttribute.js"; + +export class ZShapeBasicMaterial extends CustomShaderMaterial { + + /** + * WARNING: + * - constructor does not pass arguments to parent class + * - evades "custom" in shader name by setting programName after super + */ + constructor(args = {}){ + super(); + + this.type = "ZShapeBasicMaterial"; + this.programName = "basic_zshape"; + + // Uniforms aspect and viewport set by MeshRenderer based on actual viewport + this.setUniform("ShapeSize", "ShapeSize" in args ? args.ShapeSize : [1.0, 1.0, 1.0]); + + this.color = args.color ? args.color : new Color(Math.random() * 0xffffff); + this.emissive = args.emissive ? args.emissive : new Color(Math.random() * 0xffffff); + this.diffuse = args.diffuse ? args.diffuse : new Color(Math.random() * 0xffffff); + + this.side = args.side ? args.side : FRONT_AND_BACK_SIDE; + // this._specular = new Color(Math.random() * 0xffffff); + this._specular = new Color(0.5 * 0xffffff); + this._shininess = 64; + } + + set specular(val) { + this._specular = val; + + // Notify onChange subscriber + if (this._onChangeListener) { + var update = {uuid: this._uuid, changes: {specular: this._specular.getHex()}}; + this._onChangeListener.materialUpdate(update) + } + } + set shininess(val) { + this._shininess = val; + + // Notify onChange subscriber + if (this._onChangeListener) { + var update = {uuid: this._uuid, changes: {shininess: this._shininess}}; + this._onChangeListener.materialUpdate(update) + } + } + + get specular() { return this._specular; } + get shininess() { return this._shininess; } + + clone_for_picking() { + let o = new ZShapeBasicMaterial( { + ShapeSize: this.getUniform("ShapeSize"), + color: this.color, emissive: this.emissive, diffuse: this.diffuse, + side: this.side + } ); + if (this.hasSBFlag("SCALE_PER_INSTANCE")) o.addSBFlag("SCALE_PER_INSTANCE"); + if (this.hasSBFlag("MAT4_PER_INSTANCE")) o.addSBFlag("MAT4_PER_INSTANCE"); + for (const m of this.maps) o.addMap(m); + o._instanceData = this._instanceData; + o.addSBFlag('PICK_MODE_UINT'); + o.setUniform("u_PickInstance", false); + return o; + } + + clone_for_outline() { + let o = new ZShapeBasicMaterial( { + ShapeSize: this.getUniform("ShapeSize"), + color: this.color, emissive: this.emissive, diffuse: this.diffuse, + side: this.side + } ); + if (this.hasSBFlag("SCALE_PER_INSTANCE")) o.addSBFlag("SCALE_PER_INSTANCE"); + if (this.hasSBFlag("MAT4_PER_INSTANCE")) o.addSBFlag("MAT4_PER_INSTANCE"); + for (const m of this.maps) o.addMap(m); + o._instanceData = this._instanceData; + o.addSBFlag('OUTLINE'); + o.setUniform("u_OutlineGivenInstances", false); + o.setAttribute("a_OutlineInstances", Int32Attribute([0], 1, 0x7fffffff)); + return o; + } + + get color() { return this._color; } + set color(val) { + this._color = val; + + // Notify onChange subscriber + if (this._onChangeListener) { + var update = {uuid: this._uuid, changes: {color: this._color.getHex()}}; + this._onChangeListener.materialUpdate(update) + } + } + + get emissive() { return this._emissive; } + set emissive(val) { + this._emissive = val; + + // Notify onChange subscriber + if (this._onChangeListener) { + var update = {uuid: this._uuid, changes: {emissive: this._emissive.getHex()}}; + this._onChangeListener.materialUpdate(update) + } + } + get diffuse() { return this._diffuse; } + set diffuse(val) { + this._diffuse = val; + + // Notify onChange subscriber + if (this._onChangeListener) { + var update = {uuid: this._uuid, changes: {diffuse: this._diffuse.getHex()}}; + this._onChangeListener.materialUpdate(update) + } + } + + // Outline - setup / reset for instance list outlining. + // To be called on outline version (with OUTLINE SB-flag). + outline_instances_setup(instance_list) { + this.setUniform("u_OutlineGivenInstances", true); + let buf_attr = this.getAttribute("a_OutlineInstances"); + buf_attr.array = new Int32Array(instance_list); + buf_attr.divisor = 1; + // leaks buffers in gl-attrib-manager + // this.setAttribute("a_OutlineInstances", Int32Attribute(instance_list, 1, 1)); + } + outline_instances_reset() { + this.setUniform("u_OutlineGivenInstances", false); + let buf_attr = this.getAttribute("a_OutlineInstances"); + buf_attr.array = new Int32Array([0]); + buf_attr.divisor = 0x7fffffff; + // leaks buffers in gl-attrib-manager + // this.setAttribute("a_OutlineInstances", Int32Attribute([0], 1, 0x7fffffff)); + } + + + update(data) { + super.update(data); + + for (let prop in data) { + switch (prop) { + case "color": + this._color = data.color; + delete data.color; + break; + case "emissive": + this._emissive = data.emissive; + delete data.emissive; + break; + case "diffuse": + this._diffuse = data.diffuse; + delete data.diffuse; + break; + case "specular": + this._specular.setHex(data.specular); + delete data.specular; + break; + case "shininess": + this._shininess = data.shininess; + delete data.shininess; + break; + } + } + } +} diff --git a/src/objects/ZShape.js b/src/objects/ZShape.js new file mode 100644 index 0000000..e7d5909 --- /dev/null +++ b/src/objects/ZShape.js @@ -0,0 +1,316 @@ +/** + * Based on ZSprite by Matevz. + * + */ + +import {Mesh} from './Mesh.js'; +import {Quad} from './Quad.js'; +import {ZShapeBasicMaterial} from '../materials/ZShapeBasicMaterial.js'; +import {Vector2} from '../RenderCore.js'; +import {Geometry} from './Geometry.js'; +import {Float32Attribute, Uint32Attribute} from '../core/BufferAttribute.js'; + + +export class ZShape extends Mesh { + constructor(geometry = null, material = null) { + if (geometry === null) { + /* + let xy0 = new Vector2(-0.5, 0.5); + let xy1 = new Vector2(0.5, -0.5); + geometry = Quad.makeGeometry(xy0, xy1, false, true, false, false); + */ + geometry = ZShape.makeCubeGeometry(); + console.log("zshape cube geometry ", geometry); + this._geometry = geometry; + } + + if (material === null) { + material = new ZShapeBasicMaterial(); + } + // MT for Sebastien -- what would be the best way to clone material? + // ZShapeBasicMaterial.clone_for_outline() seems OK (but one needs to + // take care with uniform / texture / instanceData updates). + let pmat = material.clone_for_picking(); + let omat = material.clone_for_outline(); + + //SUPER + super(geometry, material, pmat, omat); + this.type = "ZShape"; + } + + static makeCubeGeometry() { + let cube = new Geometry(); + cube.vertices = Float32Attribute([ + // Front face + -1.0, -1.0, 1.0, + 1.0, -1.0, 1.0, + 1.0, 1.0, 1.0, + -1.0, 1.0, 1.0, + + // Back face + -1.0, -1.0, -1.0, + -1.0, 1.0, -1.0, + 1.0, 1.0, -1.0, + 1.0, -1.0, -1.0, + + // Top face + -1.0, 1.0, -1.0, + -1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, + 1.0, 1.0, -1.0, + + // Bottom face + -1.0, -1.0, -1.0, + 1.0, -1.0, -1.0, + 1.0, -1.0, 1.0, + -1.0, -1.0, 1.0, + + // Right face + 1.0, -1.0, -1.0, + 1.0, 1.0, -1.0, + 1.0, 1.0, 1.0, + 1.0, -1.0, 1.0, + + // Left face + -1.0, -1.0, -1.0, + -1.0, -1.0, 1.0, + -1.0, 1.0, 1.0, + -1.0, 1.0, -1.0 + ], 3); + + + cube.indices = Uint32Attribute([ + 0, 1, 2, 0, 2, 3, // Front face + 4, 5, 6, 4, 6, 7, // Back face + 8, 9, 10, 8, 10, 11, // Top face + 12, 13, 14, 12, 14, 15, // Bottom face + 16, 17, 18, 16, 18, 19, // Right face + 20, 21, 22, 20, 22, 23 // Left face + ], 1); + cube.computeVertexNormals(); + + //per face UVs + cube.uv = Float32Attribute([ + // Front face + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + + // Back face + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + + // Top face + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + 1.0, 0.0, + + // Bottom face + 0.0, 1.0, + 1.0, 1.0, + 1.0, 0.0, + 0.0, 0.0, + + // Right face + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + 1.0, 0.0, + + // Left face + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + ], 2); + + cube.type = "Cube"; + return cube; + } + + static makeHexagonGeometry() { + let vBuff = new Float32Array((7 * 2 + 6 * 4 )* 3); + let stepAngle = Math.PI / 3; + let R = 1; + // bottom vertex + vBuff[0] = vBuff[1] = vBuff[2] = 0; + // circle vertices + let off = 3; + for (let j = 0; j < 6; ++j) { + let angle = j * stepAngle; + let x = R * Math.cos(angle); + let y = R * Math.sin(angle); + let z = 0; + vBuff[off] = x; + vBuff[off + 1] = y; + vBuff[off + 2] = z; + off += 3; + } + // z depth vertices + let hexHeight = 1; + let ro = 0; + for (let j = 0; j < 7; ++j) { + vBuff[ro + 21] = vBuff[ro]; + vBuff[ro + 22] = vBuff[ro + 1]; + vBuff[ro + 23] = vBuff[ro + 2] + hexHeight; + ro += 3; + } + + // side vertices + off = 7*2*3; + for (let j = 0; j < 6; ++j) { + let angle = j * stepAngle; + let x = R * Math.cos(angle); + let y = R * Math.sin(angle); + + vBuff[off ] = x; + vBuff[off + 1] = y; + vBuff[off + 2] = 0; + + vBuff[off + 3] = x; + vBuff[off + 4] = y; + vBuff[off + 5] = hexHeight; + + let x2 = R * Math.cos(angle+ stepAngle); + let y2 = R * Math.sin(angle+ stepAngle); + + vBuff[off + 6] = x2; + vBuff[off + 7] = y2; + vBuff[off + 8] = hexHeight; + + vBuff[off + 9] = x2; + vBuff[off + 10] = y2; + vBuff[off + 11] = 0; + + off += 12; + } + + let idxBuffSize = 6*3*2+ 6*6; + let idxBuff = new Uint32Array(idxBuffSize); + let protoIdcs = [0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,1]; + let b = 0; + + // top + for (let c = 0; c < protoIdcs.length; c++) { + idxBuff[b++] = protoIdcs[c]; + + } + // bottom + for (let c = 0; c < protoIdcs.length; c++) { + idxBuff[b++] = protoIdcs[c] + 7; + } + + // sides + let protoSide = [0,1,2,2,3,0]; + + for (let side = 0; side < 6; ++side) { + for (let c = 0; c < protoSide.length; c++) { + idxBuff[b++] = 14 + side*4 + protoSide[c]; + } + } + + let hex = new Geometry(); + hex.vertices = Float32Attribute(vBuff,3); + hex.indices = Uint32Attribute(idxBuff,1); + hex.computeVertexNormals(); + + hex.type = "Hexagon"; + return hex; + } + + // Tesselate cone. Note: main cone axis are aligned with z axis + static makeConeGeometry(drawCap) { + // + // vertices + // + let nStep = 36; + let vBuff = new Float32Array((nStep * 2 + 2) * 3); + + // apex cone at the center + vBuff[0] = vBuff[1] = vBuff[2] = 0; + + // plate vertices + let stepAngle = 2 * Math.PI / nStep; + let H = 1.0; + let R = 1.0; + let off = 3; + for (let i = 0; i < nStep; ++i) { + let angle = i * stepAngle; + let x = R * Math.cos(angle); + let y = R * Math.sin(angle); + + vBuff[off ] = x; + vBuff[off + 1] = y; + vBuff[off + 2] = H; + + off += 3; + } + + // plate center + vBuff[off ] = 0; + vBuff[off + 1] = 0; + vBuff[off + 2] = H; + + off += 3; + // duplicate vertices + for (let i = 0; i < nStep; ++i) { + let angle = i * stepAngle; + let x = R * Math.cos(angle); + let y = R * Math.sin(angle); + + vBuff[off ] = x; + vBuff[off + 1] = y; + vBuff[off + 2] = H; + + off += 3; + } + + // + // indices + // + let idxBuffSize = nStep * 3; + if (drawCap) + idxBuffSize *= 2; + let lastCIdx = nStep * 3 - 1; + let idxBuff = new Uint32Array(idxBuffSize); + // make polygon for each angle step + let b = 0; + for (let i = 0; i < nStep; ++i) { + idxBuff[b++] = 0; + idxBuff[b++] = i + 1; + if (b == lastCIdx) + idxBuff[b++] = 1 + else + idxBuff[b++] = i + 2; + } + + if (drawCap) { + let lvx = nStep + 1; + for (let i = 0; i < nStep; ++i) { + idxBuff[b++] = lvx; + idxBuff[b++] = lvx + i + 1; + if (b == (idxBuffSize - 1)) + idxBuff[b++] = lvx + 1 + else + idxBuff[b++] = lvx + i + 2; + + } + } + + console.log("Idx budd ", idxBuff); + // + // Geometry + // + let cone = new Geometry(); + cone.vertices = Float32Attribute(vBuff,3); + cone.indices = Uint32Attribute(idxBuff,1); + cone.computeVertexNormals(); + + cone.type = "Cone"; + return cone; + } +} diff --git a/src/shaders/basic/basic_zshape_template.frag b/src/shaders/basic/basic_zshape_template.frag new file mode 100644 index 0000000..7dddfa8 --- /dev/null +++ b/src/shaders/basic/basic_zshape_template.frag @@ -0,0 +1,278 @@ +#version 300 es +precision mediump float; + +//DEF +//********************************************************************************************************************** + +#if (DLIGHTS) +struct DLight { + vec3 direction; + vec3 color; +}; +#fi + +#if (PLIGHTS) +struct PLight { + //bool directional; + vec3 position; + vec3 position_worldspace; + vec3 color; + float distance; + //float decay; + + mat4 VPMat; + samplerCube shadowmap; + bool castShadows; + bool hardShadows; + float minBias; + float maxBias; + float shadowFar; + + float constant; + float linear; + float quadratic; +}; +#fi + +struct Material { + vec3 emissive; + vec3 diffuse; + float alpha; + #if (INSTANCED) + sampler2D instanceData0; + #fi + #if (TEXTURE) + #for I_TEX in 0 to NUM_TEX + sampler2D texture##I_TEX; + #end + #fi + + // AMT ADD + vec3 specular; + float shininess; + + bool blinn; + +}; + + +//UIO +//********************************************************************************************************************** + +uniform Material material; + +#if (TRANSPARENT) + uniform float alpha; +#else + float alpha = 1.0; +#fi + +#if (DLIGHTS) + uniform DLight dLights[##NUM_DLIGHTS]; +#fi + +#if (PLIGHTS) + uniform PLight pLights[##NUM_PLIGHTS]; +#fi +uniform vec3 ambient; + +#if (PLIGHTS) +in vec3 fragVPos; +#fi +// AMT again what is dependent with plights +#if (!NORMAL_MAP && !NORMAL_FLAT) +in vec3 fragVNorm; +#fi + + +#if (COLORS) +#fi +in vec4 fragVColor; // AMT take it out from color define + +#if (TEXTURE) + in vec2 fragUV; +#fi + +#if (PICK_MODE_RGB) + uniform vec3 u_RGB_ID; + layout(location = 0) out vec4 objectID; +#else if (PICK_MODE_UINT) + uniform uint u_UINT_ID; + #if (INSTANCED) + uniform bool u_PickInstance; + flat in uint InstanceID; + #fi + layout(location = 0) out uint objectID; +#else if (OUTLINE) + // in vec3 v_position_viewspace; + in vec3 v_normal_viewspace; + in vec3 v_ViewDirection_viewspace; + + layout (location = 0) out vec4 vn_viewspace; + layout (location = 1) out vec4 vd_viewspace; + #if (DEPTH) + layout (location = 2) out vec4 de_viewspace; // could be float + #fi +#else + out vec4 outColor; +#fi + +#if (CLIPPING_PLANES) + struct ClippingPlane { + vec3 normal; + float constant; + }; + + uniform ClippingPlane clippingPlanes[##NUM_CLIPPING_PLANES]; + + in vec3 vViewPosition; +#fi + +// in vec4 v_VColor; + + +//FUNCTIONS +//********************************************************************************************************************** +#if (PLIGHTS || SLIGHTS) +float calcAttenuation(float constant, float linear, float quadratic, float distance) { + //float attenuation = 1.0f / (1.0f + 0.01f * distance + 0.0001f * (distance * distance)); + //float attenuation = light.decay / (light.decay + 0.01f * distance + 0.0001f * (distance * distance)); + return 1.0 / (constant + linear * distance + quadratic * (distance * distance)); +} +#fi + + +#if (PLIGHTS) +// Calculates the point light color contribution +vec3 calcPointLight (PLight light, vec3 normal, vec3 viewDir) { + + float distance = length(light.position - fragVPos); + if(light.distance > 0.0 && distance > light.distance) return vec3(0.0, 0.0, 0.0); + + vec3 lightDir = normalize(light.position - fragVPos); + + // Difuse + float diffuseF = max(dot(lightDir, normal), 0.0f); + + // Specular + //vec3 reflectDir = reflect(-lightDir, normal); + //float specularF = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess); + float specularF; + if(material.blinn) + { + vec3 halfwayDir = normalize(lightDir + viewDir); + specularF = pow(max(dot(normal, halfwayDir), 0.0), material.shininess); + } + else + { + vec3 reflectDir = reflect(-lightDir, normal); + specularF = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + } + + // Attenuation + float attenuation = 1.0; // calcAttenuation(light.constant, light.linear, light.quadratic, distance); + + // Combine results + // vec3 diffuse = light.color * diffuseF * material.diffuse * attenuation; + // vec3 specular = light.color * specularF * material.specular * attenuation; + // #if (COLORS) + vec3 diffuse = light.color * diffuseF * (fragVColor.rgb) * attenuation; + //#else + // vec3 diffuse = light.color * diffuseF * material.diffuse * attenuation; + //#fi + vec3 specular = light.color * specularF * material.specular * attenuation; + + return (diffuse + specular); +} +#fi + + +//MAIN +//********************************************************************************************************************** +void main() { + + #if (CLIPPING_PLANES) + bool clipped = true; + for(int i = 0; i < ##NUM_CLIPPING_PLANES; i++){ + clipped = ( dot( vViewPosition, clippingPlanes[i].normal ) > clippingPlanes[i].constant ) && clipped; + } + if ( clipped ) discard; + #fi + + // vec4 color = v_VColor; + + #if (OUTLINE) + vn_viewspace = vec4(v_normal_viewspace, 0.0); + vd_viewspace = vec4(v_ViewDirection_viewspace, 0.0); + #if (DEPTH) + de_viewspace = vec4(gl_FragCoord.z, 0.0, 0.0, 1.0); + #fi + #else if (PICK_MODE_RGB) + objectID = vec4(u_RGB_ID, 1.0); + #else if (PICK_MODE_UINT) + #if (INSTANCED) + if (u_PickInstance) { + objectID = InstanceID; // 0 is a valid result + } else { + objectID = u_UINT_ID; + } + #else + objectID = u_UINT_ID; + #fi + #else + + // AMT additions + #if (!NORMAL_MAP) + #if (NORMAL_FLAT) + vec3 fdx = dFdx(fragVPos); + vec3 fdy = dFdy(fragVPos); + vec3 normal = normalize(cross(fdx, fdy)); + + //vec3 viewDir = vec3(0.0, 0.0, -1.0); //view direction in viewspace! + #else if (!NORMAL_FLAT) + vec3 normal = normalize(fragVNorm); + #fi + + vec3 viewDir = normalize(-fragVPos); + + #if (HEIGHT_MAP) + texCoords = parallaxOffset(texCoords, viewDir); + if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0) discard; + #fi + #else + vec3 viewDir = normalize(-v_position_tangentspace); + + #if (HEIGHT_MAP) + texCoords = parallaxOffset(texCoords, viewDir); + if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0) discard; + #fi + + vec3 normal = texture(material.normalMap, texCoords).rgb; + normal = normal*2.0 - 1.0; + normal = normalize(normal); + #fi + + // Calculate combined light contribution + #if (!DIFFUSE_MAP) + vec3 combined = ambient; + #else + vec3 combined = ambient * texture(material.diffuseMap, texCoords).rgb; + #fi + + #if (PLIGHTS) + vec3 pLight; + float pShadow = 0.0; + + #for lightIdx in 0 to NUM_PLIGHTS + #if (!NORMAL_MAP) + pLight = calcPointLight(pLights[##lightIdx], normal, viewDir); + #else + pLight = calcPointLight_tangentspace(pLights[##lightIdx], v_pLightPosition_tangentspace[##lightIdx], viewDir, v_position_tangentspace, normal, texCoords); + #fi + + combined += pLight * (1.0 - pShadow); + #end + outColor = vec4(combined, alpha); + #fi +#fi +} diff --git a/src/shaders/basic/basic_zshape_template.vert b/src/shaders/basic/basic_zshape_template.vert new file mode 100644 index 0000000..3eb0cf0 --- /dev/null +++ b/src/shaders/basic/basic_zshape_template.vert @@ -0,0 +1,345 @@ +#version 300 es +precision mediump float; + + +//DEF +//********************************************************************************************************************** + +#if (INSTANCED) +struct Material { + vec3 emissive; + vec3 diffuse; + float alpha; + sampler2D instanceData0; + // The following one could actually be instanced in int (or it has to be float?) + // #if (OUTLINE) + // sampler2D instance_indices; + // #fi + #if (TEXTURE) + #for I_TEX in 0 to NUM_TEX + sampler2D texture##I_TEX; + #end + #fi + + // AMT ADD + vec3 specular; + float shininess; + + bool blinn; +}; +#fi + +//STRUCT +//********************************************************************************************************************** +#if (DLIGHTS) +struct DLight { + vec3 direction; + vec3 color; +}; +#fi +#if (PLIGHTS) +struct PLight { + //bool directional; + vec3 position; + vec3 position_worldspace; + vec3 color; + float distance; + //float decay; + + mat4 VPMat; + samplerCube shadowmap; + bool castShadows; + bool hardShadows; + float minBias; + float maxBias; + float shadowFar; + + float constant; + float linear; + float quadratic; +}; +#fi +#if (SLIGHTS) +struct SLight { + vec3 position; + vec3 color; + float distance; + float decay; + float cutoff; + float outerCutoff; + vec3 direction; +}; +#fi + +//UIO +//********************************************************************************************************************** +uniform mat4 MVMat; // Model View Matrix +uniform mat4 PMat; // Projection Matrix +uniform vec2 viewport; +uniform vec3 ShapeSize; + +in vec3 VPos; // Vertex position +in vec3 VNorm; // Vertex normal +uniform mat3 NMat; // Normal Matrix + +#if (COLORS) + in vec4 VColor; +#fi +out vec4 fragVColor; // AMT take it outfrom COLORS define + +#if (TEXTURE) + in vec2 uv; + out vec2 fragUV; +#fi + +#if (PLIGHTS) + out vec3 fragVPos; +#fi +#if (!NORMAL_MAP && !NORMAL_FLAT) +out vec3 fragVNorm; +#fi + +#if (POINTS) + uniform float pointSize; +#fi + +#if (CLIPPING_PLANES) + out vec3 vViewPosition; +#fi + +#if (INSTANCED) + uniform Material material; + #if (PICK_MODE_UINT) + flat out uint InstanceID; + #fi + #if (OUTLINE) + uniform bool u_OutlineGivenInstances; + in int a_OutlineInstances; + #fi + +#fi + +#if (OUTLINE) +out vec3 v_normal_viewspace; +out vec3 v_ViewDirection_viewspace; +#fi + +// AMT +#if (DLIGHTS) +uniform DLight dLights[##NUM_DLIGHTS]; +#fi +#if (PLIGHTS) +uniform PLight pLights[##NUM_PLIGHTS]; +#fi +#if (SLIGHTS) +uniform SLight sLights[##NUM_SLIGHTS]; +#fi + + +uniform vec3 ambient; +vec3 coldif; + +//FUNCTIONS +//********************************************************************************************************************** +#if (DLIGHTS) +vec3 calcDirectLight (DLight light, vec3 normal, vec3 viewDir) { + + vec3 lightDir = normalize(-light.direction); + + // Difuse + float diffuseF = max(dot(normal, lightDir), 0.0f); + + // Combine results + vec3 diffuse = light.color * diffuseF * coldif; + + return diffuse; +} +#fi + + +#if (SLIGHTS) +vec3 calcSpotLight (vec3 VPos_viewspace, SLight light, vec3 normal, vec3 viewDir) { + + float distance = length(light.position - VPos_viewspace); + // AMT if(light.distance > 0.0 && distance > light.distance) return vec3(0.0, 0.0, 0.0); + + vec3 lightDir = normalize(light.position - VPos_viewspace); + + + // spot + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = light.cutoff - light.outerCutoff; + float intensity = clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0); + //if(theta <= light.cutoff) return vec3(0.0, 0.0, 0.0); + if(theta <= light.outerCutoff) return vec3(0.0, 0.0, 0.0); + + + // Difuse + float diffuseF = max(dot(lightDir, normal), 0.0f); + + // Attenuation + //float attenuation = 1.0f / (1.0f + 0.01f * distance + 0.0001f * (distance * distance)); + float attenuation = 1.0f; // light.decay / (light.decay + 0.01f * distance + 0.0001f * (distance * distance)); + + // Combine results + vec3 diffuse = light.color * diffuseF * coldif * attenuation; + + return diffuse * intensity; +} +#fi +//FUNCTIONS +//********************************************************************************************************************** + +#if (PLIGHTS) +// Calculates the point light color contribution +vec3 calcPointLight (vec3 VPos_viewspace, PLight light, vec3 normal, vec3 viewDir) { + + float distance = length(light.position - VPos_viewspace); + // AMT if(light.distance > 0.0 && distance > light.distance) return vec3(0.0, 0.0, 0.0); + + vec3 lightDir = normalize(light.position - VPos_viewspace); + + // Difuse + float diffuseF = max(dot(lightDir, normal), 0.0f); + + // Attenuation + //float attenuation = 1.0f / (1.0f + 0.01f * distance + 0.0001f * (distance * distance)); + float attenuation = 1.0f;// AMT light.decay / (light.decay + 0.01f * distance + 0.0001f * (distance * distance)); + + // Combine results + // vec3 diffuse = light.color * diffuseF * material.diffuse * attenuation; + vec3 diffuse = light.color * diffuseF * coldif * attenuation; + + return diffuse; +} +#fi + +//MAIN +//********************************************************************************************************************** +void main() { + // Position of the origin in viewspace. + vec3 VPos_final; + vec3 VPos_local = vec3(ShapeSize.x, ShapeSize.y, ShapeSize.z) * VPos; + + #if (INSTANCED) + int iID = gl_InstanceID; + #if (OUTLINE) + if (u_OutlineGivenInstances) + iID = a_OutlineInstances; + #fi + #if (MAT4_PER_INSTANCE) + int pID = 4 * iID; + #else if (SCALE_PER_INSTANCE) + int pID = 2 * iID; // pixelID + #else + int pID = iID; // pixelID + #fi + int tsx = textureSize(material.instanceData0, 0).x; + ivec2 tc = ivec2(pID % tsx, pID / tsx); + vec4 pos = texelFetch(material.instanceData0, tc, 0); + + uint rgba = floatBitsToUint(pos.w); + coldif.r = float((uint(0xff0000) & rgba) >> 16) / 255.0; + coldif.g = float((uint(0xff00) & rgba) >> 8) / 255.0; + coldif.b = float((uint(0xff) & rgba) >> 0) / 255.0; + + #if (SCALE_PER_INSTANCE) + vec4 scale = texelFetchOffset(material.instanceData0, tc, 0, ivec2(1, 0)); + VPos_final = pos.xyz + VPos_local * scale.xyz; + #else if (MAT4_PER_INSTANCE) + mat3 mmat = mat3(texelFetchOffset(material.instanceData0, tc, 0, ivec2(1, 0)).xyz, + texelFetchOffset(material.instanceData0, tc, 0, ivec2(2, 0)).xyz, + texelFetchOffset(material.instanceData0, tc, 0, ivec2(3, 0)).xyz); + VPos_final = pos.xyz + mmat * VPos_local; + #else + VPos_final = pos.xyz + VPos_local; + #fi + #if (PICK_MODE_UINT) + InstanceID = uint(iID); + #fi + #else + VPos_final = VPos_local; + coldif = material.diffuse; + #fi + + vec4 VPos_viewspace = MVMat * vec4(VPos_final, 1.0); + + // Assume vertices in x,y plane, z = 0; close to (0, 0) as ShapeSize + // will scale them (for centered sprite there should be a quad with x, y = +-0.5). + gl_Position = PMat * VPos_viewspace; + + #if (PLIGHTS) + // Pass vertex position to fragment shader + fragVPos = vec3(VPos_viewspace) / VPos_viewspace.w; + #fi + + //#if (COLORS) + // Pass vertex color to fragment shader + fragVColor = vec4(coldif, 1.0); + //#fi + + #if (TEXTURE) + // Pass uv coordinate to fragment shader + fragUV = uv; + #fi + + #if (CLIPPING_PLANES) + vViewPosition = -VPos_viewspace.xyz; + #fi + + #if (OUTLINE) + v_normal_viewspace = vec3(0.0, 0.0, -1.0); + + float dToCam = length(VPos_viewspace.xyz); + v_ViewDirection_viewspace = -VPos_viewspace.xyz / dToCam; + #fi + + // define colors for fragment shader + // + vec4 combined = vec4(ambient + material.emissive, material.alpha); +#if (MAT4_PER_INSTANCE) + vec3 normal = normalize(NMat * mmat * VNorm); +#else + vec3 normal = normalize(NMat * VNorm); +#fi + vec3 viewDir = normalize(-VPos_viewspace.xyz); + + #if (DLIGHTS) + vec3 dLight; + float dShadow = 0.0; + + #for lightIdx in 0 to NUM_DLIGHTS + dLight = calcDirectLight(dLights[##lightIdx], normal, viewDir); + combined.rgb += dLight; + #end + #fi + #if (PLIGHTS) + vec3 pLight; + float pShadow = 0.0; + + #for lightIdx in 0 to NUM_PLIGHTS + pLight = calcPointLight(VPos_viewspace.xyz, pLights[##lightIdx], normal, viewDir); + // combined.rgb += pLight; + #end + #fi + #if (SLIGHTS) + vec3 sLight; + float sShadow = 0.0; + + #for lightIdx in 0 to NUM_SLIGHTS + sLight = calcSpotLight(VPos_viewspace.xyz, sLights[##lightIdx], normal, viewDir); + combined.rgb += sLight; + #end + #fi + + // #if (!NORMAL_MAP && !NORMAL_FLAT) + #if (NORMAL_MAP && !NORMAL_FLAT)// ?? AMT TMP HACK for the FLATNOTMAL prop bug!!!!! + // Transform normal + #if (!INSTANCED) + fragVNorm = vec3(NMat * VNorm); + #fi + #if (INSTANCED) + fragVNorm = vec3(NMat * mat3(MMat) * VNorm); + #fi + #fi + } diff --git a/src/shaders/programs.json b/src/shaders/programs.json index 80ae1cf..7914c13 100644 --- a/src/shaders/programs.json +++ b/src/shaders/programs.json @@ -59,7 +59,6 @@ "fragment": "basic/basic_template-FLAT.frag" } }, - "basic_sprite": { "description": "Default gl2 program used for testing.", "shaders": { @@ -82,6 +81,14 @@ } }, + "basic_zshape": { + "description": "ZShape instanced from texture; supports PICKING and OUTLINE modes.", + "shaders": { + "vertex": "basic/basic_zshape_template.vert", + "fragment": "basic/basic_zshape_template.frag" + } + }, + "basic_stripe": { "description": "Default gl2 program used for testing.", "shaders": { @@ -475,4 +482,4 @@ "fragment": "custom/jumpFloodingLayersFinal.frag" } } -} \ No newline at end of file +}