Custom Scene Node Lighting

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Hotari
Posts: 9
Joined: Tue Dec 25, 2018 2:57 am

Custom Scene Node Lighting

Post by Hotari »

Hello.

I want to draw a dynamic scene node in per-pixel lighting. I referred the tutorials and tried this.

Code: Select all

 
#include <irrlicht.h>
 
using namespace irr;
using namespace core;
using namespace video;
using namespace scene;
using namespace gui;
using namespace io;
 
class CSceneNode : public ISceneNode {
public:
    CSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) : ISceneNode(parent, mgr, id), meshBuffer(new SMeshBuffer()) {
        meshBuffer->Material.Wireframe = false;
        //meshBuffer->Material.Lighting = false;
        meshBuffer->Material.MaterialType = EMT_PARALLAX_MAP_SOLID;
 
        meshBuffer->Vertices.set_used(6);
        meshBuffer->Vertices[0] = S3DVertex(0, 0, 10, 1, 1, 0, SColor(255, 0, 255, 255), 0, 1);
        meshBuffer->Vertices[1] = S3DVertex(10, 0, -10, 1, 0, 0, SColor(255, 255, 0, 255), 0.5f, 0);
        meshBuffer->Vertices[2] = S3DVertex(0, 20, 0, 0, 1, 1, SColor(255, 255, 255, 0), 0, 0);
        meshBuffer->Vertices[3] = S3DVertex(-10, 0, -10, 0, 0, 1, SColor(255, 0, 255, 0), 0.5f, 1);
 
        meshBuffer->Vertices[4] = S3DVertex(0, 0, 10, 1, 1, 0, SColor(255, 0, 255, 255), 1, 1);
        meshBuffer->Vertices[5] = S3DVertex(0, 20, 0, 0, 1, 1, SColor(255, 255, 255, 0), 1, 0);
 
        meshBuffer->Indices.set_used(12);
        u16 indices[] = { 2,3,0, 1,3,2, 1,4,3, 5,4,1 };
        for (s32 i = 0; i < 12; i++) {
            meshBuffer->Indices[i] = indices[i];
        }
 
        meshBuffer->BoundingBox.reset(meshBuffer->Vertices[0].Pos);
        for (s32 i = 1; i < 4; ++i) {
            meshBuffer->BoundingBox.addInternalPoint(meshBuffer->Vertices[i].Pos);
        }
    }
 
    virtual void OnRegisterSceneNode() {
        if (IsVisible) {
            SceneManager->registerNodeForRendering(this);
        }
 
        ISceneNode::OnRegisterSceneNode();
    }
 
    virtual void render() {
        IVideoDriver* drv = SceneManager->getVideoDriver();
 
        drv->setMaterial(meshBuffer->Material);
        drv->setTransform(ETS_WORLD, AbsoluteTransformation);
        drv->drawMeshBuffer(meshBuffer);
    }
 
    virtual const aabbox3d<f32>& getBoundingBox() const
    {
        return meshBuffer->BoundingBox;
    }
 
    virtual u32 getMaterialCount() const
    {
        return 1;
    }
 
    virtual SMaterial& getMaterial(u32 i)
    {
        return meshBuffer->Material;
    }
 
private:
    SMeshBuffer* meshBuffer;
};
 
int main() {
    IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d<u32>(640, 480), 16, false);
    if (device == 0) {
        return 1;
    }
 
    IVideoDriver* drv = device->getVideoDriver();
    ISceneManager* mgr = device->getSceneManager();
 
    drv->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
 
    mgr->addCameraSceneNode(0, vector3df(0, 0, -40), vector3df(0, 0, 0));
    //mgr->addCameraSceneNodeFPS()->setPosition(vector3df(0, 0, -40));
    mgr->addLightSceneNode(0, vector3df(20, 0, -20));
    mgr->addSphereSceneNode(5.0f, 16, 0, 777, vector3df(20, 0, -20))->setMaterialFlag(EMF_LIGHTING, false);
 
    CSceneNode *node = new CSceneNode(mgr->getRootSceneNode(), mgr, 666);
    node->setMaterialTexture(0, drv->getTexture("a.png"));
    ITexture* HTM = drv->getTexture("ah.png");
    drv->makeNormalMapTexture(HTM);
    node->setMaterialTexture(1, HTM);
 
    ISceneNodeAnimator* animation = mgr->createRotationAnimator(vector3df(0.8f, 0, 0.3f));
    if (animation) {
        node->addAnimator(animation);
        animation->drop();
    }
 
    node->drop();
 
    while (device->run()) {
        drv->beginScene();
        //drv->beginScene(true, true, SColor(0, 100, 100, 100));
 
        mgr->drawAll();
 
        drv->endScene();
    }
 
    device->drop();
 
    return 0;
}
 
