Showing posts with label shader. Show all posts
Showing posts with label shader. Show all posts

Thursday, August 30, 2018

Uniform type mismatch error - OpenGL ES 3.0 shader program linked on Android 7/8/9 but failed on iOS 10/11?

Leave a Comment

I was frustrated by an error when linking OpenGL es shader 3.0 program on iOS.

I have one vertex shader and one fragment shader and they are linked to generate a single program. There are shared uniforms and uniform blocks in both shaders. I understand that these uniforms must have exactly same type, precision and name, so that I even copy the uniform declaration from one shader to the other shader.

Here is the code of my vertex shader:

// Vertex shader #version 300 es precision highp float;  // ...........................  // Shared uniforms ...  uniform mat4 viewMatrix; uniform mat4 modelViewMatrix; uniform mat4 texcoordMatrix; uniform mat4 projMatrix;  uniform bool shadingEnabled; uniform bool fogEnabled; uniform bool flatShading; uniform bool specularEnabled; uniform bool generateReflectionTexCoord; uniform float zBias;  layout (std140) uniform cbFog {     int     g_fogMode;     float   g_fogStart;     float   g_fogEnd;     float   g_fogDensity;     vec4    g_fogColor; }; layout (std140) uniform cbMaterial {     vec4 mtlAmbient;     vec4 mtlDiffuse;     vec4 mtlSpecular;     vec4 mtlEmissive;     int  mtlSpecularPower;     float _padding4;     float _padding5;     float _padding6; };  // ...........................  // Vertex shader's input and output ...  // ...........................  // Vertex shader code ... 

And here is the code of my fragment shader:

// Fragment shader #version 300 es precision highp float;  // ...........................  // Shared uniforms ...  uniform mat4 viewMatrix; uniform mat4 modelViewMatrix; uniform mat4 texcoordMatrix; uniform mat4 projMatrix;  uniform bool shadingEnabled; uniform bool fogEnabled; uniform bool flatShading; uniform bool specularEnabled; uniform bool generateReflectionTexCoord; uniform float zBias;  layout (std140) uniform cbFog {     int     g_fogMode;     float   g_fogStart;     float   g_fogEnd;     float   g_fogDensity;     vec4    g_fogColor; }; layout (std140) uniform cbMaterial {     vec4 mtlAmbient;     vec4 mtlDiffuse;     vec4 mtlSpecular;     vec4 mtlEmissive;     int  mtlSpecularPower;     float _padding4;     float _padding5;     float _padding6; };  // ...........................  // Fragment shader's input and output ...  // ...........................  // Fragment shader code ... 

Please note that all uniform declarations are copied from vertex shader into fragment shader so that they are guaranteed to be identical.

The result is that the program can be successfully linked on Android and some OpenGL ES simulators like PowerVR, but it fail to be linked on iOS 10/11 and the following is the error message:

Error when linking shader program: ERROR: Uniform type mismatch '<uniform cbMaterial>' ERROR: Uniform type mismatch '<uniform cbFog>' 

The iOS OpenGL ES complains that uniform block cbMaterial and cbFog have mismatched type. Anyone can help me find the reason for me? Thanks!

PS: I understand that OpenGL ES might be deprecated on macOS 10.14 and iOS 12, I still need to get this working on iOS for certain maintenance reason.

0 Answers

Read More

Friday, April 20, 2018

Have 3d text shader be non-emissive?

Leave a Comment

In Unity, how can I stop my 3d texts from "glowing" in the dark?

I'm using below shader code, for instance, but the texts turn up much brighter/ self-emissive than other things. Changing to "Lighting On" gets rid of the glow, but will then also get rid of the material color, and turn up black.

How to solve this? Many thanks!

Shader "GUI/3D Text Shader - Cull Back" { Properties {     _MainTex ("Font Texture", 2D) = "white" {}     _Color ("Text Color", Color) = (1,1,1,1) }  SubShader {     Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }     Lighting Off Cull Back ZWrite Off Fog { Mode Off }     Blend SrcAlpha OneMinusSrcAlpha     Pass {         Color [_Color]         SetTexture [_MainTex] {             combine primary, texture * primary         }     } } 

1 Answers

Answers 1

Copied from comments, added for context:

