Opengl - 旋转、缩放、平移 [英] Opengl - rotation, scale, translation

查看:78
本文介绍了Opengl - 旋转、缩放、平移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:使用 opengl 进行渲染时应用旋转、缩放和平移的顺序是什么?

Question: What is the order to apply rotation, scale, and translation for rendering using opengl?

目前我正在运行代码

  • GL11.glScaled(比例值)
  • GL11.glRotated(x)//间距
  • GL11.glRotated(y)//yaw
  • GL11.glRotated(z)//滚动
  • GL11.glTranslated(x, y, z)

我尝试过更改顺序,结果有很多不同.一些配置改进了渲染,例如,最后缩放不会干扰翻译.然而,它似乎打破了旋转,导致俯仰和滚动同时滚动模型.

I've tried changing the order with a lot of different results. Some configuration improve the rendering, for example, scaling last doesn't mess with the translation. However, it seems to break the rotation causing pitch and roll to both roll the model.

一些额外信息:该代码适用于使用 JSON 数据呈现项目的 Minecraft mod.可以在这里找到确切的代码:https://github.com/VoltzEngine-Project/Engine/blob/development/src/main/scala/com/builtbroken/mc/client/json/render/state/ModelState.java#L48

Some extra information: The code is for a Minecraft mod that renders items using JSON data. The exact code can be found here: https://github.com/VoltzEngine-Project/Engine/blob/development/src/main/scala/com/builtbroken/mc/client/json/render/state/ModelState.java#L48

根据 BDL 的要求添加到帖子中的代码

Code added to post by request of BDL

package com.builtbroken.mc.client.json.render.state;

import com.builtbroken.jlib.helpers.MathHelper;
import com.builtbroken.mc.client.SharedAssets;
import com.builtbroken.mc.client.json.ClientDataHandler;
import com.builtbroken.mc.client.json.imp.IModelState;
import com.builtbroken.mc.client.json.models.ModelData;
import com.builtbroken.mc.client.json.texture.TextureData;
import com.builtbroken.mc.imp.transform.rotation.EulerAngle;
import com.builtbroken.mc.imp.transform.vector.Pos;
import cpw.mods.fml.client.FMLClientHandler;
import org.lwjgl.opengl.GL11;

/**
 * Render/Texture/Animation states used for rendering models in the game
 *
 * @see <a href="https://github.com/BuiltBrokenModding/VoltzEngine/blob/development/license.md">License</a> for what you can and can't do with the code.
 * Created by Dark(DarkGuardsman, Robert) on 11/22/2016.
 */
public class ModelState extends TextureState implements IModelState
{
    public String modelID;
    public String[] parts;
    public Pos offset;
    public Pos scale;
    public EulerAngle rotation;

    public boolean renderParent = false;
    public boolean renderOnlyParts = true;

    public ModelState(String ID)
    {
        super(ID);
    }

    public ModelState(String ID, String modelID, Pos offset, Pos scale, EulerAngle rotation)
    {
        this(ID);
        this.modelID = modelID;
        this.offset = offset;
        this.scale = scale;
        this.rotation = rotation;
    }

    @Override
    public boolean render(boolean subRender, float yaw, float pitch, float roll)
    {
        TextureData textureData = getTexture(); //Texture reference, texture is .png loaded using property code owned by Mojang so can not be shared
        ModelData data = getModel(); //Model reference, model is .obj rendered using triangles
        if (data != null && data.getModel() != null)
        {
            //Starts rendering by storing previous matrix
            GL11.glPushMatrix();

            if (!subRender)
            {
                //TODO handle parent additions, in which parent and child data are combined
                //Scales object by value
                if (scale != null)
                {
                    GL11.glScaled(scale.x(), scale.y(), scale.z());
                }
                else if (parentState instanceof IModelState && ((IModelState) parentState).getScale() != null)
                {
                    GL11.glScaled(((IModelState) parentState).getScale().x(), ((IModelState) parentState).getScale().y(), ((IModelState) parentState).getScale().z());
                }

                //Rotates object, needs to be handled after scaling
                if (rotation != null)
                {
                    GL11.glRotated(MathHelper.clampAngleTo360(rotation.pitch() + pitch), 1, 0, 0);
                    GL11.glRotated(MathHelper.clampAngleTo360(rotation.yaw() + yaw), 0, 1, 0);
                    GL11.glRotated(MathHelper.clampAngleTo360(rotation.roll() + roll), 0, 0, 1);
                }
                else if (parentState instanceof IModelState && ((IModelState) parentState).getRotation() != null)
                {
                    GL11.glRotated(MathHelper.clampAngleTo360(((IModelState) parentState).getRotation().pitch() + pitch), 1, 0, 0);
                    GL11.glRotated(MathHelper.clampAngleTo360(((IModelState) parentState).getRotation().yaw() + yaw), 0, 1, 0);
                    GL11.glRotated(MathHelper.clampAngleTo360(((IModelState) parentState).getRotation().roll() + roll), 0, 0, 1);
                }

                //Moves the object
                if (offset != null)
                {
                    GL11.glTranslated(offset.x(), offset.y(), offset.z());
                }
                else if (parentState instanceof IModelState && ((IModelState) parentState).getOffset() != null)
                {
                    GL11.glTranslated(((IModelState) parentState).getOffset().x(), ((IModelState) parentState).getOffset().y(), ((IModelState) parentState).getOffset().z());
                }
            }

            //Render parent
            GL11.glPushMatrix();
            if (parentState instanceof IModelState)
            {
                if (renderParent)
                {
                    ((IModelState) parentState).render(true);
                }
                else if (parts == null && parentState instanceof ModelState && ((ModelState) parentState).renderParent)
                {
                    if (((ModelState) parentState).parentState instanceof IModelState)
                    {
                        ((IModelState) ((ModelState) parentState).parentState).render(true);
                    }
                }
            }
            GL11.glPopMatrix();

            //Binds texture
            if (textureData != null)
            {
                FMLClientHandler.instance().getClient().renderEngine.bindTexture(textureData.getLocation());
            }
            else
            {
                //Backup texture bind, if no texture
                FMLClientHandler.instance().getClient().renderEngine.bindTexture(SharedAssets.GREY_TEXTURE);
            }

            //Render model
            data.render(renderOnlyParts, getPartsToRender());

            //Ends render by restoring previous matrix(rotation, position, etc)
            GL11.glPopMatrix();
            return true;
        }
        return false;
    }