The result was NOT one I hoped.
Please tell me how to draw like tutorial 11.

ah.png is a grayscale of a.png

Thank you.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Scene Node Lighting

Post by CuteAlien »

It needs a meshbuffer with tangents. So SMeshBufferTangents which uses S3DVertexTangents. Irrlicht's IMeshManipulator has a createMeshWithTangents function which does that somehow automatic. But it takes and returns a mesh, so you have to put your meshbuffers in a mesh to use that one (and there really should be functions to just take meshbuffers and convert them ... guess no one wrote them yet).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Hotari
Posts: 9
Joined: Tue Dec 25, 2018 2:57 am

Re: Custom Scene Node Lighting

Post by Hotari »

Thank you.
I heard a good thing. :D

I corrected the code like this.
I added this method,

Code: Select all

 
IMeshBuffer* createMeshBufferWithTangents(IMeshBuffer* meshBuffer, IMeshManipulator* mnp, bool recalculateNormals = false, bool smooth = false, bool angleWeighted = false, bool calculateTangents = true) {
    if (!meshBuffer) {
        return 0;
    }
 
    const IMeshBuffer* const original = meshBuffer;
    const u32 indexCount = original->getIndexCount();
    const u16* indices = original->getIndices();
 
    SMeshBufferTangents* buffer = new SMeshBufferTangents();
 
    buffer->Material = original->getMaterial();
    buffer->Vertices.reallocate(indexCount);
    buffer->Indices.reallocate(indexCount);
 
    core::map<video::S3DVertexTangents, int> verticesMap;
    int vertexLocation;
 
    const video::E_VERTEX_TYPE vertexType = original->getVertexType();
    video::S3DVertexTangents newVertex;
    for (u32 i = 0; i < indexCount; i++) {
        switch (vertexType) {
        case video::EVT_STANDARD:
        {
            const video::S3DVertex oldVertex = ((const video::S3DVertex*)original->getVertices())[indices[i]];
            newVertex = video::S3DVertexTangents(oldVertex.Pos, oldVertex.Normal, oldVertex.Color, oldVertex.TCoords);
        }
        break;
 
        case video::EVT_2TCOORDS:
        {
            const video::S3DVertex2TCoords oldVertex = ((const video::S3DVertex2TCoords*)original->getVertices())[indices[i]];
            newVertex = video::S3DVertexTangents(oldVertex.Pos, oldVertex.Normal, oldVertex.Color, oldVertex.TCoords);
        }
        break;
 
        case video::EVT_TANGENTS:
        {
            const video::S3DVertexTangents oldVertex = ((const video::S3DVertexTangents*)original->getVertices())[indices[i]];
            newVertex = oldVertex;
        }
        break;
        }
 
        core::map<video::S3DVertexTangents, int>::Node* node = verticesMap.find(newVertex);
        if (node) {
            vertexLocation = node->getValue();
        }
        else {
            vertexLocation = buffer->Vertices.size();
            buffer->Vertices.push_back(newVertex);
            verticesMap.insert(newVertex, vertexLocation);
        }
 
        buffer->Indices.push_back(vertexLocation);
    }
 
    buffer->recalculateBoundingBox();
 
    if (calculateTangents) {
        mnp->recalculateTangents(buffer, recalculateNormals, smooth, angleWeighted);
    }
 
    return buffer;
}
 
and these lines in the constructor.

Code: Select all

 
...
for (s32 i = 0; i < 12; i++) {
    meshBuffer->Indices[i] = indices[i];
}
 