I suspect the emissive glow is just the material's unlit color contrasting against a dark/variably lit scene? A lit shader could fix such an issue, however Unity's TextMesh component appears to not generate mesh normals and thus the shader's lighting calculations will corrupt (if at all be compiled). It explains why Lighting On outputs black. Without access to TextMesh internals and confined to the limitations of fixed-function shaders, a custom shader may be your only option.

The following is a basic Surface Shader using the Lambert lightning model. Under the hood it will compile to a standard vertex/fragment shader with Unity's lighting calculations automagically injected. It's been written as a drop-in replacement, so simply add it to your project and drag and drop it onto your material:

Shader "GUI/3D Text Shader - Lit" {     Properties     {         _Color ("Text Color", Color) = (1,1,1,1)         _MainTex ("Font Texture", 2D) = "white" {}     }      SubShader     {         Tags {"RenderType"="Transparent" "Queue"="Transparent"}         Cull Back          CGPROGRAM            #pragma surface SS_Main Lambert vertex:VS_Main alpha:blend          #pragma target 3.0          uniform fixed4 _Color;         uniform sampler2D _MainTex;          struct Output         {              float4 vertex    : POSITION;              float3 normal    : NORMAL;                   float4 texcoord  : TEXCOORD0;              float4 texcoord1 : TEXCOORD1;              float4 texcoord2 : TEXCOORD2;         };          struct Input         {             float2 uv_MainTex;         };                void VS_Main (inout Output o)          {                       // Generate normals for lighting.             o.normal = float3(0, 0, -1);         }          void SS_Main (Input IN, inout SurfaceOutput o)         {                    fixed4 c = tex2D (_MainTex, IN.uv_MainTex);             o.Albedo = _Color.rgb;             o.Alpha = c.a;         }         ENDCG     } } 
Read More

Monday, October 30, 2017

GLSL: Can I combine MRT, ssbo and imageAtomic operations in the same shader (pass)?

Leave a Comment

A 2-pass rendering system in OpenGL is using an MRT shader that is bound to 2 framebuffer textures tex1 and tex2. The goal of the mrt pass is to compute the overdraw in the scene and render it out in a gather pass. I use the framebuffer textures to pass on the result.

It also has a working ssbo buffer that is quite large (and using a fixed screen resolution) and takes ages to link, but I can use it to do atomicAdds. What I am trying to accomplish is to replace this with imageAtomicAdd operations on a uiimage2D, just like with the mrt passes.

The problem is that the result of imageAtomicAdd is always zero, where I expect it to go up just like atomicAdd does at that point..

#version 440 core  layout(early_fragment_tests) in;  // this works fine layout (location = 0) out vec4 tex1; layout (location = 1) out vec4 tex2;  // this works fine layout(std430, binding = 3) buffer ssbo_data {         uint v[1024*768]; };  // this does not work at all. uniform volatile layout(r32ui) uimage2D imgCounter;  out vec4 frag_colour;  void main ()  {            ivec2 coords = ivec2(gl_FragCoord.xy);     uint addValue = 1u;      uint countOverdraw1 = atomicAdd(v[coords.x + coords.y * 1024], 1u);     uint countOverdraw2 = imageAtomicAdd(imgCounter, ivec2(0,0), 1u);       memoryBarrier();      // supports 256 levels of overdraw..     float overdrawDepth = 256.0;     vec3 c1 = vec3(float(countOverdraw1+1)/overdrawDepth ,0,1);     vec3 c2 = vec3(float(countOverdraw2+1)/overdrawDepth ,0,1);      tex1 = vec4(c1,1);       tex2 = vec4(c2,1);       frag_colour = vec4(1,1,1,1); } 

From the khronos website on image atomic operations I gather that..

Atomic operations to any texel that is outside of the boundaries of the bound image will return 0 and do nothing.

.. but the coordinate ivec2(0,0) would be well within the bounds of the texture size (1024 x 768).

Maybe the texture is not set up correctly? This is how I construct the uiimage2D (pieced together from the pipeline flow):

EDIT: I update the code as per suggestion by the answer from Nicol Bolas: texture parameters are set instead of sampler parameters

char data[1024*768*4]; glGenTextures(1, &m_Handle);  m_Target = GL_TEXTURE_2D;  glActiveTexture(GL_TEXTURE0+6); glBindTexture(m_Target,m_Handle);  // updated : a sampler object was bound to the texture, but is now removed  glTexParameteri(m_Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // updated glTexParameteri(m_Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // updated glTexParameteri(m_Target, GL_TEXTURE_WRAP_R, GL_REPEAT);       // updated glTexParameteri(m_Target, GL_TEXTURE_WRAP_S, GL_REPEAT);       // updated glTexParameteri(m_Target, GL_TEXTURE_WRAP_T, GL_REPEAT);       // updated glTexImage2D(m_Target, 0, R32UI, 1024, 768, 0, GL_RED_INTEGER, GL_UNSIGNED_INT,  data);      

If I run it through gDEBugger GL, I see that "Texture data is not available at this time" and while the 'Texture 4' parameters of the texture are filled in and correct, none of the 'Texture Parameters' and 'Level 0 parameters' are shown (N/A). Trapping the debugger at that point throws a whole number of problems that do not appear outside of gDEBugger. Here are the first few:

GL_INVALID_OPERATION error generated. The required buffer is missing. GL_INVALID_ENUM error generated. <pname> requires feature(s) disabled in the current profile.  GL_INVALID_OPERATION error generated. <index> exceeds the maximum number of supported texture units.  GL_INVALID_ENUM error generated. or require feature(s) disabled in the current profile.   GL_INVALID_OPERATION error generated. Can't mix integer and non-integer data ... 

I'm explicitly forcing GL 4.4 or GL4.4 'core' profile so I'm a bit puzzled what may be the problem with the required buffer that is missing. Could it be that it is mistakingly seeing the imgCounter as part of the MRT setup for the framebuffer?

1 Answers

Answers 1

That texture is incomplete.

See, when you bind a texture for use with image load/store operations, you don't bind a sampler along with it. So all of those glSamplerParameter calls are meaningless to the texture's completeness status.

The texture is incomplete because the filtering parameters are GL_LINEAR, but the texture is an unsigned integer format. When creating integer format textures, you should always set the texture's parameters to valid values.

Read More

Monday, October 16, 2017

How to cast and receive shadows with RawShaderMaterial?

Leave a Comment

I have a RawShaderMaterial with lighting for InstancedBufferGeometry

How can I cast and receive shadows with this shader?

Here is my material:

var uniforms = Object.assign(      THREE.UniformsLib['lights'],      {         map: { type: "t", value: texture },     }     );  var material = new THREE.RawShaderMaterial( {     lights: true,     uniforms: uniforms,     vertexShader: document.getElementById( 'vs' ).textContent,     fragmentShader: document.getElementById( 'fs' ).textContent,     transparent: false     } ); 

Full example: http://thegrook.com/three.js/shadow1.html

Thanks

0 Answers

Read More

Friday, March 24, 2017

Weird behavior if DataTextures are not square (1:1)

Leave a Comment

*UPDATE: Photos of the expected and weird behaviors are at the bottom of this post.

I have a pair of shader programs where everything works great if my DataTextures are square (1:1), but if one or both are 2:1 (width:height) ratio the behavior gets messed up. I can extend each of the buffers with unused filler to make sure they are always square, but this seems unnecessarily costly (memory-wise) in the long run, as one of the two buffer sizes is quite large to start. Is there a way to handle a 2:1 buffer in this scenario?

I have a pair of shader programs:

  1. The first is a single frag shader used to calculate the physics for my program (it writes out a texture tPositions to be read by the second set of shaders). It is driven by Three.js's GPUComputeRenderer script (resolution set at the size of my largest buffer.)
  2. The second pair of shaders (vert and frag) use the data texture tPositions produced by the first shader program to then render out the visualization (resolution set at the window size).

The visualization is a grid of variously shaped particle clouds. In the shader programs, there are textures of two different sizes: The smaller sized textures contain information for each of the particle clouds (one texel per cloud), larger sized textures contain information for each particle in all of the clouds (one texel per particle). Both have a certain amount of unused filler tacked on the end to fill them out to a power of 2.

Texel-per-particle sized textures (large): tPositions, tOffsets

Texel-per-cloud sized textures (small): tGridPositionsAndSeeds, tSelectionFactors

As I said before, the problem is that when these two buffer sizes (the large and the small) are at a 1:1 (width: height) ratio, the programs work just fine; however, when one or both are at a 2:1 (width:height) ratio the behavior is a mess. What accounts for this, and how can I address it? Thanks in advance!

UPDATE: Could the problem be related to my housing the texel coords to read the tPosition texture in the shader's position attribute in the second shader program? If so, perhaps this Github issue regarding texel coords in the position attribute may be related, though I can't find a corresponding question/answer here on SO.

UPDATE 2: I'm also looking into whether this could be an unpack alignment issue. Thoughts?

Here's the set up in Three.js for the first shader program:

function initComputeRenderer() {      textureData = MotifGrid.getBufferData();      gpuCompute = new GPUComputationRenderer( textureData.uPerParticleBufferWidth, textureData.uPerParticleBufferHeight, renderer );      dtPositions = gpuCompute.createTexture();     dtPositions.image.data = textureData.tPositions;      offsetsTexture = new THREE.DataTexture( textureData.tOffsets, textureData.uPerParticleBufferWidth, textureData.uPerParticleBufferHeight, THREE.RGBAFormat, THREE.FloatType );     offsetsTexture.needsUpdate = true;      gridPositionsAndSeedsTexture = new THREE.DataTexture( textureData.tGridPositionsAndSeeds, textureData.uPerMotifBufferWidth, textureData.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );     gridPositionsAndSeedsTexture.needsUpdate = true;      selectionFactorsTexture = new THREE.DataTexture( textureData.tSelectionFactors, textureData.uPerMotifBufferWidth, textureData.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );     selectionFactorsTexture.needsUpdate = true;      positionVariable = gpuCompute.addVariable( "tPositions", document.getElementById( 'position_fragment_shader' ).textContent, dtPositions );     positionVariable.wrapS = THREE.RepeatWrapping; // repeat wrapping for use only with bit powers: 8x8, 16x16, etc.     positionVariable.wrapT = THREE.RepeatWrapping;      gpuCompute.setVariableDependencies( positionVariable, [ positionVariable ] );      positionUniforms = positionVariable.material.uniforms;     positionUniforms.tOffsets = { type: "t", value: offsetsTexture };     positionUniforms.tGridPositionsAndSeeds = { type: "t", value: gridPositionsAndSeedsTexture };     positionUniforms.tSelectionFactors = { type: "t", value: selectionFactorsTexture };     positionUniforms.uPerMotifBufferWidth = { type : "f", value : textureData.uPerMotifBufferWidth };     positionUniforms.uPerMotifBufferHeight = { type : "f", value : textureData.uPerMotifBufferHeight };     positionUniforms.uTime = { type: "f", value: 0.0 };     positionUniforms.uXOffW = { type: "f", value: 0.5 };  } 

Here is the first shader program (only a frag for physics calculations):

   // tPositions is handled by the GPUCompute script     uniform sampler2D tOffsets;      uniform sampler2D tGridPositionsAndSeeds;     uniform sampler2D tSelectionFactors;     uniform float uPerMotifBufferWidth;     uniform float uPerMotifBufferHeight;     uniform float uTime;     uniform float uXOffW;      [...skipping a noise function for brevity...]      void main() {          vec2 uv = gl_FragCoord.xy / resolution.xy;          vec4 offsets = texture2D( tOffsets, uv ).xyzw;         float alphaMass = offsets.z;         float cellIndex = offsets.w;          if (cellIndex >= 0.0) {              float damping = 0.98;              float texelSizeX = 1.0 / uPerMotifBufferWidth;             float texelSizeY = 1.0 / uPerMotifBufferHeight;             vec2 perMotifUV = vec2( mod(cellIndex, uPerMotifBufferWidth)*texelSizeX, floor(cellIndex / uPerMotifBufferHeight)*texelSizeY );             perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);              vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;             float swapState = selectionFactors.x;             vec4 gridPosition = texture2D( tGridPositionsAndSeeds, perMotifUV ).xyzw;             vec2 noiseSeed = gridPosition.zw;             vec4 nowPos;             vec2 velocity;              nowPos = texture2D( tPositions, uv ).xyzw;             velocity = vec2(nowPos.z, nowPos.w);              if ( swapState == 0.0 ) {                 nowPos = texture2D( tPositions, uv ).xyzw;                 velocity = vec2(nowPos.z, nowPos.w);             } else { // if swapState == 1                 //nowPos = vec4( -(uTime) + gridPosition.x + offsets.x, gridPosition.y + offsets.y, 0.0, 0.0 );                 nowPos = vec4( -(uTime) + offsets.x, offsets.y, 0.0, 0.0 );                 velocity = vec2(0.0, 0.0);             }              [...skipping the physics for brevity...]              vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);             // Write new position out             gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y);    } 

Here is the setup for the second shader program: Note: The renderer for this section is a WebGLRenderer at window size

function makePerParticleReferencePositions() {      var positions = new Float32Array( perParticleBufferSize * 3 );      var texelSizeX = 1 / perParticleBufferDimensions.width;     var texelSizeY = 1 / perParticleBufferDimensions.height;      for ( var j = 0, j3 = 0; j < perParticleBufferSize; j ++, j3 += 3 ) {          positions[ j3 + 0 ] = ( ( j % perParticleBufferDimensions.width ) / perParticleBufferDimensions.width ) + ( 0.5 * texelSizeX );         positions[ j3 + 1 ] = ( Math.floor( j / perParticleBufferDimensions.height ) / perParticleBufferDimensions.height ) + ( 0.5 * texelSizeY );         positions[ j3 + 2 ] = j * 0.0001; // this is the real z value for the particle display      }      return positions; }  var positions = makePerParticleReferencePositions();  ...  // Add attributes to the BufferGeometry:  gridOfMotifs.geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); gridOfMotifs.geometry.addAttribute( 'aTextureIndex', new THREE.BufferAttribute( motifGridAttributes.aTextureIndex, 1 ) ); gridOfMotifs.geometry.addAttribute( 'aAlpha', new THREE.BufferAttribute( motifGridAttributes.aAlpha, 1 ) ); gridOfMotifs.geometry.addAttribute( 'aCellIndex', new THREE.BufferAttribute(         motifGridAttributes.aCellIndex, 1 ) );  uniformValues = {}; uniformValues.tSelectionFactors = motifGridAttributes.tSelectionFactors; uniformValues.uPerMotifBufferWidth = motifGridAttributes.uPerMotifBufferWidth; uniformValues.uPerMotifBufferHeight = motifGridAttributes.uPerMotifBufferHeight;  gridOfMotifs.geometry.computeBoundingSphere();  ...  function makeCustomUniforms( uniformValues ) {      selectionFactorsTexture = new THREE.DataTexture( uniformValues.tSelectionFactors, uniformValues.uPerMotifBufferWidth, uniformValues.uPerMotifBufferHeight, THREE.RGBAFormat, THREE.FloatType );     selectionFactorsTexture.needsUpdate = true;      var customUniforms = {         tPositions : { type : "t", value : null },         tSelectionFactors : { type : "t", value : selectionFactorsTexture },         uPerMotifBufferWidth : { type : "f", value : uniformValues.uPerMotifBufferWidth },         uPerMotifBufferHeight : { type : "f", value : uniformValues.uPerMotifBufferHeight },         uTextureSheet : { type : "t", value : texture }, // this is a sprite sheet of all 10 strokes         uPointSize : { type : "f", value : 18.0 }, // the radius of a point in WebGL units, e.g. 30.0         // Coords for the hatch textures:         uTextureCoordSizeX : { type : "f", value : 1.0 / numTexturesInSheet },         uTextureCoordSizeY : { type : "f", value : 1.0 }, // the size of a texture in the texture map ( they're square, thus only one value )     };     return customUniforms; } 

And here is the corresponding shader program (vert & frag):

Vertex shader:

    uniform sampler2D tPositions;     uniform sampler2D tSelectionFactors;     uniform float uPerMotifBufferWidth;     uniform float uPerMotifBufferHeight;     uniform sampler2D uTextureSheet;     uniform float uPointSize; // the radius size of the point in WebGL units, e.g. "30.0"     uniform float uTextureCoordSizeX; // vertical dimension of each texture given the full side = 1     uniform float uTextureCoordSizeY; // horizontal dimension of each texture given the full side = 1      attribute float aTextureIndex;     attribute float aAlpha;     attribute float aCellIndex;      varying float vCellIndex;     varying vec2 vTextureCoords;     varying vec2 vTextureSize;     varying float vAlpha;     varying vec3 vColor;     varying float vDensity;     [...skipping noise function for brevity...]      void main() {          vec4 tmpPos = texture2D( tPositions, position.xy );         vec2 pos = tmpPos.xy;         vec2 vel = tmpPos.zw;          vCellIndex = aCellIndex;          if (aCellIndex >= 0.0) { // buffer filler cell indexes are -1              float texelSizeX = 1.0 / uPerMotifBufferWidth;             float texelSizeY = 1.0 / uPerMotifBufferHeight;             vec2 perMotifUV = vec2( mod(aCellIndex, uPerMotifBufferWidth)*texelSizeX, floor(aCellIndex / uPerMotifBufferHeight)*texelSizeY );             perMotifUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);              vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;             float aSelectedMotif = selectionFactors.x;             float aColor = selectionFactors.y;             float fadeFactor = selectionFactors.z;              vTextureCoords = vec2( aTextureIndex * uTextureCoordSizeX, 0 );             vTextureSize = vec2( uTextureCoordSizeX, uTextureCoordSizeY );              vAlpha = aAlpha * fadeFactor;             vDensity = vel.x + vel.y;             vAlpha *= abs( vDensity * 3.0 );              vColor = vec3( 1.0, aColor, 1.0 ); // set RGB color associated to vertex; use later in fragment shader.              gl_PointSize = uPointSize;          } else { // if this is a filler cell index (-1)             vAlpha = 0.0;             vDensity = 0.0;             vColor = vec3(0.0, 0.0, 0.0);             gl_PointSize = 0.0;         }         gl_Position = projectionMatrix * modelViewMatrix * vec4( pos.x, pos.y, position.z, 1.0 ); // position holds the real z value. The z value of "color" is a component of velocity     } 

Fragment shader:

    uniform sampler2D tPositions;     uniform sampler2D uTextureSheet;      varying float vCellIndex;     varying vec2 vTextureCoords;     varying vec2 vTextureSize;     varying float vAlpha;     varying vec3 vColor;     varying float vDensity;        void main() {         gl_FragColor = vec4( vColor, vAlpha );          if (vCellIndex >= 0.0) { // only render out the texture if this point is not a buffer filler             vec2 realTexCoord = vTextureCoords + ( gl_PointCoord * vTextureSize );             gl_FragColor = gl_FragColor * texture2D( uTextureSheet, realTexCoord );         }     } 

Expected Behavior: I can achieve this by forcing all the DataTextures to be 1:1 expected behavior - shaped particle clouds correctly assembled and displayed in an offset grid

Weird Behavior: When the smaller DataTextures are 2:1 those perfectly horizontal clouds in the top right of the picture below form and have messed up physics. When the larger DataTextures are 2:1, the grid is skewed, and the clouds appear to be missing parts (as seen below). When both the small and large textures are 2:1, both odd behaviors happen (this is the case in the image below). weird behavior - particle clouds incorrectly assembled and displayed in a skewed grid

0 Answers

Read More

Monday, June 13, 2016

Coloring heightmap faces instead of vertices

Leave a Comment

I'm trying to create a heightmap colored by face, instead of vertex. For example, this is what I currently have:

My terrain, by vertex But this is what I want: Per face coloring

I read that I have to split each vertex into multiple vertices, then index each separately for the triangles. I also know that blender has a function like this for its models (split vertices, or something?), but I'm not sure what kind of algorithm I would follow for this. This would be the last resort, because multiplying the amount of vertices in the mesh for no reason other than color doesn't seem efficient.

I also discovered something called flatshading (using the flat qualifier on the pixel color in the shaders), but it seems to only draw squares instead of triangles. Is there a way to make it shade triangles?

Flatshaded

For reference, this is my current heightmap generation code:

public class HeightMap extends GameModel {  private static final float START_X = -0.5f; private static final float START_Z = -0.5f; private static final float REFLECTANCE = .1f;  public HeightMap(float minY, float maxY, float persistence, int width, int height, float spikeness) {     super(createMesh(minY, maxY, persistence, width, height, spikeness), REFLECTANCE); }  protected static Mesh createMesh(final float minY, final float maxY, final float persistence, final int width,         final int height, float spikeness) {     SimplexNoise noise = new SimplexNoise(128, persistence, 2);// Utils.getRandom().nextInt());      float xStep = Math.abs(START_X * 2) / (width - 1);     float zStep = Math.abs(START_Z * 2) / (height - 1);      List<Float> positions = new ArrayList<>();     List<Integer> indices = new ArrayList<>();      for (int z = 0; z < height; z++) {         for (int x = 0; x < width; x++) {             // scale from [-1, 1] to [minY, maxY]             float heightY = (float) ((noise.getNoise(x * xStep * spikeness, z * zStep * spikeness) + 1f) / 2                     * (maxY - minY) + minY);              positions.add(START_X + x * xStep);             positions.add(heightY);             positions.add(START_Z + z * zStep);              // Create indices             if (x < width - 1 && z < height - 1) {                 int leftTop = z * width + x;                 int leftBottom = (z + 1) * width + x;                 int rightBottom = (z + 1) * width + x + 1;                 int rightTop = z * width + x + 1;                  indices.add(leftTop);                 indices.add(leftBottom);                 indices.add(rightTop);                  indices.add(rightTop);                 indices.add(leftBottom);                 indices.add(rightBottom);             }         }     }      float[] verticesArr = Utils.listToArray(positions);     Color c = new Color(147, 105, 59);     float[] colorArr = new float[positions.size()];     for (int i = 0; i < colorArr.length; i += 3) {         float brightness = (Utils.getRandom().nextFloat() - 0.5f) * 0.5f;         colorArr[i] = (float) c.getRed() / 255f + brightness;         colorArr[i + 1] = (float) c.getGreen() / 255f + brightness;         colorArr[i + 2] = (float) c.getBlue() / 255f + brightness;     }     int[] indicesArr = indices.stream().mapToInt((i) -> i).toArray();      float[] normalArr = calcNormals(verticesArr, width, height);      return new Mesh(verticesArr, colorArr, normalArr, indicesArr); }  private static float[] calcNormals(float[] posArr, int width, int height) {     Vector3f v0 = new Vector3f();     Vector3f v1 = new Vector3f();     Vector3f v2 = new Vector3f();     Vector3f v3 = new Vector3f();     Vector3f v4 = new Vector3f();     Vector3f v12 = new Vector3f();     Vector3f v23 = new Vector3f();     Vector3f v34 = new Vector3f();     Vector3f v41 = new Vector3f();     List<Float> normals = new ArrayList<>();     Vector3f normal = new Vector3f();     for (int row = 0; row < height; row++) {         for (int col = 0; col < width; col++) {             if (row > 0 && row < height - 1 && col > 0 && col < width - 1) {                 int i0 = row * width * 3 + col * 3;                 v0.x = posArr[i0];                 v0.y = posArr[i0 + 1];                 v0.z = posArr[i0 + 2];                  int i1 = row * width * 3 + (col - 1) * 3;                 v1.x = posArr[i1];                 v1.y = posArr[i1 + 1];                 v1.z = posArr[i1 + 2];                 v1 = v1.sub(v0);                  int i2 = (row + 1) * width * 3 + col * 3;                 v2.x = posArr[i2];                 v2.y = posArr[i2 + 1];                 v2.z = posArr[i2 + 2];                 v2 = v2.sub(v0);                  int i3 = (row) * width * 3 + (col + 1) * 3;                 v3.x = posArr[i3];                 v3.y = posArr[i3 + 1];                 v3.z = posArr[i3 + 2];                 v3 = v3.sub(v0);                  int i4 = (row - 1) * width * 3 + col * 3;                 v4.x = posArr[i4];                 v4.y = posArr[i4 + 1];                 v4.z = posArr[i4 + 2];                 v4 = v4.sub(v0);                  v1.cross(v2, v12);                 v12.normalize();                  v2.cross(v3, v23);                 v23.normalize();                  v3.cross(v4, v34);                 v34.normalize();                  v4.cross(v1, v41);                 v41.normalize();                  normal = v12.add(v23).add(v34).add(v41);                 normal.normalize();             } else {                 normal.x = 0;                 normal.y = 1;                 normal.z = 0;             }             normal.normalize();             normals.add(normal.x);             normals.add(normal.y);             normals.add(normal.z);         }     }     return Utils.listToArray(normals); }  } 

Edit

I've tried doing a couple things. I tried rearranging the indices with flat shading, but that didn't give me the look I wanted. I tried using a uniform vec3 colors and indexing it with gl_VertexID or gl_InstanceID (I'm not entirely sure the difference), but I couldn't get the arrays to compile. Here is the github repo, by the way.

1 Answers

Answers 1

flat qualified fragment shader inputs will receive the same value for the same primitive. In your case, a triangle.

Of course, a triangle is composed of 3 vertices. And if the vertex shaders output 3 different values, how does the fragment shader know which value to get?

This comes down to what is called the "provoking vertex." When you render, you specify a particular primitive to use in your glDraw* call (GL_TRIANGLE_STRIP, GL_TRIANGLES, etc). These primitive types will generate a number of base primitives (ie: single triangle), based on how many vertices you provided.

When a base primitive is generated, one of the vertices in that base primitive is said to be the "provoking vertex". It is that vertex's data that is used for all flat parameters.

The reason you're seeing what you are seeing is because the two adjacent triangles just happen to be using the same provoking vertex. Your mesh is smooth, so two adjacent triangles share 2 vertices. Your mesh generation just so happens to be generating a mesh such that the provoking vertex for each triangle is shared between them. Which means that the two triangles will get the same flat value.

You will need to adjust your index list or otherwise alter your mesh generation so that this doesn't happen. Or you can just divide your mesh into individual triangles; that's probably much easier.

Read More

Saturday, April 16, 2016

Trying to port a GLSL glass shader to Processing 3.0

Leave a Comment

EDITED

I am beginner on Processing language and GLSL shaders. I am trying to port a fresnel+cubemap shader for a glass material. But as result my shape ever disappear, instead... :-(

My vertex shader is:

const float Air = 1.0; const float Glass = 1.51714;  const float Eta = Air / Glass;  const float R0 = ((Air - Glass) * (Air - Glass)) / ((Air + Glass) * (Air + Glass));  uniform mat4 transform; uniform mat4 modelview; uniform mat3 normalMatrix;  attribute vec4 vertex; attribute vec3 normal;  varying vec3 v_reflection; varying vec3 v_refraction; varying float v_fresnel;  void main(void){      vec4 t_vertex = modelview * vertex;      vec3 incident = normalize(vec3(t_vertex));      vec3 t_normal = normalMatrix * normal;      v_refraction = refract(incident, t_normal, Eta);     v_reflection = reflect(incident, t_normal);      v_fresnel = R0 + (1.0 - R0) * pow((1.0 - dot(-incident, t_normal)), 5.0);      gl_Position = transform * t_vertex; } 

And the fragment shader:

#ifdef GL_ES precision mediump float; precision mediump int; #endif  uniform samplerCube cubemap;  varying vec3 v_refraction; varying vec3 v_reflection; varying float v_fresnel;  void main(void){     vec4 refractionColor = textureCube(cubemap, normalize(v_refraction));     vec4 reflectionColor = textureCube(cubemap, normalize(v_reflection));      gl_FragColor = mix(refractionColor, reflectionColor, v_fresnel); } 

I am testing this shader with the Processing 3.0 sketch bellow (edited), on Android Mode:

PShader shader; PShape sphere;  void setup() {   fullScreen(P3D);   noStroke();    shader = loadShader("glass.frag.glsl", "glass.vert.glsl");   openCubeMap("posx.png", "negx.png", "posy.png", "negy.png", "posz.png", "negz.png");   shader.set("cubemap", 1);    sphere = createShape(SPHERE, 120);   sphere.setFill(color(-1, 50)); }   void draw() {   background(0);          directionalLight(102, 102, 102, 0, 0, -1);   lightSpecular(204, 204, 204);   directionalLight(102, 102, 102, 0, 1, -1);   specular(100, 150, 150);    translate(width / 2, height / 2);   shader(shader);   shape(sphere); }    void openCubeMap(String posX, String negX, String posY, String negY, String posZ, String negZ) {    PGL pgl = beginPGL();   // create the OpenGL-based cubeMap   IntBuffer envMapTextureID = IntBuffer.allocate(1);   pgl.genTextures(1, envMapTextureID);   pgl.activeTexture(PGL.TEXTURE1);   pgl.enable(PGL.TEXTURE_CUBE_MAP);     pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, envMapTextureID.get(0));   pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_S, PGL.CLAMP_TO_EDGE);   pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_T, PGL.CLAMP_TO_EDGE);   pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_R, PGL.CLAMP_TO_EDGE);   pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MIN_FILTER, PGL.LINEAR);   pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MAG_FILTER, PGL.LINEAR);    //Load in textures   String[] textureNames = { posX, negX, posY, negY, posZ, negZ };   for (int i=0; i<textureNames.length; i++) {         PImage texture = loadImage(textureNames[i]);     int w = texture.width;     int h = texture.height;     texture.loadPixels();     pgl.texImage2D(PGL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, PGL.RGBA, w, h, 0, PGL.RGBA, PGL.UNSIGNED_BYTE, IntBuffer.wrap(texture.pixels));   }    endPGL(); } 

And I am using this images to build the cubemap.

Someone know how I can make this work?

0 Answers

Read More