    @Override
    public Pos getScale()
    {
        if (scale == null)
        {
            return parentState instanceof IModelState ? ((IModelState) parentState).getScale() : null;
        }
        else if (parentState instanceof IModelState)
        {
            //TODO add to parent rotation, or null out rotation
            //TODO setup logic via configs to allow users to decide how rotation is used
        }
        return scale;
    }

    @Override
    public Pos getOffset()
    {
        if (offset == null)
        {
            return parentState instanceof IModelState ? ((IModelState) parentState).getOffset() : null;
        }
        else if (parentState instanceof IModelState)
        {
            //TODO add to parent rotation, or null out rotation
            //TODO setup logic via configs to allow users to decide how rotation is used
        }
        return offset;
    }

    @Override
    public EulerAngle getRotation()
    {
        if (rotation == null)
        {
            return parentState instanceof IModelState ? ((IModelState) parentState).getRotation() : null;
        }
        else if (parentState instanceof IModelState)
        {
            //TODO add to parent rotation, or null out rotation
            //TODO setup logic via configs to allow users to decide how rotation is used
        }
        return rotation;
    }

    @Override
    public ModelData getModel()
    {
        if (parentState instanceof IModelState)
        {
            return ((IModelState) parentState).getModel();
        }
        return ClientDataHandler.INSTANCE.getModel(modelID);
    }

    @Override
    public String[] getPartsToRender()
    {
        if (parentState instanceof IModelState && (parts == null || parts.length == 0))
        {
            return ((IModelState) parentState).getPartsToRender();
        }
        return parts;
    }

    @Override
    public TextureData getTexture()
    {
        TextureData textureData = ClientDataHandler.INSTANCE.getTexture(textureID);
        if (textureData == null && parentState instanceof IModelState)
        {
            return ((IModelState) parentState).getTexture();
        }
        return textureData;
    }
}

推荐答案

对于通常的用例,请遵循以下操作顺序:缩放 -> 旋转 -> 平移

Follow this order of operations for the usual use case: Scale -> Rotate -> Translate

对于旋转本身,一个直观的约定是先滚动,然后是俯仰,最后是偏航.滚动沿对象的轴发生.向上或向下倾斜滚动的物体.然后水平定向模型.

For the rotation itself, an intuitive convention is first roll, then pitch and at the end yaw. Rolling happens along an axis of the object. Pitch up or down the rolled object. Then horizontally orient the model.

缩放发生在对象模型坐标中.缩放发生后旋转,因此您可以相对于场景帧旋转缩放模型.最后,您最后使用平移将生成的转换对象放置到位.

Scaling happens in object model coordinates. Rotation after the scale happens so you're rotating the scaled model with respect to the scene frame. Eventually you use translation last to place the resulting transformed object into place.

有时您需要进行前一轮的缩放和旋转,以解决工具/引擎在右手、坐标(Z 向上或 Y 向上)和缩放方面的差异

You sometimes need to do a previous round of scale and rotation to account for the tool/engine differences in right-handedness, coordinates (Z is up or Y is up.) and scale

这篇关于Opengl - 旋转、缩放、平移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