IMeshBuffer* newMeshBuffer = createMeshBufferWithTangents(meshBuffer, SceneManager->getMeshManipulator());
meshBuffer->drop();
meshBuffer = (SMeshBuffer*)newMeshBuffer;
 
meshBuffer->BoundingBox.reset(meshBuffer->Vertices[0].Pos);
...
 
Although, I thought that the behavior of shadow was wrong.
I don't know if the result is right... :(
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Scene Node Lighting

Post by CuteAlien »

Hm, add a screenshot maybe (you couldn't in your first post, but you can do that now). Note that this is only lighting, not shadows (but things away from light should still be dark).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Hotari
Posts: 9
Joined: Tue Dec 25, 2018 2:57 am

Re: Custom Scene Node Lighting

Post by Hotari »

It's not a screenshot image but...

Screen Capture
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Scene Node Lighting

Post by CuteAlien »

Hm, yeah - seriously hard to tell if it's correct. Looks OK to me on first view. Sometimes easier to see when you add a whole bunch of objects instead of just one. And maybe in 2 layers (objects in identical positions in both layers except for height).
Also might help to draw 3d lines from light to object-centers.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Hotari
Posts: 9
Joined: Tue Dec 25, 2018 2:57 am

Re: Custom Scene Node Lighting

Post by Hotari »

I tried this code,

Code: Select all

 
#include <irrlicht.h>
 
using namespace irr;
using namespace core;
using namespace video;
using namespace scene;
using namespace gui;
using namespace io;
 
IMeshBuffer* createMeshBufferWithTangents(IMeshBuffer* meshBuffer, IMeshManipulator* mnp, bool recalculateNormals = false, bool smooth = false, bool angleWeighted = false, bool calculateTangents = true) {
    if (!meshBuffer) {
        return 0;
    }
 
    const IMeshBuffer* const original = meshBuffer;
    const u32 indexCount = original->getIndexCount();
    const u16* indices = original->getIndices();
 
    SMeshBufferTangents* buffer = new SMeshBufferTangents();
 
    buffer->Material = original->getMaterial();
    buffer->Vertices.reallocate(indexCount);
    buffer->Indices.reallocate(indexCount);
 
    core::map<video::S3DVertexTangents, int> verticesMap;
    int vertexLocation;
 
    const video::E_VERTEX_TYPE vertexType = original->getVertexType();
    video::S3DVertexTangents newVertex;
    for (u32 i = 0; i < indexCount; i++) {
        switch (vertexType) {
        case video::EVT_STANDARD:
        {
            const video::S3DVertex oldVertex = ((const video::S3DVertex*)original->getVertices())[indices[i]];
            newVertex = video::S3DVertexTangents(oldVertex.Pos, oldVertex.Normal, oldVertex.Color, oldVertex.TCoords);
        }
        break;
 
        case video::EVT_2TCOORDS:
        {
            const video::S3DVertex2TCoords oldVertex = ((const video::S3DVertex2TCoords*)original->getVertices())[indices[i]];
            newVertex = video::S3DVertexTangents(oldVertex.Pos, oldVertex.Normal, oldVertex.Color, oldVertex.TCoords);
        }
        break;
 
        case video::EVT_TANGENTS:
        {
            const video::S3DVertexTangents oldVertex = ((const video::S3DVertexTangents*)original->getVertices())[indices[i]];
            newVertex = oldVertex;
        }
        break;
        }
 
        core::map<video::S3DVertexTangents, int>::Node* node = verticesMap.find(newVertex);
        if (node) {
            vertexLocation = node->getValue();
        }
        else {
            vertexLocation = buffer->Vertices.size();
            buffer->Vertices.push_back(newVertex);
            verticesMap.insert(newVertex, vertexLocation);
        }
 
        buffer->Indices.push_back(vertexLocation);
    }
 
    buffer->recalculateBoundingBox();
 
    if (calculateTangents) {
        mnp->recalculateTangents(buffer, recalculateNormals, smooth, angleWeighted);
    }
 
    return buffer;
}
 
class CSceneNode : public ISceneNode {
public:
    CSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) : ISceneNode(parent, mgr, id), meshBuffer(new SMeshBuffer()) {
        meshBuffer->Material.Wireframe = false;
        //meshBuffer->Material.Lighting = false;
        meshBuffer->Material.MaterialType = EMT_PARALLAX_MAP_SOLID;
 
        meshBuffer->Vertices.set_used(6);
        meshBuffer->Vertices[0] = S3DVertex(0, 0, 10, 1, 1, 0, SColor(255, 0, 255, 255), 0, 1);
        meshBuffer->Vertices[1] = S3DVertex(10, 0, -10, 1, 0, 0, SColor(255, 255, 0, 255), 0.5f, 0);
        meshBuffer->Vertices[2] = S3DVertex(0, 20, 0, 0, 1, 1, SColor(255, 255, 255, 0), 0, 0);
        meshBuffer->Vertices[3] = S3DVertex(-10, 0, -10, 0, 0, 1, SColor(255, 0, 255, 0), 0.5f, 1);
 
        meshBuffer->Vertices[4] = S3DVertex(0, 0, 10, 1, 1, 0, SColor(255, 0, 255, 255), 1, 1);
        meshBuffer->Vertices[5] = S3DVertex(0, 20, 0, 0, 1, 1, SColor(255, 255, 255, 0), 1, 0);
 
        meshBuffer->Indices.set_used(12);
        u16 indices[] = { 2,3,0, 1,3,2, 1,4,3, 5,4,1 };
        for (s32 i = 0; i < 12; i++) {
            meshBuffer->Indices[i] = indices[i];
        }
 
        IMeshBuffer* newMeshBuffer = createMeshBufferWithTangents(meshBuffer, SceneManager->getMeshManipulator());
        meshBuffer->drop();
        meshBuffer = (SMeshBuffer*)newMeshBuffer;
 
        meshBuffer->BoundingBox.reset(meshBuffer->Vertices[0].Pos);
        for (s32 i = 1; i < 4; ++i) {
            meshBuffer->BoundingBox.addInternalPoint(meshBuffer->Vertices[i].Pos);
        }
    }
 
    virtual void OnRegisterSceneNode() {
        if (IsVisible) {
            SceneManager->registerNodeForRendering(this);
        }
 
        ISceneNode::OnRegisterSceneNode();
    }
 
    virtual void render() {
        IVideoDriver* drv = SceneManager->getVideoDriver();
 
        drv->setMaterial(meshBuffer->Material);
        drv->setTransform(ETS_WORLD, AbsoluteTransformation);
        drv->drawMeshBuffer(meshBuffer);
    }
 
    virtual const aabbox3d<f32>& getBoundingBox() const
    {
        return meshBuffer->BoundingBox;
    }
 
    virtual u32 getMaterialCount() const
    {
        return 1;
    }
 
    virtual SMaterial& getMaterial(u32 i)
    {
        return meshBuffer->Material;
    }
 
private:
    SMeshBuffer* meshBuffer;
};
 
