How to use the custom shader for drawing the height map(mesh) in threepp
Hi, here is class I used to draw a mesh
// =============================================================
// Helper Functions (outside the class)
// =============================================================
// Example height function
float f(float x, float y, float tx = 0.0f)
{
float dx = x - 0.5f;
float dy = y - 0.5f;
float r = std::sqrt(dx * dx + dy * dy);
return std::sin((r + tx) * 8.0f * 3.1415926f) * 0.5f;
}
// Generate grid like your old code
void generate_grid(int N, std::vector<threepp::Vector3>& vertices, std::vector<unsigned int>& indices)
{
vertices.clear();
indices.clear();
for (int j = 0; j <= N; ++j)
{
for (int i = 0; i <= N; ++i)
{
float x = (float)i / (float)N;
float y = (float)j / (float)N;
float z = f(x, y);
vertices.push_back({x, y, z});
}
}
for (int j = 0; j < N; ++j)
{
for (int i = 0; i < N; ++i)
{
int row1 = j * (N + 1);
int row2 = (j + 1) * (N + 1);
// triangle 1
indices.push_back(row1 + i);
indices.push_back(row1 + i + 1);
indices.push_back(row2 + i + 1);
// triangle 2
indices.push_back(row1 + i);
indices.push_back(row2 + i + 1);
indices.push_back(row2 + i);
}
}
}
///////////////////////////////////////////////////////////////////////////////
#define TEST 1
#if not TEST
class SurfaceRenderer
{
public:
SurfaceRenderer()
{
m_Geometry = std::make_shared<threepp::BufferGeometry>();
m_Material = threepp::ShaderMaterial::create();
// Use the simplified shaders below
m_Material->vertexShader = m_VertexShader;
m_Material->fragmentShader = m_FragmentShader;
// No need for ZL/ZH uniforms in the simplified version
m_Material->uniforms = {};
m_Mesh = std::make_shared<threepp::Mesh>(m_Geometry, m_Material);
m_Mesh->frustumCulled = false;
}
void SetData(const std::vector<threepp::Vector3>& vertices,
const std::vector<unsigned int>& indices)
{
std::vector<float> verticesData;
verticesData.reserve(vertices.size() * 3);
for (const auto& v : vertices)
{
verticesData.push_back(v.x);
verticesData.push_back(v.y);
verticesData.push_back(v.z);
}
auto positionsUnique = threepp::TypedBufferAttribute<float>::create(verticesData, 3);
m_Geometry->setAttribute("position", std::move(positionsUnique));
m_Geometry->setIndex(indices);
m_Geometry->computeVertexNormals();
m_Geometry->computeBoundingSphere();
m_Geometry->computeBoundingBox();
}
void SetZRange(float /*zl*/, float /*zh*/) {}
std::shared_ptr<threepp::Mesh> GetMesh()
{
return m_Mesh;
}
private:
std::shared_ptr<threepp::BufferGeometry> m_Geometry;
std::shared_ptr<threepp::ShaderMaterial> m_Material;
std::shared_ptr<threepp::Mesh> m_Mesh;
const std::string m_VertexShader = R"(#version 330 core
layout(location = 0) in vec3 vertPos;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
out vec3 pos;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(vertPos, 1.0);
pos = vertPos;
})";
const std::string m_FragmentShader = R"(#version 330 core
uniform float ZL;
uniform float ZH;
in vec3 pos;
out vec3 color;
vec3 jet(float t)
{
return clamp(vec3(1.5) - abs(4.0 * vec3(t) + vec3(-3, -2, -1)),
vec3(0), vec3(1));
}
void main()
{
float param = (pos.z - ZL) / (ZH - ZL);
color = jet(param);
})";
};
#else
// =============================================================
// TEST MODE: MeshBasicMaterial-based Renderer
// =============================================================
class SurfaceRenderer
{
public:
SurfaceRenderer()
{
m_Geometry = std::make_shared<threepp::BufferGeometry>();
m_Material = threepp::MeshBasicMaterial::create();
m_Material->color = threepp::Color::red;
m_Mesh = std::make_shared<threepp::Mesh>(m_Geometry, m_Material);
}
void SetData(const std::vector<threepp::Vector3>& vertices,
const std::vector<unsigned int>& indices)
{
std::vector<float> verticesData;
verticesData.reserve(vertices.size() * 3);
for (auto& v : vertices)
{
verticesData.push_back(v.x);
verticesData.push_back(v.y);
verticesData.push_back(v.z);
}
auto positionsUnique = threepp::TypedBufferAttribute<float>::create(verticesData, 3);
m_Geometry->setAttribute("position", std::move(positionsUnique));
m_Geometry->setIndex(indices);
m_Geometry->computeVertexNormals();
m_Geometry->computeBoundingSphere();
m_Geometry->computeBoundingBox();
}
void SetZRange(float /*zl*/, float /*zh*/)
{
// ignored for testing
}
std::shared_ptr<threepp::Mesh> GetMesh()
{
return m_Mesh;
}
private:
std::shared_ptr<threepp::BufferGeometry> m_Geometry;
std::shared_ptr<threepp::MeshBasicMaterial> m_Material;
std::shared_ptr<threepp::Mesh> m_Mesh;
const std::string m_VertexShader = "";
const std::string m_FragmentShader = "";
};
#endif
Here is the client code to use this class:
// Create and keep the instance alive
surface = std::make_shared<SurfaceRenderer>();
std::vector<threepp::Vector3> vertices1;
std::vector<unsigned int> indices1;
generate_grid(50, vertices1, indices1);
surface->SetData(vertices1, indices1);
float zl = +std::numeric_limits<float>::max();
float zh = -std::numeric_limits<float>::max();
for (auto &v: vertices1)
{
if(v.z < zl) zl = v.z;
if(v.z > zh) zh = v.z;
}
surface->SetZRange(zl, zh);
scene->add(surface->GetMesh());
You can see that if the TEST is defined as 1, then the simplified red mesh is shown, see the image shot below:
But if the TEST is defined as 0, nothing is shown. I mean I can't use the ShaderMaterial class for customized shaders.
The expected output is like below, it is a kind of height map(jet color map), which means the higher parts of the mesh will shown in red, and the lower parts of the mesh will shown in blue, see image shot below:
The above image is drawn by pure OpenGL code/render, I'm trying to migrate the code from the pure OpenGL to threepp framework, but found a bit hard. Can you help? Thanks.
BTW, It looks like the mouse rotation method has slightly different along different x,y,z axis. I mean in some axis' rotation, it is hard to rotate. Is the mouse rotation follow the way like: Object Mouse Trackball - OpenGL Wiki?
In my own pure OpenGL code, I don't see the mouse rotation is different if I rotate on different direction. But under threepp, it looks like in some axis, the rotation angle has a positive and negative limit? Thanks.
For the colormap, could you use LUT? https://github.com/markaren/threepp/blob/master/examples/misc/lut.cpp
For the colormap, could you use LUT? https://github.com/markaren/threepp/blob/master/examples/misc/lut.cpp
Thanks, you mean look up table for the color selection? I think that code does not touch the shader code.
But for me, I need some customized shader code, it will make the scene much flexible. I can tweak the shader code, and generate many different kinds of color effects. And the shader code runs much faster, because it runs on GPU.
I'm not sure if the threepp library has some kinds of "shader debug log" information I can use?
I mean I still has the issue, but I don't know how to debug it, whether it is a shader code error or other error, the code builds OK, but it just shows nothing when I run it.
Thanks.
renderer.checkShaderErrors = true; might produce output, but I'm not completely sure.
renderer.checkShaderErrors = true;might produce output, but I'm not completely sure.
OK, thanks.
When enabled this option, I see one log message:
[Shader error] Attached vertex shader is not compiled.
So, I will check whether the vertex shader code has some issue.
OK, now, I see that I find the reason.
If you looked at the source code here:
https://github.com/markaren/threepp/blob/ada259b72435e380c8e3def429fc8001233b1a8f/src/threepp/renderers/gl/GLProgram.cpp#L718
I see there are many shader code prefix string which is defined as std::string prefixVertex, prefixFragment;
Which means unless I set the value isRawShaderMaterial = true. All my code will append to the prefix string.
Now, which the code changes here:
// Corrected Vertex Shader: No #version at the top
const std::string m_VertexShader = R"(
out vec3 pos;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
pos = position;
}
)";
const std::string m_FragmentShader = R"(
uniform float ZL;
uniform float ZH;
in vec3 pos;
out vec4 color;
vec3 jet(float t)
{
return clamp(vec3(1.5) - abs(4.0 * vec3(t) + vec3(-3, -2, -1)),
vec3(0), vec3(1));
}
void main()
{
float param = (pos.z - ZL) / (ZH - ZL);
vec3 c = jet(param);
color = vec4(c, 1.0);
}
)";
And here is the result image:
The shader issue is fixed now, but I'm not sure how to fix the mouse rotation issue mentioned in the first post. In some axis rotation, the angle get locked or limited.
class OrbitControls {
public:
bool enabled = true;
Vector3 target;
float minDistance = 0.f;
float maxDistance = std::numeric_limits<float>::infinity();
float minZoom = 0.f;
float maxZoom = std::numeric_limits<float>::infinity();
float minPolarAngle = 0.f;
float maxPolarAngle = math::PI;
// How far you can orbit horizontally, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
float minAzimuthAngle = -std::numeric_limits<float>::infinity();// radians
float maxAzimuthAngle = std::numeric_limits<float>::infinity(); // radians
Maybe, I need to set the PolarAngle to infinity to unlock the limit.
https://threejs.org/docs/#examples/en/controls/TrackballControls
I think what I need is a Trackball control.
While when I looked at the source code of threepp here:
threepp/include/threepp/controls at master · markaren/threepp
I see it does not have the trackball control?
Thanks.
I see it does not have the trackball control?
Correct. https://github.com/mrdoob/three.js/blob/r129/examples/jsm/controls/TrackballControls.js is not implemented.
I have create another issue for the trackball control implementation request, thanks.
There are several class of the material: RawShaderMaterial and ShaderMaterial, if I use the former one, the full shader code is needed. If the later one is used, only portion of the shader code is needed. Some of the uniform variables and other codes were already implemented by the threepp framework. I'm not sure what's the advantage of using the later one, maybe it will affect the raytracking feature or other features? Any ideas? Thanks.
It should work the same way as in three.js. I don't really have the full details.