int main() {
    IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d<u32>(640, 480), 16, false);
    if (device == 0) {
        return 1;
    }
 
    IVideoDriver* drv = device->getVideoDriver();
    ISceneManager* mgr = device->getSceneManager();
 
    drv->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
 
 
    //----------------------------chnage
    mgr->addCameraSceneNode(0, vector3df(0, 0, -80), vector3df(0, 0, 0));
    //mgr->addCameraSceneNodeFPS()->setPosition(vector3df(0, 0, -80));
    mgr->addLightSceneNode(0, vector3df(0, 0, -20));
    mgr->addSphereSceneNode(5.0f, 16, 0, 777, vector3df(0, 0, -20))->setMaterialFlag(EMF_LIGHTING, false);
 
    ITexture* tex = drv->getTexture("a.png");
    ITexture* HTM = drv->getTexture("ah.png");
    drv->makeNormalMapTexture(HTM);
 
    s32 nodeCount = 8;
    f32 rad = 2 * PI / nodeCount;
    for (s32 i = 0; i < nodeCount; i++) {
        CSceneNode *node = new CSceneNode(mgr->getRootSceneNode(), mgr, 666 + i);
        node->setPosition(vector3df(30 * cosf(rad*i), 30 * sinf(rad*i), 0));
        node->setMaterialTexture(0, tex);
        node->setMaterialTexture(1, HTM);
 
        ISceneNodeAnimator* animator = mgr->createRotationAnimator(vector3df(0.8f, 0, 0.3f));
        if (animator) {
            node->addAnimator(animator);
            animator->drop();
        }
 
        node->drop();
    }
    //---------------------------/chnage
 
 
    while (device->run()) {
        //drv->beginScene();
        drv->beginScene(true, true, SColor(0, 100, 100, 100));
 
        mgr->drawAll();
 
 
        //----------------------------add
        for (s32 i = 0; i < nodeCount; i++) {
            drv->draw3DLine(vector3df(0, 0, -20), mgr->getSceneNodeFromId(666 + i)->getPosition(), SColor(255, 255, 255, 0));
        }
        //---------------------------/add
 
 
        drv->endScene();
    }
 
    device->drop();
 
    return 0;
}
 
and the cause got known.
An unknown object is flying like this! :shock:
Screen Capture

The light looked like moving in spite that I did not add any animators.
Also, I intended to draw 8 yellow lines but 8 purple lines were spinning around the first scene node round and round.
I wasn't able to change the color of these lines to any other colors.

I cannot understand why these results are shown. :?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Scene Node Lighting

Post by CuteAlien »

OK, can't test right now. But before calling draw3DLine you have to reset material and transformation matrix in driver. They currently are whatever your last node rendered set them to.
So before the first call to draw3DLine, add:

Code: Select all

 
SMaterial someMaterial;
someMaterial.Lighting = false;
drv->setMaterial(someMaterial);
drv->setTransform(video::ETS_WORLD, core::IdentityMatrix);
 
(you don't have to set that for each call as draw3DLine doesn't change the material and transformations itself)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
devsh
Competition winner
Posts: 2057
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Re: Custom Scene Node Lighting

Post by devsh »

Are you going to use a shader afterwards or are you going to rely on built-in irrlicht materials?

If yes then bump mapping / derivative mapping may be a better alternative.
Hotari
Posts: 9
Joined: Tue Dec 25, 2018 2:57 am

Re: Custom Scene Node Lighting

Post by Hotari »

I can draw 8 yellow lines, thanks to you, Mr.CuteAlien.
devsh wrote:Are you going to use a shader afterwards or are you going to rely on built-in irrlicht materials?
I'm going to use built-in irrlicht materials on the node, not shaders.
Should I use shaders?
What is bump mapping different from setting material and texture?
I don't know how to do the derivative mapping.

Image

Although temporary, Why are faces away from light bright?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Scene Node Lighting

Post by CuteAlien »

Hm, not sure why they are bright. Guess I have to test as well. In this shot it looks as if light were 90° off for some reason. Thought not sure if I could debug this - it's also a shader, but one written in graphic card assembly which I don't really know (and not really want to learn as no one writes shaders in that anymore...).

About writing own shader - sooner or later you usually do that. The build-in stuff is good to get started, but unless you want to have _exactly_ what they do (like 2 lights and no texture matrix transformations and no kind of other effect) you will need an own at some point in many projects.

edit: You might want to draw the normals of your polygons. Maybe one of them goes inside? That might explain it. (you would still see the polygon as backface culling is not based on normal but on index-order of vertices being clockwise/anti-clockwise).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
devsh
Competition winner
Posts: 2057
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Re: Custom Scene Node Lighting

Post by devsh »

It looks like your model has "shared vertices" in some places, which basically makes the normals gently caress-up.
It basically makes your tetrahedron think its a sphere.

If you want a tetrahedron lit like a tetrahedron you need not 4 but 12 vertices, for distinct faces.

Btw, here's my explainer on Tangent Space Dot3 Normal Mapping (Irrlicht default), Bump Mapping and Derivative Mapping. It will also explain normal interpolation to a degree.
https://github.com/buildaworldnet/Irrli ... x-tangents

There's also a post by me in the Code Snippets part of the forum how to use pixel shader "dFdx" functions to calcuate tangents per-pixel (which makes bump mapping and derivative mapping possible).
Hotari
Posts: 9
Joined: Tue Dec 25, 2018 2:57 am

Re: Custom Scene Node Lighting

Post by Hotari »

Thank you.
I'll learn about shaders, bump mapping and derivative mapping. (I also must learn linguistically... haha)
Post Reply